-
Notifications
You must be signed in to change notification settings - Fork 121
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
Build pipelining support #744
Conversation
3d3e56e
to
6d08494
Compare
002eb58
to
ebca5de
Compare
daa1114
to
1772ed8
Compare
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
It would be good if we could use Here's what I had in mind: This can be combined with We can stick with this |
Here are some challenges:
For example, given subprojects core (
|
We have the exact same problem with .tasty, which is why we only emit .tasty in the backend even though they could be emitted at pickler (and even then we also need all of this wonderful stuff: https://github.com/lampepfl/dotty/blob/11760ea2b23ad7eb5b5749f489ee5395980c0daf/sbt-dotty/src/dotty/tools/sbtplugin/DottyPlugin.scala#L127-L152) |
Also to document "making sure it works for both Java and Scala" part of the challenge... Here's zinc/zinc/src/main/scala/sbt/internal/inc/MixedAnalyzingCompiler.scala Lines 157 to 163 in 0a96116
By default it calls delay Javac compilation?Using core and app subproject as example, let's say both subprojects are Scala and Java sources. The question is when can we start "app" subproject compile. Ideally we want to start as soon as early artifacts are available from core. So should we wait till whole compilation is done for core subproject? Doing so would undermine the pipelining whenever *.class-based JavaAnalyze?AnalyzingJavaCompiler (https://github.com/sbt/zinc/blob/v1.4.0-M5/zinc/src/main/scala/sbt/internal/inc/javac/AnalyzingJavaCompiler.scala) runs analysis on top of the If we try to pipeline mixed Java/Scala subprojects, the Analysis information created by |
The intention is that we use Downstream projects that use AFAICT some of this information (e.g. external library dependencies) is irrelevant for the decision making of the downstream incremental compiler and won't be needed until subsequent compilation of this project. The API extraction is important, but should be safe to replace with I think it would be useful to validate our assumptions about what information is irrelevant to downstream incremental compilation, they would only be consulted as part of |
Good idea. I think all we need are zinc/internal/zinc-core/src/main/scala/sbt/internal/inc/IncrementalCommon.scala Lines 776 to 783 in 0a96116
|
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
0c47d86
to
4e392cf
Compare
For modular pipelining we need both early output (JAR file containing Scala sig files) and early Analysis (Zinc internal information). This adds `IncOptions#earlyOutput` and `Lookup#storeEarlyAnalysis` so the early artifacts can be generated during compile phases.
Early analysis store is passed into the Setup. CompileProgress is used to notify the early output timing.
The deletion part required some tweaking to make sure this works for dir-based output.
If a macro is found in any classes, use the regular output.
With only Scala pipelining implemented, this Java-only pipelining test is pending. The issue lies in the fact that while scalac can consume its own .sig early output artifacts, javac can't.
mergeAndInvalidate will merge the partialAnalysis with the pruned Analysis, so merged it twice will break it (duplicate Compilations). Only record the generated products in the partialAnalysis - fails the restore-classes scripted test if not.
This is to avoid the "The process cannot access the file because it is being used by another process" issue, on Windows.
The entry point API of Zinc, xsbti.compile.IncrementalCompiler, is defined in compiler-interface and is, therefore, entirely in Java, only. Therefore, in order to allow a user (e.g. an external build tool) to define their own profiler using this interface I extracted a Java-only interface for InvalidationProfiler and its components. Having done that I could add it to compiler-interface's xsbti.compile.ExternalHooks. I've kept the original, Scala variant, interface methods (e.g. using Scala's Iterable instead of Array or java.util.Set) for backwards compatibility and I've created an AdaptedRunProfiler that knows how to adapt the calls to the underlying XRunProfiler it contains.
subproject-java scripted test demonstrates the need to coordinate Java compilation. |
Ref sbt/zinc#744 This implements `ThisBuild / usePipelining`, which configures subproject pipelining available from Zinc 1.4.0. The basic idea is to start subproject compilation as soon as pickle JARs (early output) becomes available. This is in part enabled by Scala compiler's new flags `-Ypickle-java` and `-Ypickle-write`. The other part of magic is the use of `Def.promise`: ``` earlyOutputPing := Def.promise[Boolean], ``` This notifies `compileEarly` task, which to the rest of the tasks would look like a normal task but in fact it is promise-blocked. In other words, without calling full `compile` task together, `compileEarly` will never return, forever waiting for the `earlyOutputPing`.
Ref sbt/zinc#744 This implements `ThisBuild / usePipelining`, which configures subproject pipelining available from Zinc 1.4.0. The basic idea is to start subproject compilation as soon as pickle JARs (early output) becomes available. This is in part enabled by Scala compiler's new flags `-Ypickle-java` and `-Ypickle-write`. The other part of magic is the use of `Def.promise`: ``` earlyOutputPing := Def.promise[Boolean], ``` This notifies `compileEarly` task, which to the rest of the tasks would look like a normal task but in fact it is promise-blocked. In other words, without calling full `compile` task together, `compileEarly` will never return, forever waiting for the `earlyOutputPing`.
Ref sbt/zinc#744 This implements `ThisBuild / usePipelining`, which configures subproject pipelining available from Zinc 1.4.0. The basic idea is to start subproject compilation as soon as pickle JARs (early output) becomes available. This is in part enabled by Scala compiler's new flags `-Ypickle-java` and `-Ypickle-write`. The other part of magic is the use of `Def.promise`: ``` earlyOutputPing := Def.promise[Boolean], ``` This notifies `compileEarly` task, which to the rest of the tasks would look like a normal task but in fact it is promise-blocked. In other words, without calling full `compile` task together, `compileEarly` will never return, forever waiting for the `earlyOutputPing`.
Ref sbt/zinc#744 This implements `ThisBuild / usePipelining`, which configures subproject pipelining available from Zinc 1.4.0. The basic idea is to start subproject compilation as soon as pickle JARs (early output) becomes available. This is in part enabled by Scala compiler's new flags `-Ypickle-java` and `-Ypickle-write`. The other part of magic is the use of `Def.promise`: ``` earlyOutputPing := Def.promise[Boolean], ``` This notifies `compileEarly` task, which to the rest of the tasks would look like a normal task but in fact it is promise-blocked. In other words, without calling full `compile` task together, `compileEarly` will never return, forever waiting for the `earlyOutputPing`.
Ref sbt/zinc#744 This implements `ThisBuild / usePipelining`, which configures subproject pipelining available from Zinc 1.4.0. The basic idea is to start subproject compilation as soon as pickle JARs (early output) becomes available. This is in part enabled by Scala compiler's new flags `-Ypickle-java` and `-Ypickle-write`. The other part of magic is the use of `Def.promise`: ``` earlyOutputPing := Def.promise[Boolean], ``` This notifies `compileEarly` task, which to the rest of the tasks would look like a normal task but in fact it is promise-blocked. In other words, without calling full `compile` task together, `compileEarly` will never return, forever waiting for the `earlyOutputPing`.
This is a work-in-progress, open source port of build pipelining support implemented by Lightbend Scala team (scala/scala#7712) and Morgan Stanley (https://github.com/mspnf/zinc/blob/1.3.x-contrib/README-MORGANSTANLEY.MD).
Java supportRef scala/scala#7712
Ref scala/scala-dev#643
This adds a new flag
incOption.withPipelining(true)
that enables incremental build pipelining.Note: If incOptions pipelining is enabled, the build tool must call
compileAllJava(in, logger)
after both*.class
compilation has completed && hasModified.