I’m doing perf work on my gradle build which is a decent size multiproject build. It has 133 subprojects. My current objective is to run a war task that is already up to date and see what tasks are not running and what tasks are taking a long time to run. I want to reduce the incremental time it takes to produce my war.
My first reading of the scan showed some “NO SOURCE” tasks taking about 5 seconds, but then I sorted by duration and noticed that there are 5 tasks that all take more than 5 seconds and that they are all the first tasks to fire. I have 5 worker threads.
This is gradle 4.3, although we are in the process of upgrading to 4.10. So we shouldn’t do anything drastic until I can try this on 4.10.
I’m hesitant to post the full gradle scan since it shows some of the stuff we do in our production build. I’d be happy to PM it to you I just couldn’t see how to do that.
I’m also going to try some other tasks and see if changing the execution tree shows the same behavior.
I was running some different tasks in my project today and I can see that the first 5 tasks assigned out to threads are different tasks and they run with no problem. I still need to try on gradle 4.10 and when I get that done I will report back here.
I can reproduce the problem with a single task - compileJava. It takes 5 seconds all by itself. Watching in VisualVM I can see one daemon thread is Runnable so it is not blocked. Watching the daemon process in Process Monitor (I’m on windows) I can see Gradle doing a lot, and I mean millions, of file operations. Taking a stack snapshot, the thread is doing this. I do have a lot of files in my repository, but when I run a subproject compileJava, I see Gradle playing around with files in all the other projects even once the compileJava task begins. If anybody can shed light on this stacktrace I would appreciate it.
“Task worker for ‘:’” #45 prio=5 os_prio=0 tid=0x000000002620a000 nid=0x5bc8 runnable [0x0000000032e0d000]
java.lang.Thread.State: RUNNABLE
at java.io.WinNTFileSystem.canonicalize0(Native Method)
at java.io.WinNTFileSystem.canonicalize(WinNTFileSystem.java:428)
at java.io.File.getCanonicalPath(File.java:618)
at java.io.File.getCanonicalFile(File.java:643)
at org.gradle.api.internal.file.FileNormaliser.normalise(FileNormaliser.java:54)
at org.gradle.api.internal.file.AbstractFileResolver.resolve(AbstractFileResolver.java:88)
at org.gradle.api.internal.file.AbstractFileResolver.resolve(AbstractFileResolver.java:68)
at org.gradle.api.internal.file.collections.DefaultFileCollectionResolveContext$FileCollectionConverter.convertInto(DefaultFileCollectionResolveContext.java:177)
at org.gradle.api.internal.file.collections.DefaultFileCollectionResolveContext.doResolve(DefaultFileCollectionResolveContext.java:138)
at org.gradle.api.internal.file.collections.DefaultFileCollectionResolveContext.resolveAsFileCollections(DefaultFileCollectionResolveContext.java:94)
at org.gradle.api.internal.file.collections.DefaultFileCollectionResolveContext$FileCollectionConverter.convertInto(DefaultFileCollectionResolveContext.java:161)
at org.gradle.api.internal.file.collections.DefaultFileCollectionResolveContext.doResolve(DefaultFileCollectionResolveContext.java:111)
at org.gradle.api.internal.file.collections.DefaultFileCollectionResolveContext.resolveAsFileCollections(DefaultFileCollectionResolveContext.java:94)
at org.gradle.api.internal.file.collections.DefaultFileCollectionResolveContext$FileCollectionConverter.convertInto(DefaultFileCollectionResolveContext.java:161)
at org.gradle.api.internal.file.collections.DefaultFileCollectionResolveContext.doResolve(DefaultFileCollectionResolveContext.java:111)
at org.gradle.api.internal.file.collections.DefaultFileCollectionResolveContext.resolveAsFileCollections(DefaultFileCollectionResolveContext.java:94)
at org.gradle.api.internal.file.CompositeFileCollection.getSourceCollections(CompositeFileCollection.java:172)
at org.gradle.api.internal.tasks.DefaultSourceSetOutput_Decorated.getSourceCollections(Unknown Source)
at org.gradle.api.internal.file.CompositeFileCollection.getFiles(CompositeFileCollection.java:55)
at org.gradle.api.internal.tasks.DefaultSourceSetOutput_Decorated.getFiles(Unknown Source)
at org.gradle.internal.cleanup.DefaultBuildOutputCleanupRegistry.doResolvePaths(DefaultBuildOutputCleanupRegistry.java:69)
- locked <0x000000056cd3d648> (a org.gradle.internal.cleanup.DefaultBuildOutputCleanupRegistry)
at org.gradle.internal.cleanup.DefaultBuildOutputCleanupRegistry.getResolvedPaths(DefaultBuildOutputCleanupRegistry.java:60)
at org.gradle.internal.cleanup.DefaultBuildOutputCleanupRegistry.isOutputOwnedByBuild(DefaultBuildOutputCleanupRegistry.java:47)
at org.gradle.api.internal.tasks.execution.CleanupStaleOutputsExecuter.execute(CleanupStaleOutputsExecuter.java:62)
at org.gradle.api.internal.tasks.execution.ResolveTaskArtifactStateTaskExecuter.execute(ResolveTaskArtifactStateTaskExecuter.java:52)
at org.gradle.api.internal.tasks.execution.SkipTaskWithNoActionsExecuter.execute(SkipTaskWithNoActionsExecuter.java:52)
at org.gradle.api.internal.tasks.execution.SkipOnlyIfTaskExecuter.execute(SkipOnlyIfTaskExecuter.java:54)
at org.gradle.api.internal.tasks.execution.ExecuteAtMostOnceTaskExecuter.execute(ExecuteAtMostOnceTaskExecuter.java:43)
at org.gradle.api.internal.tasks.execution.CatchExceptionTaskExecuter.execute(CatchExceptionTaskExecuter.java:34)
at org.gradle.execution.taskgraph.DefaultTaskGraphExecuter$EventFiringTaskWorker$1.run(DefaultTaskGraphExecuter.java:248)
at org.gradle.internal.progress.DefaultBuildOperationExecutor$RunnableBuildOperationWorker.execute(DefaultBuildOperationExecutor.java:336)
at org.gradle.internal.progress.DefaultBuildOperationExecutor$RunnableBuildOperationWorker.execute(DefaultBuildOperationExecutor.java:328)
at org.gradle.internal.progress.DefaultBuildOperationExecutor.execute(DefaultBuildOperationExecutor.java:199)
at org.gradle.internal.progress.DefaultBuildOperationExecutor.run(DefaultBuildOperationExecutor.java:110)
at org.gradle.execution.taskgraph.DefaultTaskGraphExecuter$EventFiringTaskWorker.execute(DefaultTaskGraphExecuter.java:241)
at org.gradle.execution.taskgraph.DefaultTaskGraphExecuter$EventFiringTaskWorker.execute(DefaultTaskGraphExecuter.java:230)
at org.gradle.execution.taskgraph.DefaultTaskPlanExecutor$TaskExecutorWorker.processTask(DefaultTaskPlanExecutor.java:123)
at org.gradle.execution.taskgraph.DefaultTaskPlanExecutor$TaskExecutorWorker.access$200(DefaultTaskPlanExecutor.java:79)
at org.gradle.execution.taskgraph.DefaultTaskPlanExecutor$TaskExecutorWorker$1.execute(DefaultTaskPlanExecutor.java:104)
at org.gradle.execution.taskgraph.DefaultTaskPlanExecutor$TaskExecutorWorker$1.execute(DefaultTaskPlanExecutor.java:98)
at org.gradle.execution.taskgraph.DefaultTaskExecutionPlan.execute(DefaultTaskExecutionPlan.java:626)
at org.gradle.execution.taskgraph.DefaultTaskExecutionPlan.executeWithTask(DefaultTaskExecutionPlan.java:581)
at org.gradle.execution.taskgraph.DefaultTaskPlanExecutor$TaskExecutorWorker.run(DefaultTaskPlanExecutor.java:98)
at org.gradle.internal.concurrent.ExecutorPolicy$CatchAndRecordFailures.onExecute(ExecutorPolicy.java:63)
at org.gradle.internal.concurrent.ManagedExecutorImpl$1.run(ManagedExecutorImpl.java:46)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
at org.gradle.internal.concurrent.ThreadFactoryImpl$ManagedThreadRunnable.run(ThreadFactoryImpl.java:55)
at java.lang.Thread.run(Thread.java:748)
Also I’m not sure that the problem is exactly folders named “build”. The below screenshow shows a sample output of Process Monitor. And there are 1000s of lines like this (more than a 1M actually).
the rootProject location should be c:\git-repos\prpc-platform.
I will check around carefully for any clean configurations.
We do not reconfigure buildDir anywhere, it is always “build”.
We have not reconfigured any java output locations either. It is always build/classes/java/…
Also, I have about 95,000 files under various build/classes folders. There are lots of other files under build/ for other projects that build wars and that kind of stuff. But as far as class files go, it is about 95k.
I put Gradle in the debugger and I can see that org.gradle.internal.cleanup.DefaultBuildOutputCleanupRegistry#doResolvePaths takes me 5 seconds to run. You can also see the size of two important variables - the outputs HashSet has 1320 entries and the result has 2759 entries. BTW, this runs 100x faster on Linux (which probably isn’t a surprise). Does anybody know if this code has changed at all in Gradle 4.10? I can work today on getting Gradle 4.10 working so I can test there if there is a chance this might work better there.
We have a branch that uses 4.10. I’m working through some environmental issues to get that branch to build correctly and once I do that I will produce a scan and see what is going on.