diff options
author | Guillaume Martres <smarter@ubuntu.com> | 2017-04-14 02:23:59 +0200 |
---|---|---|
committer | Guillaume Martres <smarter@ubuntu.com> | 2017-04-14 02:50:04 +0200 |
commit | d773a32c9731dd5b105ac718900f8217fa75bcb2 (patch) | |
tree | 590d781ef7f81663e3baff0df9920b8ac1e52c2b | |
parent | 9e45ad16d012e6a2ff3be411c2fe101b1c74b831 (diff) | |
download | dotty-d773a32c9731dd5b105ac718900f8217fa75bcb2.tar.gz dotty-d773a32c9731dd5b105ac718900f8217fa75bcb2.tar.bz2 dotty-d773a32c9731dd5b105ac718900f8217fa75bcb2.zip |
Make warm compilation speed with sbt 2x faster
Previously, every call to `compile` in sbt with dotty took about the
same time because we created a new ClassLoader everytime and thus
thrased the JIT code cache, by reusing ClassLoaders we can make
`compile` about 2x faster.
You can reproduce this by running:
> dotty-compiler-bootstrapped/compile
This takes ~50 seconds on my machine. Then clean using:
> ;dotty-compiler-bootstrapped/clean;dotty-compiler-update
And run `dotty-compiler-bootstrapped/compile` again, this takes ~25
seconds for me. I get very similar timings from scalac (replacing
`dotty-compiler-bootstrapped` by `dotty-compiler`).
-rw-r--r-- | sbt-bridge/src/xsbt/CompilerClassLoader.scala | 15 |
1 files changed, 14 insertions, 1 deletions
diff --git a/sbt-bridge/src/xsbt/CompilerClassLoader.scala b/sbt-bridge/src/xsbt/CompilerClassLoader.scala index 3cb3f344f..c0bdcb5e9 100644 --- a/sbt-bridge/src/xsbt/CompilerClassLoader.scala +++ b/sbt-bridge/src/xsbt/CompilerClassLoader.scala @@ -2,6 +2,8 @@ package xsbt import java.net.{URL, URLClassLoader} +import scala.collection.mutable + /** A classloader to run the compiler * * A CompilerClassLoader is constructed from a list of `urls` that need to be on @@ -42,6 +44,14 @@ class CompilerClassLoader(urls: Array[URL], sbtLoader: ClassLoader) } object CompilerClassLoader { + /** Cache the result of `fixBridgeLoader`. + * + * Reusing ClassLoaders is important for warm performance since otherwise the + * JIT code cache for the compiler will be discarded between every call to + * the sbt `compile` task. + */ + private[this] val fixedLoaderCache = new mutable.WeakHashMap[ClassLoader, ClassLoader] + /** Fix the compiler bridge ClassLoader * * Soundtrack: https://www.youtube.com/watch?v=imamcajBEJs @@ -70,7 +80,10 @@ object CompilerClassLoader { * @param bridgeLoader The classloader that sbt uses to load the compiler bridge * @return A fixed classloader that works with dotty */ - def fixBridgeLoader(bridgeLoader: ClassLoader) = bridgeLoader match { + def fixBridgeLoader(bridgeLoader: ClassLoader): ClassLoader = + fixedLoaderCache.getOrElseUpdate(bridgeLoader, computeFixedLoader(bridgeLoader)) + + private[this] def computeFixedLoader(bridgeLoader: ClassLoader) = bridgeLoader match { case bridgeLoader: URLClassLoader => val dualLoader = bridgeLoader.getParent val dualLoaderClass = dualLoader.getClass |