Gradle 8.11: Faster Configuration Cache and Improved Configuration Time

cdsap

Iñaki Villar

Posted on November 17, 2024

Gradle 8.11: Faster Configuration Cache and Improved Configuration Time

As modularization becomes increasingly common in Android projects, it increases the number of subprojects within a Gradle build. While modularization brings many benefits—such as improved software development practices and reduced build times by reusing tasks unaffected by code changes—it also has a side effect: the configuration time in Gradle projects increases as the project structure grows. For instance, the following graph represents a build executing the :help task in a project containing between 100 and 1000 modules, incremented in steps of 100, during a fresh daemon build:

Image description

The Configuration Cache feature, introduced by the Gradle team, addresses this problem by caching the result of the configuration phase of the build, then reusing it in subsequent builds if no relevant changes have occurred. This feature made local development faster and easier to work with, enabling faster build cycles. However, as projects grow, new optimizations to the configuration cache are needed to continue providing the best possible developer experience.

Gradle 8.11 introduces new improvements to the configuration cache process, including per-project serialization and string deduplication. Additionally, it introduces a new incubating feature that enables storing and loading the configuration cache in parallel, resulting in improved performance.
To enable the feature, add the following flag in gradle.properties:

org.gradle.configuration-cache.parallel=true
Enter fullscreen mode Exit fullscreen mode

In this article, we will share the results of our experiments with the new Gradle 8.11 parallel configuration cache feature in the nowinandroid project and explore how both local and CI builds can benefit from decreased configuration time.

Methodology

As always, before diving into the results, let's take a look at the experiment:

Project

The experiment uses a project forked from nowinandroid(latest commit).
The task used for this experiment is assembleDebug.

Variants Experiment

Scenarios

  • Build with configuration cache miss:
    • Dependencies prepopulated in the Gradle user home.
    • Using clean agents.
  • Build with configuration cache hit.

Environment

Github Action runner:

  • Linux 6.5.0-1025-azure
  • 4 cores
  • JDK 17
  • Xmx 4GB (Gradle-Kotlin)
Scenario Configuration Cache Miss

100 iterations for each variant using Telltale to orchestrate the execution.

Scenario Configuration Cache Hit

20 iterations for each variant using Gradle Profiler and Telltale.

Metrics

  • The build metrics data is published to Develocity using build scans.
  • With the Develocity API, experiment configuration cache metrics are now accessible via the new endpoint: /api/builds/{id}/gradle-configuration-cache, introduced in Develocity 2024.2. Example output:
{
  "result": {
    "outcome": "HIT",
    "entrySize": 1254385,
    "load": {
      "duration": 500,
      "hasFailed": false
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

Results

Configuration cache entry size

Before diving into the results related to durations, we first analyze the impact of these optimizations on reducing the size of the cache artifact:

Image description

  • Gradle 8.11 has reduced the size of the cache entry for the assembleDebug task by 14.67%.
  • Enabling parallel configuration results in the same cache artifact size as Gradle 8.11.

Configuration time with cache miss (dependencies already downloaded)

This scenario simulates a configuration cache miss, ensuring that all dependencies are pre-downloaded to eliminate the impact of network latency during dependency resolution. The median result for each variant is as follows:

Image description

  • Gradle 8.11 reduced the configuration time by 4.26%
  • Gradle 8.11 with parallel configuration cache reduced the configuration time by 8.16%

Configuration Cache Miss (using clean agents)

In this scenario, we are working with clean agents that request dependencies. The median result for each variant is as follows:
Image description

  • Gradle 8.11 reduced the configuration time by 14.5%.
  • Gradle 8.11 with parallel configuration further reduced configuration time by 31.72%.

Here, we have some very interesting results showing that using the parallel configuration cache reduces configuration time by 85 seconds. This highlights the significant benefits of enabling parallel configuration cache.

Configuration cache operations (dependencies already downloaded)

Storing cache entry

Using the Develocity API, we extracted the store operation duration for each variant in the scenario where the dependencies are already provided:

Image description

  • Comparing 8.10 to 8.11 with parallel configuration cache shows a significant improvement of 29.58% on the median for the operation of saving the configuration cache entry.

Load cache entry

Using the Develocity API, this time we extracted the load operation duration for each variant in the scenario where the dependencies are already provided:

Image description

  • Gradle 8.11: Offers a significant improvement over 8.10 for this metric, reducing the value by over 20%.
  • Parallel Configuration in 8.11 increases the value slightly compared to default 8.11, it still performs better than 8.10 overall.

Configuration cache operations (using clean agents)

In the scenario with clean agents, we noticed high variability due to non-deterministic connectivity operations. For instance, in the case of the load operation:

Image description

and for the store operation:

Image description

We observed a slight improvement when using 8.11 parallel, but the visualization is noisy. For this reason, we chose to present the percentiles instead:

Storing cache entry

Image description

  • Gradle 8.11 offers modest improvements over 8.10 across all percentiles, particularly at the median and upper quartile levels.

  • Gradle 8.11 with Parallel Configuration Cache dramatically reduces metrics across all percentiles, like the median with an improvement of 65%.

Loading cache entry

Image description

  • Gradle 8.11 median value improved (decreased) by approximately 11.6% when moving from Gradle 8.10.
  • Gradle 8.11 parallel configuration median value improved (decreased) by approximately 14.6% when moving from Gradle 8.10.

Configuration Cache Hit

For the second scenario, using Gradle Profiler, we iterated over the same runner executing the same build. In this case, the configuration cache was hit, and we measured the median configuration time for those builds. The results are as follows:

Image description

We noticed a slight improvement in the median configuration time when hitting the cache. However, given the size of the project, the reduction in duration is not significant.

Configuration Cache Hit - load time

Finally, for the same scenario—hitting the configuration cache—we analyzed the output of the Develocity endpoint for the load operation:
Image description

  • Gradle 8.11 and Gradle 8.11 parallel offer significant improvements over 8.10, with reductions of 30.6% and 26%, respectively. However, in the context of this project, the value of the load operation in the experiment is not significant.

References Experiment

Build Scans

Configuration cache miss scenarios

Dependencies Cache Clean Agents
Gradle 8.10 Build Scans Build Scans
Gradle 8.11 Build Scans Build Scans
Gradle 8.11 Parallel Build Scans Build Scans

Configuration cache hit scenarios

Gradle Profiler Builds
Gradle 8.10 Build Scans
Gradle 8.11 Build Scans
Gradle 8.11 Parallel Build Scans

Experiments

Experiment Scenario Results
Gradle 8.10 vs Gradle 8.11 Dependencies Cache Experiment
Gradle 8.11 vs Gradle 8.11 Parallel Dependencies Cache Experiment
Gradle 8.10 vs Gradle 8.11 Clean Experiment
Gradle 8.11 vs Gradle 8.11 Parallel Clean Experiment
Gradle 8.10 vs Gradle 8.11 Gradle Profiler Experiment
Gradle 8.11 vs Gradle 8.11 Parallel Gradle Profiler Experiment

Final notes

Analyzing the results, we've observed a significant improvement in configuration time when enabling org.gradle.configuration-cache.parallel. This feature not only reduces the configuration time but also reduces the configuration cache entry size. This means the Gradle model saved in the cache uses less space on disk. As a result, the cache is stored and loaded faster, which is especially helpful for big and complex projects.

Of course, the results are based on the project under experiment and may vary depending on your project, but we strongly recommend enabling org.gradle.configuration-cache.parallel to take advantage of these improvements.

Happy Building!

💖 💪 🙅 🚩
cdsap
Iñaki Villar

Posted on November 17, 2024

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related