ProAndroidDev

The latest posts from Android Professionals and Google Developer Experts.

Follow publication

Profile & Benchmark Android Builds

Nika Chapidze
ProAndroidDev
Published in
7 min readMar 27, 2025

--

Generated by https://openai.com

#1 Android Studio Build Analyzer:

#2 Gradle Profile Option (Local)

./gradlew --profile assembleDebug  # Or assemble[Flavor]Debug

#3. Gradle Scan Option (Remote 🌐)

./gradlew --scan

Publishing a build scan to scans.gradle.com requires accepting the Gradle Terms of Use defined at https://gradle.com/help/legal-terms-of-use.
Do you accept these terms? [yes, no] yes
Gradle Terms of Use accepted.
Publishing build scan...
https://gradle.com/s/dtt4r5mtn655y

#4 Gradle Profiler tool

brew install gradle-profiler
gradle-profiler --benchmark \
--project-dir [root-dir] \
--output-dir [output-dir] \
--scenario-file scenarios.txt
scenario_name {
tasks = [":app:assembleDebug"] // gradle task for scenario

cleanup-tasks = ["clean"] // Cleanup gradle task

jvm-args = ["-Xmx4g", "-XX:+UseParallelGC"] // Java arguments

gradle-args = ["--max-workers=4"] // Gradle arguments

// Adds a public method to a Java or Kotlin source class. Each iteration adds a new method and removes the previously added one
apply-non-abi-change-to = ["path/your_code_file.java"]
// Changes the body of a public method in a Java or Kotlin source class
apply-abi-change-to = ["path/your_code_file.java"]

// Adds view to layout
apply-android-layout-change-to = "app/src/main/res/your_layout_file.xml"
// Adds composable
apply-kotlin-composable-change-to = "app/src/main/java/your_composable.kt"

// Changes value of string
apply-android-resource-value-change-to = "app/src/main/res/values/strings.xml"
// Adds new string
apply-android-resource-change-to = "src/main/res/values/strings.xml"

// checks out a specific commit for the build step, and a different one for the cleanup step.
git-checkout = {
cleanup = "efb43a1" #commit hash or branch name"
build = "master”
}
// Reverts a given set of commits before the build and resets it afterward.
git-revert = [“eaav2e4”]
}

— Testing Different Gradle & JVM Arguments

clean_build_parallelGC_4gb {
tasks = [":app:assembleDebug"]
jvm-args = ["-Xmx4g", "-XX:+UseParallelGC"]
cleanup-tasks = ["clean"]
}
clean_build_G1GC_2gb_max_workers_4 {
tasks = [":app:assembleDebug"]
gradle-args = ["--max-workers=4"]
jvm-args = ["-XX:+UseG1GC"]
cleanup-tasks = ["clean"]
}
parallelGC_4gb vs G1GC_2gb_max_workers_4
# <root-project>/scenarios.txt
non_parallel {
tasks = [":app:assembleDebug"]
clear-build-cache-before = SCENARIO
}
parallel {
tasks = [":app:assembleDebug"]
gradle-args = ["--parallel"]
clear-build-cache-before = SCENARIO
}
non-parallel vs parallel

— Enabling Caching for Faster Builds

# <root-project>/scenarios.txt
with_caching {
tasks = [":app:assembleDebug"]
gradle-args = ["--configuration-cache", "--build-cache"]
apply-non-abi-change-to = ["feature1/src/main/java/ge/chapo/feature1/DummyData.kt",
"feature2/src/main/java/ge/chapo/feature2/DummyData.kt",
"feature3/src/main/java/ge/chapo/feature3/DummyData.kt",
]
clear-build-cache-before = SCENARIO
}

without_caching {
tasks = [":app:assembleDebug"]
apply-non-abi-change-to = ["feature1/src/main/java/ge/chapo/feature1/DummyData.kt",
"feature2/src/main/java/ge/chapo/feature2/DummyData.kt",
"feature3/src/main/java/ge/chapo/feature3/DummyData.kt",
]
clear-build-cache-before = SCENARIO
}
gradle-profiler --benchmark --measure-config-time --measure-local-build-cache --project-dir ./ --output-dir ./build --scenario-file scenarios.txt --gradle-user-home=./build/gradle 
without caching vs with caching

— Changing files

# <root-project>/scenarios.txt
modify_functions {
tasks = [":app:assembleDebug"]
apply-abi-change-to = ["feature1/src/main/java/ge/chapo/feature1/DummyData.kt"]
apply-non-abi-change-to = ["feature1/src/main/java/ge/chapo/feature1/DummyData.kt"]
warm-ups = 1
iterations = 3
clear-build-cache-before = SCENARIO
}

modify_strings {
tasks = [":app:assembleDebug"]
apply-android-resource-change-to = ["feature1/src/main/res/values/strings.xml"]
warm-ups = 1
iterations = 3
clear-build-cache-before = SCENARIO
}

modify_layout {
tasks = [":app:assembleDebug"]
apply-android-layout-change-to = ["feature1/src/main/res/layout/some_layout.xml"]
warm-ups = 1
iterations = 3
clear-build-cache-before = SCENARIO
}

modify_compose {
tasks = [":app:assembleDebug"]
apply-kotlin-composable-change-to = ["app/src/main/java/ge/chapo/gradleoptimisationsample/MainActivity.kt"]
warm-ups = 1
iterations = 3
clear-build-cache-before = SCENARIO
}

— KAPT vs KSP (Git revert)

# <root-project>/scenarios.txt
kapt {
tasks = [":app:assembleDebug"]
git-revert = ["b1b1c7c1"]
cleanup-tasks = ["clean"]
warm-ups = 2
}

ksp {
tasks = [":app:assembleDebug"]
cleanup-tasks = ["clean"]
warm-ups = 2
}
kapt vs ksp

— Disabling jetifier (Git checkout)

# <root-project>/scenarios.txt
disable_jetifier {
tasks = [":app:assembleDebug"]
git-checkout = {
build = "master"
}
cleanup-tasks = ["clean"]
warm-ups = 1
}

enable_jetifier {
tasks = [":app:assembleDebug"]
git-checkout = {
build = "scenarios/7-jetifier"
}
cleanup-tasks = ["clean"]
warm-ups = 1
}

--

--