Refresh Gradle project refreshes all projects

Not sure if I understand how “Refresh Gradle Project” works.

If I add a dependency to a project in my workspace that is only ever referenced in the deploy configuration for the “ear” task Buildship still synchronizes all projects in my Eclipse workspace when hitting Refresh project. Since the build contains ~200 modules this takes several minutes to finish. I would have expected that Gradle will only refresh the projects that depend on the changed project. Can someone explain how “Refresh Gradle project” works?

With such a large workspace changes in project dependencies become pretty annoying. After performing a flight recorder analysis Buildship seems to spend most of the time in “org.eclipse.core.internal.resources.Resource.refreshLocal()” which seems to be pretty slow.

Assuming that you use 1.0.x version of Buildship, here’s how the refresh works:
Based on the current selection, Buildship collects all imported Gradle builds that have at least one selected project. A project synchronization is then executed on all projects contained by the collected Gradle builds.

It should be faster than that, especially if you recently did a refresh already. I can import a 500 module build in about 20s and refresh it in 10s. That number is mostly dominated by Gradle`s configuration time, which is improved in every release.

Can you tell us a little more about which operation is taking long? Configuration? Depenency Resolution? If you do a profiler run of Buildship, you won’t see those, since the Gradle build runs in a different process.

As mentioned above, the flight recorder might be misleading here, as it only contains the work that Buildship itself does and excludes what the Gradle daemon does (which is usually most of the work). If refreshLocal() really is the bottleneck, then hitthing F5 (refresh) on your projects should also take minutes. Is that the case?

I’m using Buildship version 1.0.15 on a reasonably fast i7 machine with 16GB RAM. Tried both Eclipse 4.4 and 4.5.
Refreshing all projects with F5 is not very fast but a lot faster than "Refresh Gradle projects"
Configuring projects and resolving dependencies is fairly quick. It actually spends most of the time in "Synchronize Gradle project “…” with workspace project"
Is there a way to profile this synchronization step, (e.g. similar to --profile switch in Gradle)? Or would I just try to profile the Gradle process?
I’d be very interested in optimizing this process since it’s the only thing my team is complaining about after migrating the build from Ivy to Buildship.

Had a closer look at the processes involved when performing the refresh. The Gradle daemon is already idle while Eclipse is using 100% CPU on a single core while “Synchronize Gradle project ‘…’ with workspace project” runs.

So it seems it’s not a problem with the Gradle build itself but more an Eclipse issue, would you agree?

If it takes time in the Synchronize with workspace project step, then profiling Eclipse itself is the way to go. If you could upload a CPU flame graph or some profiler snapshot, that would be awesome :slight_smile:

Screenshot of the profiler results. I wasn’t able to upload the whole profiling dump since it exceeds the upload limit by a few kBs.
Will try to make it available on Dropbox or something.

Here is a link to the profiler dump:

This should be importable using Java Mission Control.

Thank you for the profiler dump, Wolfgang! I’ll get back to you once I have some results on what we can improve.

I think we can significantly improve the user experience by not doing the synchronous refresh. This is something that we had in mind for a while but never had evidence that it was causing real user pain. Thanks for bringing this to our attention!

For completeness sake, could you include a profiler dump of just hitting F5 on those projects?

1 Like

Great news, doing a refresh in the background (or something similar) would be really helpful, I guess.

Here’s the dump from hitting refresh: (1.1 MB)

Thanks for the recording. It seems that doing the refresh inside a JavaModel transaction also has the side effect of creating a lot of memory pressure, because JDT buffers all the classpath change events.