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

Android Build Performance at DenverDroids

Android Build Performance at DenverDroids

Tony Robalik

July 16, 2019
Tweet

More Decks by Tony Robalik

Other Decks in Programming

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.4.2’ } } $ ./gradlew wrapper --gradle-version 5.5.1
  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 > 5s Single-line change ℳ

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

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

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

    clean build No-op build doing any work at all High GC time
  15. | X Red Flags Startup/Settings/buildSrc > 5s 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 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”) ] }
  23. | 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" }
  24. | X Inefficient Plugins // `version.gradle` as before // root

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

    local dev performance apply plugin: 'io.fabric' android { buildTypes { debug { ext.alwaysUpdateBuildId = false } } }
  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) https://youtrack.jetbrains.com/issue/KT-24203
  32. | X Faster Compilation Modularization => Compile avoidance Decoupled code

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

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

    Lombok, Android-State, Dagger Others: github.com/gradle/gradle/issues/5277 (aka incap)
  35. | X Incremental Annotation Processing Since Gradle 4.7 Early adopters:

    Lombok, Android-State, Dagger Others: github.com/gradle/gradle/issues/5277 (aka incap)
  36. | 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
  37. | 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
  38. | X

  39. | 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