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

Android Build Performance at DenverDroids

Android Build Performance at DenverDroids

Avatar for Tony Robalik

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