DEV Community

ColtonIdle
ColtonIdle

Posted on

How to profile your Android app's build time

If you've ever wondered "Will my project build faster with 8 gigs of ram vs 4" then this article is for you.

Today we'll be talking about the standalone gradle-profiler tool. There's a nice little intro into using it here: https://developer.android.com/studio/build/profile-your-build but a lot of the stuff there still went over my head. I am but a measly android developer, who still feels like I need a PhD to understand gradle.

I've got two typical scenarios I want to test that I run into every day.

  1. Builds after a clean
  2. Incremental builds

Builds after a clean seem to take my project around 3 minutes on average. This is completely unmeasured, but mostly this is what I see in the bottom right hand corner in Android Studio "You build finished in 3 minutes and 02 seconds". Going through a clean is pretty popular for me because sometimes things just don't work in the IDE (I think a lot of it is/might be due to kapt), but regardless I have to clean/invalidate caches/restart/hope that my build is fixed. And then re-run. This is the scenario I want to test first.

Install gradle-profiler

git clone https://github.com/gradle/gradle-profiler
    && cd gradle-profiler
    && ./gradlew installDist
Enter fullscreen mode Exit fullscreen mode

Edit: Now available on brew

brew install gradle-profiler
Enter fullscreen mode Exit fullscreen mode

CD into the gradle-profiler

CD into the profiler build/install/gradle-profiler/bin

Create a scenarios.txt

A scenarios.txt lists all of the scenarios that the gradle-profiler will run through. I found that the one that is in the Android Studio docs wasn't that helpful to me in testing my first scenario. I did get a ton of help from Paul Merlin who works on the Gradle team.

This is mine

clean_build_1gb {
    tasks = [":app:assembleFreeDebug", "--rerun-tasks"]
    jvm-args = ["-Xmx1024m", "-Dkotlin.daemon.jvm.options=-Xmx1024m"]
}

clean_build_2gb {
    tasks = [":app:assembleFreeDebug", "--rerun-tasks"]
    jvm-args = ["-Xmx2048m", "-Dkotlin.daemon.jvm.options=-Xmx2048m"]
}

clean_build_4gb {
    tasks = [":app:assembleFreeDebug", "--rerun-tasks"]
    jvm-args = ["-Xmx4096m", "-Dkotlin.daemon.jvm.options=-Xmx4096m"]
}

clean_build_8gb {
    tasks = [":app:assembleFreeDebug", "--rerun-tasks"]
    jvm-args = ["-Xmx8192m", "-Dkotlin.daemon.jvm.options=-Xmx8192m"]
}

clean_build_16gb {
    tasks = [":app:assembleFreeDebug", "--rerun-tasks"]
    jvm-args = ["-Xmx16384m", "-Dkotlin.daemon.jvm.options=-Xmx16384m"]
}

clean_build_32gb {
    tasks = [":app:assembleFreeDebug", "--rerun-tasks"]
    jvm-args = ["-Xmx32768m", "-Dkotlin.daemon.jvm.options=-Xmx32768m"]
}
Enter fullscreen mode Exit fullscreen mode

As you can see, I test from 1 to 32GB (my machine has a lot of ram), and I set the JVM args and kotlin jvm args to that same amount. I suppose that it would be good if I could tweak both of them to variable and just run this overnight and somehow have it run in a bunch of combinations to see what works best, but I haven't figure out how to do that yet.

You can note that I also added "--rerun-tasks" argument because according to (Paul Merlin)[https://github.com/eskatos] this means "If you want to benchmark a "rebuild everything" scenario you can ... use --rerun-tasks."

Run the profiler

./gradle-profiler --benchmark --project-dir ~/dev/rollertoaster --scenario-file ~/dev/rollertoaster/scenarios.txt
Enter fullscreen mode Exit fullscreen mode

This runs the profiler, pointed at my project file, and points it at the scenarios file in my project. (I'm saving the scenarios there so that other people on my team can easily benchmark and update their local gradle.properties file. The entire thing that has caused me to really try the profiler was the fact that my CI has wildly different ram, vs my desktop, vs my laptop, and all of us adhering to a single gradle.properties felt stupid)

After

Running the profiler could take some time as it runs a few iterations, but it will eventually give you a directory to open. In this directory you'll have an html document and you can pretty much look at the "Mean" column and choose the fastest one for you. Here I'm showing the .CSV output and you can see that my 1GB and 2GB builds failed completely, but to my surprise there wasn't much difference in adding RAM after 4GB.

Then try no-op scenario.

From Tony Robalik

It is named noop (for "no-op"), which runs the :app:assembleDebug task. I call it "no-op" because there are no file changes in this scenario, so every assemble after the first should be a "no-op." This scenario tests whether your primary daily task is well-configured: the task and all its dependencies should all be UP-TO-DATE; this build should be very fast.

noop {
  tasks = [":app:assembleDebug"]
}
Enter fullscreen mode Exit fullscreen mode

Next up, incremental changes!

IN PROGRESS

Screen Shot 2021-04-27 at 3.08.16 AM

Thanks to Adam Bennet's article that introduced me to gradle-profiler and how simple it was to get started.

Also see: https://dev.to/autonomousapps/benchmarking-builds-with-gradle-profiler-oa8

Heroku

Build apps, not infrastructure.

Dealing with servers, hardware, and infrastructure can take up your valuable time. Discover the benefits of Heroku, the PaaS of choice for developers since 2007.

Visit Site

Top comments (0)

Qodo Takeover

Introducing Qodo Gen 1.0: Transform Your Workflow with Agentic AI

Rather than just generating snippets, our agents understand your entire project context, can make decisions, use tools, and carry out tasks autonomously.

Read full post

👋 Kindness is contagious

Please leave a ❤️ or a friendly comment on this post if you found it helpful!

Okay