diff --git a/.gitattributes b/.gitattributes index fe5acc3a..c869a49f 100644 --- a/.gitattributes +++ b/.gitattributes @@ -2,3 +2,4 @@ **/dependencies/** linguist-generated **/clawicons/** linguist-generated android/src/main/baseline-prof.txt linguist-generated -diff +android/src/main/generated/** linguist-generated -diff diff --git a/.github/workflows/baseline-profile.yml b/.github/workflows/baseline-profile.yml index ddda0e91..4a9066b3 100644 --- a/.github/workflows/baseline-profile.yml +++ b/.github/workflows/baseline-profile.yml @@ -51,40 +51,27 @@ jobs: # This allows us to build most of what we need without the emulator running # and using resources - name: Build app and benchmark - run: ./gradlew :benchmark:assembleBenchmark :android:assembleBenchmark + run: ./gradlew :benchmark:assembleNonMinifiedBenchmark :android:assembleNonMinifiedRelease - - name: Clear unused Gradle Managed Devices - run: ./gradlew cleanManagedDevices --unused-only + - name: Setup emulator for benchmark + run: ./gradlew :benchmark:api31Setup - name: Run benchmark on Gradle Managed Device run: | - ./gradlew api31BenchmarkAndroidTest \ - -Dorg.gradle.workers.max=1 \ - -Pandroid.testInstrumentationRunnerArguments.androidx.benchmark.enabledRules=BaselineProfile \ + ./gradlew cleanManagedDevices + ./gradlew generateBaselineProfile \ -Pandroid.testoptions.manageddevices.emulator.gpu="swiftshader_indirect" - # If we're on main branch, copy over the baseline profile and - # commit it to the repository (if changed) + # If we're on main branch, commit the baseline profile to the repository (if changed) - name: Commit baseline profile into main if: github.ref == 'refs/heads/main' run: | - # Pull down any changes which may have been committed while this workflow has been running - git pull - # Sort the baseline profile, output to android/ - sort -o android/src/main/baseline-prof.txt benchmark/build/outputs/managed_device_android_test_additional_output/benchmark/api31/BaselineProfileGenerator_generateBaselineProfile-baseline-prof.txt # If the baseline profile has changed, commit it - if [[ $(git diff --stat android/src/main/baseline-prof.txt) != '' ]]; then - git add android/src/main/baseline-prof.txt + if [[ $(git diff --stat android/src/main/generated/baselineProfiles/baseline-prof.txt) != '' ]]; then + git add android/src/main/generated/baselineProfiles/baseline-prof.txt git commit -m "chore(android): refresh baseline profile" && git push fi - # Upload the entire output folder and attach it to the CI run - - name: Attach baseline profile - uses: actions/upload-artifact@0b7f8abb1508181956e8e162db84b466c27e18ce # v3.1.2 - with: - name: Baseline profile output - path: benchmark/build/outputs/managed_device_android_test_additional_output - - name: Clean secrets if: always() run: scripts/signing-cleanup.sh diff --git a/android/benchmark-rules.pro b/android/benchmark-rules.pro deleted file mode 100644 index e9caf635..00000000 --- a/android/benchmark-rules.pro +++ /dev/null @@ -1 +0,0 @@ --dontobfuscate diff --git a/android/build.gradle.kts b/android/build.gradle.kts index 33a56bf2..c367669f 100644 --- a/android/build.gradle.kts +++ b/android/build.gradle.kts @@ -18,6 +18,7 @@ plugins { alias(libs.plugins.anvil) alias(libs.plugins.modulegraphassert) alias(libs.plugins.whetstone) + alias(libs.plugins.baselineprofile) } android { @@ -28,18 +29,16 @@ android { useLiveLiterals = false kotlinCompilerExtensionVersion = libs.versions.composeCompiler.get() } - buildTypes { - create("benchmark") { - signingConfig = signingConfigs["debug"] - matchingFallbacks += "release" - isDebuggable = false - proguardFile("benchmark-rules.pro") - applicationIdSuffix = ".benchmark" - } - } packaging { jniLibs { useLegacyPackaging = true } } } +baselineProfile { + dexLayoutOptimization = true + mergeIntoMain = true + saveInSrc = true + from(projects.benchmark.dependencyProject) +} + moduleGraphAssert { assertOnAnyBuild = true maxHeight = 4 diff --git a/android/src/main/baseline-prof.txt b/android/src/main/generated/baselineProfiles/startup-prof.txt similarity index 78% rename from android/src/main/baseline-prof.txt rename to android/src/main/generated/baselineProfiles/startup-prof.txt index fab32bd4..fce6a466 100644 Binary files a/android/src/main/baseline-prof.txt and b/android/src/main/generated/baselineProfiles/startup-prof.txt differ diff --git a/benchmark/build.gradle.kts b/benchmark/build.gradle.kts index 6a12cadb..30d43fbc 100644 --- a/benchmark/build.gradle.kts +++ b/benchmark/build.gradle.kts @@ -10,13 +10,14 @@ import com.android.build.api.dsl.ManagedVirtualDevice plugins { alias(libs.plugins.android.test) - id("dev.msfjarvis.claw.android-common") id("dev.msfjarvis.claw.kotlin-android") + alias(libs.plugins.baselineprofile) } android { namespace = "dev.msfjarvis.claw.benchmark" + compileSdk = 34 defaultConfig { minSdk = 28 testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" @@ -30,23 +31,23 @@ android { } } - testOptions { - managedDevices { - devices { - create("api31") { - device = "Pixel 6" - apiLevel = 31 - systemImageSource = "aosp" - } - } + testOptions.managedDevices.devices { + create("api31") { + device = "Pixel 6" + apiLevel = 31 + systemImageSource = "aosp" } } targetProjectPath = ":android" - experimentalProperties["android.experimental.self-instrumenting"] = true + experimentalProperties["android.experimental.r8.dex-startup-optimization"] = true } -androidComponents { beforeVariants(selector().all()) { it.enable = it.buildType == "benchmark" } } +baselineProfile { + managedDevices += "api31" + useConnectedDevices = false + enableEmulatorDisplay = false +} dependencies { implementation(libs.androidx.benchmark.macro.junit4) diff --git a/benchmark/src/main/kotlin/dev/msfjarvis/claw/benchmark/BaselineProfileGenerator.kt b/benchmark/src/main/kotlin/dev/msfjarvis/claw/benchmark/BaselineProfileGenerator.kt index 3eb56d2f..ba38febb 100644 --- a/benchmark/src/main/kotlin/dev/msfjarvis/claw/benchmark/BaselineProfileGenerator.kt +++ b/benchmark/src/main/kotlin/dev/msfjarvis/claw/benchmark/BaselineProfileGenerator.kt @@ -28,6 +28,7 @@ class BaselineProfileGenerator { baselineProfileRule.collect( packageName = PACKAGE_NAME, maxIterations = 8, + includeInStartupProfile = true, ) { device.executeShellCommand("pm clear $PACKAGE_NAME") diff --git a/benchmark/src/main/kotlin/dev/msfjarvis/claw/benchmark/BenchmarkUtils.kt b/benchmark/src/main/kotlin/dev/msfjarvis/claw/benchmark/BenchmarkUtils.kt index 325f7aea..46551315 100644 --- a/benchmark/src/main/kotlin/dev/msfjarvis/claw/benchmark/BenchmarkUtils.kt +++ b/benchmark/src/main/kotlin/dev/msfjarvis/claw/benchmark/BenchmarkUtils.kt @@ -12,7 +12,7 @@ import androidx.test.uiautomator.UiDevice import androidx.test.uiautomator.UiObject2 import androidx.test.uiautomator.Until -const val PACKAGE_NAME = "dev.msfjarvis.claw.android.benchmark" +const val PACKAGE_NAME = "dev.msfjarvis.claw.android" private const val AWAIT_TIMEOUT = 10_000L private const val SAVE_BUTTON_ID = "save_button" private const val NAV_ID_HOTTEST = "HOTTEST" diff --git a/build-logic/src/main/kotlin/dev/msfjarvis/claw/gradle/SentryPlugin.kt b/build-logic/src/main/kotlin/dev/msfjarvis/claw/gradle/SentryPlugin.kt index b60028f8..aa81252a 100644 --- a/build-logic/src/main/kotlin/dev/msfjarvis/claw/gradle/SentryPlugin.kt +++ b/build-logic/src/main/kotlin/dev/msfjarvis/claw/gradle/SentryPlugin.kt @@ -28,15 +28,7 @@ class SentryPlugin : Plugin { onVariants(selector().all()) { variant -> val sentryDsn = project.providers.environmentVariable(SENTRY_DSN_PROPERTY) variant.manifestPlaceholders.put("sentryDsn", sentryDsn.getOrElse("")) - } - onVariants(selector().withBuildType("benchmark")) { variant -> - variant.manifestPlaceholders.put("enableSentry", "false") - } - onVariants(selector().withBuildType("debug")) { variant -> - variant.manifestPlaceholders.put("enableSentry", "false") - } - onVariants(selector().withBuildType("release")) { variant -> - variant.manifestPlaceholders.put("enableSentry", "true") + variant.manifestPlaceholders.put("enableSentry", "${variant.name == "release"}") } } project.plugins.apply(io.sentry.android.gradle.SentryPlugin::class) diff --git a/gradle.properties b/gradle.properties index d494225a..d36392c1 100644 --- a/gradle.properties +++ b/gradle.properties @@ -43,8 +43,11 @@ android.dependencyResolutionAtConfigurationTime.disallow=true # Disallow parsing the manifest too early in the build process android.disableEarlyManifestParsing=true +# Prevent CI stalling during setup +android.experimental.testOptions.managedDevices.setupTimeoutMinutes=20 + # Disable warnings about unsupported features -android.suppressUnsupportedOptionWarnings=android.dependencyResolutionAtConfigurationTime.disallow,android.disableEarlyManifestParsing,android.suppressUnsupportedOptionWarnings +android.suppressUnsupportedOptionWarnings=android.dependencyResolutionAtConfigurationTime.disallow,android.disableEarlyManifestParsing,android.suppressUnsupportedOptionWarnings,,android.experimental.testOptions.managedDevices.setupTimeoutMinutes # Add opens for KAPT # https://youtrack.jetbrains.com/issue/KT-45545#focus=Comments-27-4862682.0-0 diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 810294a1..78b05ad1 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,6 +1,7 @@ [versions] accompanist = "0.31.4-beta" agp = "8.2.0-alpha14" +benchmark = "1.2.0-beta02" coil = "2.4.0" # @keep used for kotlinCompilerExtensionVersion composeCompiler = "1.5.1" @@ -19,7 +20,7 @@ workmanager = "2.9.0-alpha02" [libraries] accompanist-sysuicontroller = { module = "com.google.accompanist:accompanist-systemuicontroller", version.ref = "accompanist" } androidx-activity-compose = "androidx.activity:activity-compose:1.7.2" -androidx-benchmark-macro-junit4 = "androidx.benchmark:benchmark-macro-junit4:1.2.0-beta02" +androidx-benchmark-macro-junit4 = { module = "androidx.benchmark:benchmark-macro-junit4", version.ref = "benchmark" } androidx-browser = "androidx.browser:browser:1.5.0" androidx-compose-animation = { module = "androidx.compose.animation:animation" } androidx-compose-bom = "dev.chrisbanes.compose:compose-bom:2023.07.00-alpha02" @@ -98,6 +99,7 @@ whetstone = { module = "com.deliveryhero.whetstone:whetstone", version.ref = "wh [plugins] android-test = { id = "com.android.test", version.ref = "agp" } anvil = "com.squareup.anvil:2.4.7" +baselineprofile = { id = "androidx.baselineprofile", version.ref = "benchmark" } kotlin-serialization = { id = "org.jetbrains.kotlin.plugin.serialization", version.ref = "kotlin" } modulegraph = "dev.iurysouza.modulegraph:0.4.0" modulegraphassert = "com.jraska.module.graph.assertion:2.4.1" diff --git a/settings.gradle.kts b/settings.gradle.kts index 3c9f6d1a..98c8caf5 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -12,6 +12,8 @@ pluginManagement { exclusiveContent { forRepository { google() } filter { + includeGroup("androidx.baselineprofile") + includeGroup("androidx.benchmark") includeGroup("androidx.databinding") includeGroup("com.android") includeModule("com.android.test", "com.android.test.gradle.plugin")