How I save 5h/week on Gradle builds

From 4 minutes to 8 seconds

César Ferreira
AndroidPub

--

Gradle, the new build system for Android projects is the next evolutionary step in JVM-based build tools. It draws on lessons learned from established tools (such as Ant and Maven) and takes their best ideas to the next level. With Android projects becoming increasingly complex and modular development practices becoming more popular, build performance is critical. Saving a few seconds per build can make a big difference in productivity.

You might have realized, that even the simplest Gradle call is pretty slow. On my mac, it takes around six seconds to simply list the available tasks for my project’s gradlew.

Here are a few tips to increase the gradle task execution performance:

Gradle Daemon

You can decrease Gradle’s startup time (on my computer down to two seconds), if you tell Gradle to use a daemon to build:

org.gradle.daemon=true

Parallel Project Execution

This can really make a significant difference if you are building a very complex project with many sub-module dependencies:

org.gradle.parallel=true

Configure projects on demand

Gradle configures every project before executing tasks, regardless of whether the project is actually needed for the particular build. “Configuration on demand” mode changes this behaviour, only configuring required projects. Like parallel mode, configuration on demand mode will have the greatest effect on multi-module depencency builds.

Global gradle.properties

The properties defined in the property file in our home directory take precedence over the properties defined in the file in our project directory. The reasoning behind this is that you want to avoid using the Gradle daemon on your build servers, where startup time is less important than memory consumption:

/Users/cesarferreira/.gradle/gradle.properties

gradle.properties

Modules are expensive… I mean.. REALLY expensive!

On my current project at linkedcare I had to build some libraries from scratch and had to fork some that almost fitted my needs but not quite!

If that modules are not constantly modified, it’s important to have this into consideration: the time needed to compile them from scratch, or even to check if the previous individual module build is up-to-date, can be up to almost 4x greater than to simply load that dependency as a binary .jar/.aar.

Hint: run the gradle build -profile for an HTML report showing where the time goes regarding the build process.

Note: keep that “unnecessary” modules in your version control system for the eventuallity of a quickfix/improvement in that dependency.

From 4 minutes to 21 seconds

Based on these tips lets take a look at the performance report:

21 seconds? Well, that’s not bad at all.

Task execution profile

LINT TASK

If you take a look at your Task Execution profile, you’ll notice that the lint task is taking a lot of time, do you really need to check the lint output for your incremental builds? Lets take it out of the picture:

gradle build -x lint

All the way to 15 seconds? Nice boost!

From 12 to 8 seconds

lint vital release

Another lint check? That takes around ~90% of the time build time for the orders module?

Lets strip it down…

gradle build -x lint -x lintVitalRelease

All the way to **** 8 seconds **** !!

Tip: If you want to skip the lint check permanently from your incremental builds you can add this to your build.gradle:

Wrapping it up:

  • Have a global gradle.properties that all your projects will inherit;
  • Run the gradle build profile tool;
  • Stick to essential module dependencies (based on the profile tool results);
  • Skip unessencial gradle tasks;

If you have any question or want to share your results, hit me up on twitter @cesarmcferreira

--

--

César Ferreira
AndroidPub

Senior Android Developer, currently working as a Tech Lead @GlueHome. More on me @ https://cesarferreira.com