Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Improving Android Build Performance

Improving Android Build Performance

We all know a fast build makes for a happy developer. Unfortunately, it’s easy for Android builds get complex and slow. You’ve updated to the latest Android Plugin, but your still waiting more than you like, what do you do?

Recent Gradle releases give you new capabilities to improve your build speed up to an order of magnitude. This session discusses how you can :

* Identify performance bottlenecks with build scans
* Fix common problems like: slow configuration time, tasks running when they shouldn’t, and builds that don’t parallelize well.
* Use Gradle Enterprise to diagnose project-wide issues and keep your newly-performant build performant.

Tony Robalik

August 27, 2018
Tweet

More Decks by Tony Robalik

Other Decks in Technology

Transcript

  1. | 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/
  2. | X

  3. | X

  4. | X #science 1. Define scenario to improve 2. Profile

    scenario 3. Identify biggest bottleneck 4. Fix bottleneck 5. Verify fix by measurement 6. Repeat
  5. | 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"] }
  6. | 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"] }
  7. | 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"] }
  8. | X Stay Up-To-Date buildscript { repositories { google() }

    dependencies { classpath ‘com.android.tools.build:gradle:3.1.4’ } } $ ./gradlew wrapper --gradle-version 4.9
  9. | X JVM tuning Provide enough heap space Other tweaks

    often do more harm than good Spend your time on structural improvements
  10. | 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
  11. | X Red Flags Startup/Settings/buildSrc > 1s Single-line change ℳ

    clean build No-op build doing any work at all High GC time
  12. | X Red Flags Startup/Settings/buildSrc > 1s Single-line change ℳ

    clean build No-op build doing any work at all High GC time
  13. | X Red Flags Startup/Settings/buildSrc > 1s Single-line change ℳ

    clean build No-op build doing any work at all High GC time
  14. | X Red Flags Startup/Settings/buildSrc > 1s Single-line change ℳ

    clean build No-op build doing any work at all High GC time
  15. | X Red Flags Startup/Settings/buildSrc > 1s Single-line change ℳ

    clean build No-op build doing any work at all High GC time
  16. | X Startup, buildSrc, Settings Don’t do this // settings.gradle

    rootDir.listFiles({ File dir, String name -> name.endsWith(“.gradle") } as FilenameFilter) .each { include "$it" } ? ¿
  17. | X Startup, buildSrc, Settings Don’t do this // settings.gradle

    rootDir.listFiles({ File dir, String name -> name.endsWith(“.gradle") } as FilenameFilter) .each { include "$it" }
  18. | X Configuration Time When running any task Even `gradlew

    help` / `gradlew tasks` Android Studio sync
  19. | 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” }
  20. | 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” }
  21. | 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
  22. | 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" }
  23. | X Inefficient Plugins // `version.gradle` as before // root

    `build.gradle` apply from: "$rootDir/version.gradle" subprojects { version = rootProject.version } Reuse expensive calculations
  24. | 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 } }
  25. | 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 } }
  26. | 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
  27. | 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
  28. | X Example: Crashlytics Unique IDs are the bane of

    local dev performance apply plugin: 'io.fabric' android { buildTypes { debug { ext.alwaysUpdateBuildId = false } } }
  29. | X Faster Compilation Modularization => Compile avoidance Decoupled code

    => Faster incremental compilation Careful with Kotlin annotation processing (for now)
  30. | X Faster Compilation Modularization => Compile avoidance Decoupled code

    => Faster incremental compilation Careful with Kotlin annotation processing (for now)
  31. | X Faster Compilation Modularization => Compile avoidance Decoupled code

    => Faster incremental compilation Careful with Kotlin annotation processing (for now)
  32. | X Faster Compilation Modularization => Compile avoidance Decoupled code

    => Faster incremental compilation Careful with Kotlin annotation processing (for now)
  33. | X Incremental Annotation Processing Since Gradle 4.7 Early adopters:

    Lombok & Android-State Others: github.com/gradle/gradle/issues/5277
  34. | X Incremental Annotation Processing Since Gradle 4.7 Early adopters:

    Lombok & Android-State Others: github.com/gradle/gradle/issues/5277
  35. | 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/ Caching
  36. | 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