-
Notifications
You must be signed in to change notification settings - Fork 21
Performance regression in the flat classpath #10289
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Comments
I'm guessing that scala/scala#5685 was unknowingly motivated by this regression. |
I can see an inefficiency in the implementation. Here's a candidate patch for 2.11.x: https://github.com/scala/scala/compare/2.11.x...retronym:backport/fasterFindClass?expand=1 However, I'm not able to reproduce the baseline slowness you're seeing in that project. diff --git a/project/Prototypes.scala b/project/Prototypes.scala
index 3d4eea1a9..ce58f8890 100644
--- a/project/Prototypes.scala
+++ b/project/Prototypes.scala
@@ -24,3 +24,3 @@ trait Prototypes {
scalacOptions := Seq("-unchecked", "-deprecation", "-target:jvm-1.8",
- "-Xcheckinit", "-encoding", "utf8", "-feature", "-Yinline-warnings","-Xfatal-warnings"),
+ "-Xcheckinit", "-encoding", "utf8", "-feature", "-Yinline-warnings","-Xfatal-warnings", "-verbose"),
publishArtifact in (Compile, packageDoc) := false, // ~/.sbt/0.13/plugins/custom.scala
package io.github.retronym
import sbt._
import Keys._
object RawCompile extends AutoPlugin {
override def trigger = allRequirements
override def requires = sbt.plugins.JvmPlugin
val compileRaw = taskKey[Unit]("Compile directly, bypassing the incremental compiler")
val cleanClasses = taskKey[Unit]("clean the classes directory")
override lazy val projectSettings = List(Compile, Test).flatMap(c => inConfig(c)(Seq(
addCompileRaw,
cleanClasses := IO.delete(classDirectory.value)
)))
def addCompileRaw = compileRaw := {
val compiler = new sbt.compiler.RawCompiler(scalaInstance.value, sbt.ClasspathOptions.auto, streams.value.log)
classDirectory.value.mkdirs()
compiler.apply(sources.value, classDirectory.value +: dependencyClasspath.value.map(_.data), classDirectory.value, scalacOptions.value)
}
}
Given that the compilation of |
D'oh, I forgot to enable the flat classpath. |
Okay, I can repro. Extracted the info for all projects under
https://gist.github.com/retronym/33400a750785acc05dfec87cfede7107 |
There are two paths forward here to fix the regression. First, we can optimize the new classpath implementation. There are some constant factor improvements that might go part of the way. We probably also need to add an index of SBT itself could also be changed to avoid calling this altogether. For symbols sourced from JARs, It actually just needs to |
@retronym I wrote some doc comments here: https://github.com/scala/scala/compare/2.12.x...lrytz:classpath-doc?expand=1 Can you integrate this (and update where necessary) into your PR? |
Promising results in overall build time with my SBT patch:
|
That looks very promising. Good catch! |
I think this might be problematic, or at least, it should support split packages. Unfortunately there are many projects that, knowingly or unknowingly, rely on them. Otherwise, I think we should fix both the classpath implementation and Sbt. :) |
Good point, the index needs to be a multi map.
|
I've prototyped the fixes in both SBT and Scala. I've tested the performance of interesting combinations after managing to serialize compilation in the multi-project build. Results: https://gist.github.com/3c89c21c54d27e566dec57a16a4bf208 They suggest that my latest fix to Scala restores the old performance. The SBT fix seems to equalize My next step is to submit that Scala fix to target 2.12.3. |
tl;dr; The flat classpath implementation is much slower during the Sbt dependency analysis. For a project with a large classpath it's around 1.5s vs. 300ms with the recursive implementation.
I will use 2.11 as a reference point because the recursive classpath was removed in 2.12. However, timings carry over to the 2.12 compiler.
I'm using https://github.com/guardian/frontend/ for benchmarking (more precisely, the
applications
subproject), which has a (very) large classpath. The time seems to be correlated to the size of the classpath and not so much with sources. The timings I got with the default 2.11 classpath (recursive):and with the flat one:
The 2.12 branch has a fix by @lrytz to speedup the classpath implementation, but even with this fix applied in the 2.11 branch the phase is about 5x slower:
At first glance, a lot of time seems to be spent in string manipulation and growing arrays. This is using VisualVM, so maybe the profiler isn't the best there is, however I think it points in the right direction.
PS. The timings with 2.12.2 for this phase are in the order of seconds, so it leads me to think the regression is still there, even though I didn't have a recursive classpath implementation for 2.12 to compare it against.
The text was updated successfully, but these errors were encountered: