Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
Android Build Performance - DroidconSF 2018
Search
Tony Robalik
November 20, 2018
Programming
1
65
Android Build Performance - DroidconSF 2018
This is a reprisal of my earlier presentation at DroidconNYC, with a few minor updates.
Tony Robalik
November 20, 2018
Tweet
Share
More Decks by Tony Robalik
See All by Tony Robalik
Android Build Performance at DenverDroids
autonomousapps
1
110
Improving Android Build Performance
autonomousapps
4
620
Other Decks in Programming
See All in Programming
Claude Agent SDK を使ってみよう
hyshu
0
600
Cursorハンズオン実践!
eltociear
2
1.1k
株式会社 Sun terras カンパニーデック
sunterras
0
310
なぜGoのジェネリクスはこの形なのか? Featherweight Goが明かす設計の核心
ryotaros
7
1.1k
あなたとKaigi on Rails / Kaigi on Rails + You
shimoju
0
160
他言語経験者が Golangci-lint を最初のコーディングメンターにした話 / How Golangci-lint Became My First Coding Mentor: A Story from a Polyglot Programmer
uma31
0
160
The Past, Present, and Future of Enterprise Java
ivargrimstad
0
350
PHPに関数型の魂を宿す〜PHP 8.5 で実現する堅牢なコードとは〜 #phpcon_hiroshima / phpcon-hiroshima-2025
shogogg
1
230
ALL CODE BASE ARE BELONG TO STUDY
uzulla
25
5.9k
Railsだからできる 例外業務に禍根を残さない 設定設計パターン
ei_ei_eiichi
0
910
Introducing ReActionView: A new ActionView-Compatible ERB Engine @ Kaigi on Rails 2025, Tokyo, Japan
marcoroth
3
1k
理論と実務のギャップを超える
eycjur
0
140
Featured
See All Featured
Embracing the Ebb and Flow
colly
88
4.8k
Making Projects Easy
brettharned
120
6.4k
Why Our Code Smells
bkeepers
PRO
340
57k
個人開発の失敗を避けるイケてる考え方 / tips for indie hackers
panda_program
115
20k
CoffeeScript is Beautiful & I Never Want to Write Plain JavaScript Again
sstephenson
162
15k
Building a Scalable Design System with Sketch
lauravandoore
463
33k
Six Lessons from altMBA
skipperchong
29
4k
Helping Users Find Their Own Way: Creating Modern Search Experiences
danielanewman
30
2.9k
A better future with KSS
kneath
239
18k
Balancing Empowerment & Direction
lara
4
690
Fireside Chat
paigeccino
40
3.7k
Designing for humans not robots
tammielis
254
26k
Transcript
Improving Android Build Performance Tony Robalik, Gradle Inc.
None
The Cost of Builds (#perfmatters)
| X Fast Builds Matter 60s waste * 50 builds
per day * 10 developers > 8h wasted per day …and that’s not even considering lost focus https://gradle.com/quantifying-the-costs-of-builds/
| X
| X
| X Fast Builds Matter Don’t even get me started
on morale…
General Advice
| X #science 1. Define scenario to improve 2. Profile
scenario 3. Identify biggest bottleneck 4. Fix bottleneck 5. Verify fix by measurement 6. Repeat
| X Automate your measurements github.com/gradle/gradle-profiler $ gradle-profiler --benchmark --scenario-file
scenarios // Scenario 1 configurationTime { tasks = ["help"] } // Scenario 2 assembleNoCache { tasks = ["clean", “assembleDebug”] gradle-args = ["--no-build-cache"] } // Scenario 3 assembleCache { tasks = ["clean", "assembleDebug"] gradle-args = ["--build-cache"] }
| X Automate your measurements github.com/gradle/gradle-profiler $ gradle-profiler --benchmark --scenario-file
scenarios // Scenario 1 configurationTime { tasks = ["help"] } // Scenario 2 assembleNoCache { tasks = ["clean", “assembleDebug”] gradle-args = ["--no-build-cache"] } // Scenario 3 assembleCache { tasks = ["clean", "assembleDebug"] gradle-args = ["--build-cache"] }
| X Automate your measurements github.com/gradle/gradle-profiler $ gradle-profiler --benchmark --scenario-file
scenarios // Scenario 1 configurationTime { tasks = ["help"] } // Scenario 2 assembleNoCache { tasks = ["clean", “assembleDebug”] gradle-args = ["--no-build-cache"] } // Scenario 3 assembleCache { tasks = ["clean", "assembleDebug"] gradle-args = ["--build-cache"] }
| X Stay Up-To-Date buildscript { repositories { google() }
dependencies { classpath ‘com.android.tools.build:gradle:3.2.1’ } } $ ./gradlew wrapper --gradle-version 4.10.2
| X JVM tuning Provide enough heap space Other tweaks
often do more harm than good Spend your time on structural improvements
| X JVM tuning Provide enough heap space Other tweaks
often do more harm than good Spend your time on structural improvements # The only useful argument org.gradle.jvmargs=-Xmx4g
| X JVM tuning
Where is the Problem?
| X Build Scans
| X Build Scans $ ./gradlew assembleDebug --scan
| X Build Scans $ ./gradlew assembleDebug --scan
| X The Build Lifecycle
| X Red Flags Startup/Settings/buildSrc > 1s Single-line change ℳ
clean build No-op build doing any work at all High GC time
| X Red Flags Startup/Settings/buildSrc > 1s Single-line change ℳ
clean build No-op build doing any work at all High GC time
| X Red Flags Startup/Settings/buildSrc > 1s Single-line change ℳ
clean build No-op build doing any work at all High GC time
| X Red Flags Startup/Settings/buildSrc > 1s Single-line change ℳ
clean build No-op build doing any work at all High GC time
| X Red Flags Startup/Settings/buildSrc > 1s Single-line change ℳ
clean build No-op build doing any work at all High GC time
Your Build
Startup, buildSrc, Settings
| X Startup, buildSrc, Settings Use the daemon, keep it
healthy
| X Startup, buildSrc, Settings Don’t do this // settings.gradle
rootDir.listFiles({ File dir, String name -> name.endsWith(“.gradle") } as FilenameFilter) .each { include "$it" } ? ¿
| X Startup, buildSrc, Settings Don’t do this // settings.gradle
rootDir.listFiles({ File dir, String name -> name.endsWith(“.gradle") } as FilenameFilter) .each { include "$it" }
| X Startup, buildSrc, Settings ?
Configuration Time
| X Configuration Time Applying plugins Evaluating build scripts Running
afterEvaluate {} blocks
| X Configuration Time When running any task Even gradlew
help / gradlew tasks Android Studio sync
| X Resolution at Configuration Time
| X Eager resolution Resolution at Configuration Time task badTask(type:
Jar) { from configurations.compile.collect { it.directory ? it : zipTree(it) } classifier “don’t do this” }
| X Eager resolution Resolution at Configuration Time task badTask(type:
Jar) { from configurations.compile.collect { it.directory ? it : zipTree(it) } classifier “don’t do this” }
| X Resolution at Configuration Time task badTask(type: Jar) {
from { configurations.compile.collect { it.directory ? it : zipTree(it) } } classifier “don’t do this” } Use lazy evaluation instead
| X Configuring Tasks import org.jmailen.gradle.kotlinter.tasks.LintTask tasks.register('lintKotlinAll', LintTask) { group
= 'verification' source files(modules.collect { "$it/src" }) reports = [ 'plain': file("$buildDir/reports/ktlint/all-lint.txt"), 'html' : file(“$buildDir/reports/ktlint/all-lint.html”) ] }
| X Inefficient Plugins
| X Expensive logic for each project Inefficient Plugins //
`version.gradle` def out = new ByteArrayOutputStream() exec { commandLine 'git', 'rev-parse', “HEAD” standardOutput = out workingDir = rootDir } version = new String(out.toByteArray()) // root `build.gradle` subprojects { apply from: "$rootDir/version.gradle" }
| X Inefficient Plugins // `version.gradle` as before // root
`build.gradle` apply from: "$rootDir/version.gradle" subprojects { version = rootProject.version } Reuse expensive calculations
| X Variant Explosion https://developer.android.com/studio/build/build-variants#filter-variants variantFilter { variant -> def
flavorName = variant.flavors[0].name def freeFlavor = flavorName == "free" if (!freeFlavor && variant.buildType.name == "release") { variant.ignore = true } }
| X Variant Explosion https://developer.android.com/studio/build/build-variants#filter-variants variantFilter { variant -> def
flavorName = variant.flavors[0].name def freeFlavor = flavorName == "free" if (!freeFlavor && variant.buildType.name == "release") { variant.ignore = true } }
| X Configuration Time Avoid dependency resolution Avoid I/O Don’t
repeat yourself
Optimizing Build Logic
| X Extract Script Plugins apply from: "$rootDir/static_analysis.gradle" apply from:
"$rootDir/coverage.gradle" apply from: “$rootDir/spock_android_lib.gradle” apply from: "$rootDir/junit5html.gradle" if (isOnCi()) { // This plugin adds ~5s to every build apply plugin: 'com.getkeepsafe.dexcount' } Makes finding issues easier
| X Extract Binary Plugins Use buildSrc Use static compilation
Keep build scripts declarative https://docs.gradle.org/current/userguide/organizing_gradle_projects.html#sec:build_sources
| X Extract Binary Plugins https://docs.gradle.org/current/userguide/organizing_gradle_projects.html#sec:build_sources $rootDir/buildSrc/ src/main/<java|kotlin|groovy>/ com/yourCompany/ all/the/things/
Execution Time
| X Execution Time Executing selected tasks Incremental Cacheable Parallelizable
| X Execution Time Executing selected tasks Incremental Cacheable Parallelizable
| X Execution Time Executing selected tasks Incremental Cacheable Parallelizable
| X Execution Time Executing selected tasks Incremental Cacheable Parallelizable
| X Incremental Builds Nothing changed? Executed tasks should be
zero!
| X Incremental Builds Nothing changed? Executed tasks should be
zero!
| X Incremental Builds Find volatile inputs
| X Incremental Builds android { defaultConfig { versionName “4.0.0-${new
Date()}” } }
| X Example: Crashlytics Unique IDs are the bane of
local dev performance
| X Example: Crashlytics Unique IDs are the bane of
local dev performance apply plugin: 'io.fabric' android { buildTypes { debug { ext.alwaysUpdateBuildId = false } } }
| X Faster Compilation Modularization => Compile avoidance Decoupled code
=> Faster incremental compilation Careful with Kotlin annotation processing (for now)
| X Faster Compilation Modularization => Compile avoidance Decoupled code
=> Faster incremental compilation Careful with Kotlin annotation processing (for now) https://youtrack.jetbrains.com/issue/KT-24203
| X Faster Compilation Modularization => Compile avoidance Decoupled code
=> Faster incremental compilation Careful with Kotlin annotation processing (for now)
| X Faster Compilation Modularization => Compile avoidance Decoupled code
=> Faster incremental compilation Careful with Kotlin annotation processing (for now)
| X Incremental Annotation Processing Since Gradle 4.7 Early adopters:
Lombok, Android-State, Dagger Others: github.com/gradle/gradle/issues/5277 (incap)
| X Incremental Annotation Processing Since Gradle 4.7 Early adopters:
Lombok, Android-State, Dagger Others: github.com/gradle/gradle/issues/5277 (incap)
| X The Build Cache https://guides.gradle.org/using-build-cache/ https://developer.android.com/studio/build/build-cache
| X The Build Cache https://guides.gradle.org/using-build-cache/ https://developer.android.com/studio/build/build-cache
| X The Build Cache https://guides.gradle.org/using-build-cache/ # gradle.properties org.gradle.caching=true https://developer.android.com/studio/build/build-cache
| X The Build Cache https://guides.gradle.org/using-build-cache/ # gradle.properties org.gradle.caching=true $
./gradlew assembleDebug --build-cache https://developer.android.com/studio/build/build-cache
| X The Build Cache https://guides.gradle.org/using-build-cache/ Many tasks are cacheable
https://developer.android.com/studio/build/build-cache
| X https://developer.android.com/studio/build/build-cache Save time for your whole team with
one or more remote caches https://guides.gradle.org/using-build-cache/ The Build Cache
| X https://developer.android.com/studio/build/build-cache https://guides.gradle.org/using-build-cache/ The Build Cache // root build.gradle
subprojects { pluginManager.withPlugin("kotlin-kapt") { kapt.useBuildCache = true } }
| X Parallelism # Or in gradle.properties org.gradle.parallel=true $ ./gradlew
assembleDebug --parallel
| X Parallelism Serial execution
| X Parallelism --parallel and small, decoupled projects
Keeping track of performance
| X Gradle Enterprise
| X See all Builds Find out what colleagues are
struggling with
| X Detailed Performance Profile
| X Watch Performance over Time
| X Watch Performance over Time
| X
Resources
| X Gradle performance guide https://guides.gradle.org/performance Android performance guide https://developer.android.com/studio/build/optimize-your-build.html
Plugin development guide https://guides.gradle.org/implementing-gradle-plugins Structuring build logic guide https://docs.gradle.org/current/userguide/organizing_build_logic.html Guides
| X scans.gradle.com
w Thank you DroidconSF 2018
[email protected]
@autonomousapps