Conversation
|
I'll try and have a look when I have a bit more time to dig into it, but I thought perhaps we could cc in @fommil, given he's been spending time recently with this problem in parallel, and he opened the original issue. Also seems codacy isn't happy. |
|
@dwijnand thanks, I have this on my todo list today to investigate / understand. Been wasting the whole day trying to build a Windows 7 image to test on. |
There was a problem hiding this comment.
this is still going to kill the performance, as it invokes quite a lot of subtasks. Hence #2348
I'll do some graph timings with my patch to see what is invoked, but my suspicion is that this isn't going to make a massive difference to performance on Windows due to the large number of Tasks that will be created 😢
There was a problem hiding this comment.
I can certainly make lighter-weight setting or task for jar file if that's going to trigger things. I just reopened #2348.
There was a problem hiding this comment.
Thanks. Btw, I don't think this is the only thing triggering lots of upstream Tasks.
|
I think I've been reading too much of the sbt source code because I actually understand this 😨 Conceptually it looks sound, but I can't be sure about which tasks are being scheduled until I run this on my test projects (I'll turn off sbt-big-project settings). I'll report back when I do that. |
|
Running this on my simple test project https://github.com/fommil/sbt-big-project/tree/master/src/sbt-test/sbt-big-project/simple reconditioned to look like I'm still seeing a lot of dependent tasks in subprojects running. This doesn't look so bad for a small project, but for huge projects this is a lot of tasks. In particular, this is causing 32 tasks to run per dependent project, which is not scalable, especially for builds with 100+ projects. Below is the output of #1209 (comment) with a filter to only show the tasks for the and if I enable caching So I honestly can't say if this improves things or not, sorry! However, combined with sbt-big-project, this might actually improve the workflow because I've still got a few unsolved problems e.g. https://github.com/fommil/sbt-big-project/issues/11 (I'll be working on that actively, so you might want to check back) |
There was a problem hiding this comment.
Won't this trigger multiple calls to compile task, one for each product?
There was a problem hiding this comment.
Within a dynamic task (Def.taskDyn) the last task value is deferred.
|
Could you give a context when is this really needed? Is it trying to workaround issues with NFS file systems? What incremental compiler is doing is equivalent to what |
Primarily yes. More details are found in #2266 and https://github.com/eed3si9n/sbt-big-project-test, but on Windows 100+ subproject build seem to take 27s just running |
|
Here's the timing breakdown that |
|
Thanks for sharing details. From incremental compiler point of view this looks good to me. I'll defer review of sbt task engine performance to other people, though. |
|
This is what I tried, using the import sbt._
import Keys._
import Def.Initialize
import fommil._
object SimpleBuild extends Build {
override lazy val settings = super.settings ++ Seq(
scalaVersion := "2.10.6",
version := "v1",
)
def simpleProject(name: String): Project = {
BigProjectTestSupport.createSources(name)
Project(name, file(name)).settings(
trackInternalDependencies := TrackLevel.TrackIfMissing,
exportJars := true
)
}
val a = simpleProject("a")
val b = simpleProject("b") dependsOn(a)
val c = simpleProject("c") dependsOn(b)
val d = simpleProject("d") dependsOn(c)
}
so, basically, fantastic work! The one thing that doesn't work quite as expected is this:
this is something I've been struggling with in sbt-big-project even without these changes, and I think the solution is to do something like this https://github.com/fommil/sbt-big-project/blob/c3d4bc3260ac5e25f63bdb94a7e0bd5c3ada6a7d/src/main/scala/BigProjectSettings.scala#L100-L117 (i.e. delete the jar if the compile produced anything). There are a couple of other sbt / zinc problems deep inside here. AFAIK, this doesn't address the fundamental performance problems with sbt on large projects on Windows, but it gives me the levers that I need in order to implement sensible workarounds in I probably need to go back to the drawing board with sbt-big-project because I don't necessarily need to cache everything that I'm caching, so I should find what the remaining bottlenecks are. I might not need to cache around Can you please squash and create a commit that cleanly applies against 0.13.9? (I get conflicts) |
|
Thanks @fommil for trying this out. |
Adds `trackInternalDependencies` and `exportToInternal` settings. These
can be used to control whether to trigger compilation of a dependent
subprojects when you call `compile`. Both keys will take one of three
values: `TrackLevel.NoTracking`, `TrackLevel.TrackIfMissing`, and
`TrackLevel.TrackAlways`. By default they are both set to
`TrackLevel.TrackAlways`.
When `trackInternalDependencies` is set to `TrackLevel.TrackIfMissing`,
sbt will no longer try to compile internal (inter-project) dependencies
automatically, unless there are no `*.class` files (or JAR file when
`exportJars` is `true`) in the output directory. When the setting is
set to `TrackLevel.NoTracking`, the compilation of internal
dependencies will be skipped. Note that the classpath will still be
appended, and dependency graph will still show them as dependencies.
The motivation is to save the I/O overhead of checking for the changes
on a build with many subprojects during development. Here's how to set
all subprojects to `TrackIfMissing`.
lazy val root = (project in file(".")).
aggregate(....).
settings(
inThisBuild(Seq(
trackInternalDependencies := TrackLevel.TrackIfMissing,
exportJars := true
))
)
The `exportToInternal` setting allows the dependee subprojects to opt
out of the internal tracking, which might be useful if you want to
track most subprojects except for a few. The intersection of the
`trackInternalDependencies` and `exportToInternal` settings will be
used to determine the actual track level. Here's an example to opt-out
one project:
lazy val dontTrackMe = (project in file("dontTrackMe")).
settings(
exportToInternal := TrackLevel.NoTracking
)
02c7239 to
c55c3ec
Compare
Inter-project dependency tracking
|
FYI, I'm formalising the above test scripted with a |
Fixes #2266
Adds
trackInternalDependenciesandexportToInternalsettings. Thesecan be used to control whether to trigger compilation of a dependent
subprojects when you call
compile. Both keys will take one of threevalues:
TrackLevel.NoTracking,TrackLevel.TrackIfMissing, andTrackLevel.TrackAlways. By default they are both set toTrackLevel.TrackAlways.When
trackInternalDependenciesis set toTrackLevel.TrackIfMissing,sbt will no longer try to compile internal (inter-project) dependencies
automatically, unless there are no
*.classfiles (or JAR file whenexportJarsistrue) in the output directory. When the setting isset to
TrackLevel.NoTracking, the compilation of internaldependencies will be skipped. Note that the classpath will still be
appended, and dependency graph will still show them as dependencies.
The motivation is to save the I/O overhead of checking for the changes
on a build with many subprojects during development. Here's how to set
all subprojects to
TrackIfMissing.The
exportToInternalsetting allows the dependee subprojects to optout of the internal tracking, which might be useful if you want to
track most subprojects except for a few. The intersection of the
trackInternalDependenciesandexportToInternalsettings will beused to determine the actual track level. Here's an example to opt-out
one project:
/review @gkossakowski @dwijnand, @jsuereth, @Duhemm