From 3c508ce52db7984b4636f935546e2b3a20a7ab61 Mon Sep 17 00:00:00 2001 From: Jason Zaugg Date: Thu, 22 Sep 2016 17:24:30 +1000 Subject: [PATCH 1/2] SD-232 Recycle classloaders to be anti-hostile to JIT. The compiler interface subclasses `scala.tools.nsc.Global`, and loading this new subclass before each `compile` task forces HotSpot JIT to deoptimize larges swathes of compiled code. It's a bit like SBT has rigged the dice to always descend the longest ladder in a game of Snakes and Ladders. The slowdown seems to be larger with Scala 2.12. There are a number of variables at play, but I think the main factor here is that we now rely on JIT to devirtualize calls to final methods in traits whereas we used to emit static calls. JIT does a good job at this, so long as classloading doesn't undo that good work. This commit extends the existing `ClassLoaderCache` to encompass the classloader that includes the compiler interface JAR. I've resorted to adding a var to `AnalyzingCompiler` to inject the dependency to get the cache to the spot I need it without binary incompatible changes to the intervening method signatures. --- main/src/main/scala/sbt/Defaults.scala | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/main/src/main/scala/sbt/Defaults.scala b/main/src/main/scala/sbt/Defaults.scala index a275d0d5b..94a72e521 100755 --- a/main/src/main/scala/sbt/Defaults.scala +++ b/main/src/main/scala/sbt/Defaults.scala @@ -307,8 +307,13 @@ object Defaults extends BuildCommon { if (plugin) scalaBase / ("sbt-" + sbtv) else scalaBase } - def compilersSetting = compilers := Compiler.compilers(scalaInstance.value, classpathOptions.value, javaHome.value, - bootIvyConfiguration.value, fileToStore.value, scalaCompilerBridgeSource.value)(appConfiguration.value, streams.value.log) + def compilersSetting = compilers := { + val compilers = Compiler.compilers(scalaInstance.value, classpathOptions.value, javaHome.value, + bootIvyConfiguration.value, fileToStore.value, scalaCompilerBridgeSource.value)(appConfiguration.value, streams.value.log) + if (!java.lang.Boolean.getBoolean("sbt.disable.interface.classloader.cache")) + compilers.scalac.setClassLoaderCache(state.value.classLoaderCache) + compilers + } lazy val configTasks = docTaskSettings(doc) ++ inTask(compile)(compileInputsSettings) ++ configGlobal ++ compileAnalysisSettings ++ Seq( compile := compileTask.value, From 1822d3f67bae629d9d3c60d6450cf34ab15eeb94 Mon Sep 17 00:00:00 2001 From: Dale Wijnand Date: Mon, 26 Sep 2016 09:22:21 +0100 Subject: [PATCH 2/2] Replace var/set with withClassLoaderCache --- main/src/main/scala/sbt/Defaults.scala | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/main/src/main/scala/sbt/Defaults.scala b/main/src/main/scala/sbt/Defaults.scala index 94a72e521..d05bfbe05 100755 --- a/main/src/main/scala/sbt/Defaults.scala +++ b/main/src/main/scala/sbt/Defaults.scala @@ -307,12 +307,21 @@ object Defaults extends BuildCommon { if (plugin) scalaBase / ("sbt-" + sbtv) else scalaBase } - def compilersSetting = compilers := { - val compilers = Compiler.compilers(scalaInstance.value, classpathOptions.value, javaHome.value, - bootIvyConfiguration.value, fileToStore.value, scalaCompilerBridgeSource.value)(appConfiguration.value, streams.value.log) - if (!java.lang.Boolean.getBoolean("sbt.disable.interface.classloader.cache")) - compilers.scalac.setClassLoaderCache(state.value.classLoaderCache) - compilers + def compilersSetting = { + compilers := { + val compilers = Compiler.compilers( + scalaInstance.value, classpathOptions.value, javaHome.value, bootIvyConfiguration.value, + fileToStore.value, scalaCompilerBridgeSource.value + )(appConfiguration.value, streams.value.log) + if (java.lang.Boolean.getBoolean("sbt.disable.interface.classloader.cache")) compilers else { + compilers.withScalac( + compilers.scalac match { + case x: AnalyzingCompiler => x.withClassLoaderCache(state.value.classLoaderCache) + case x => x + } + ) + } + } } lazy val configTasks = docTaskSettings(doc) ++ inTask(compile)(compileInputsSettings) ++ configGlobal ++ compileAnalysisSettings ++ Seq(