Nightly builds with baseline profiles (#1173)

* Overall build
  * Enable nightly builds
  * Enable Startup Profile generation for release builds
  * Skip BP generation for regular Builds
  * Test baseline profiles for all variants
* Cleanup
  * Remove stale baseline-prof.txt
  * Add generated profiles to .gitignore
* GMD
  * Setup GMD in separate step
  * Add GMD setup to all workflows
  * Lower GMD specs
  * Update GMD and Android SDK setup 
  * Add options test options for GMD startup
  * Ensure only one device is used for bp / benchmark
  * Apply guidance from issuetracker b/287312019
* Add new metrics for baseline profile measurement
  Added custom metrics to better understand how effective a baseline
  profile is. These TraceSectionMetrics keep track of JIT compilations
  as well as class initializations which should go down when a BP is
  properly applied to the app.
pull/1617/head
Ben Weiss 2 months ago committed by GitHub
parent f13324f13a
commit c01a129e4a
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

@ -25,6 +25,13 @@ jobs:
- name: Checkout - name: Checkout
uses: actions/checkout@v4 uses: actions/checkout@v4
- name: Enable KVM group perms
run: |
echo 'KERNEL=="kvm", GROUP="kvm", MODE="0666", OPTIONS+="static_node=kvm"' | sudo tee /etc/udev/rules.d/99-kvm4all.rules
sudo udevadm control --reload-rules
sudo udevadm trigger --name-match=kvm
ls /dev/kvm
- name: Copy CI gradle.properties - name: Copy CI gradle.properties
run: mkdir -p ~/.gradle ; cp .github/ci-gradle.properties ~/.gradle/gradle.properties run: mkdir -p ~/.gradle ; cp .github/ci-gradle.properties ~/.gradle/gradle.properties
@ -40,6 +47,12 @@ jobs:
validate-wrappers: true validate-wrappers: true
gradle-home-cache-cleanup: true gradle-home-cache-cleanup: true
- name: Setup Android SDK
uses: android-actions/setup-android@v3
- name: Accept licenses
run: yes | sdkmanager --licenses || true
- name: Check build-logic - name: Check build-logic
run: ./gradlew check -p build-logic run: ./gradlew check -p build-logic
@ -101,19 +114,22 @@ jobs:
commit_message: "🤖 Updates screenshots" commit_message: "🤖 Updates screenshots"
# Run local tests after screenshot tests to avoid wrong UP-TO-DATE. TODO: Ignore screenshots. # Run local tests after screenshot tests to avoid wrong UP-TO-DATE. TODO: Ignore screenshots.
- name: Run local tests and create report - name: Run local tests
if: always()
run: ./gradlew testDemoDebug :lint:test run: ./gradlew testDemoDebug :lint:test
# Replace task exclusions with `-Pandroidx.baselineprofile.skipgeneration` when
# https://android-review.googlesource.com/c/platform/frameworks/support/+/2602790 landed in a - name: Setup GMD
# release build run: ./gradlew :benchmarks:pixel6Api33Setup
--info
-Pandroid.experimental.testOptions.managedDevices.emulator.showKernelLogging=true
-Pandroid.testoptions.manageddevices.emulator.gpu="swiftshader_indirect"
- name: Build all build type and flavor permutations - name: Build all build type and flavor permutations
run: ./gradlew :app:assemble :benchmarks:assemble run: ./gradlew :app:assemble :benchmarks:assemble -Pandroidx.baselineprofile.skipgeneration
-x pixel6Api33ProdNonMinifiedReleaseAndroidTest -Pandroid.testoptions.manageddevices.emulator.gpu="swiftshader_indirect"
-x pixel6Api33DemoNonMinifiedReleaseAndroidTest -Pandroid.experimental.testOptions.managedDevices.emulator.showKernelLogging=true
-x collectDemoNonMinifiedReleaseBaselineProfile -Pandroid.experimental.androidTest.numManagedDeviceShards=1
-x collectProdNonMinifiedReleaseBaselineProfile -Pandroid.experimental.testOptions.managedDevices.maxConcurrentDevices=1
-Pandroid.experimental.testOptions.managedDevices.setupTimeoutMinutes=5
- name: Upload build outputs (APKs) - name: Upload build outputs (APKs)
uses: actions/upload-artifact@v4 uses: actions/upload-artifact@v4

@ -0,0 +1,43 @@
name: NightlyBaselineProfiles
on:
schedule:
- cron: '42 4 * * *'
jobs:
baseline_profiles:
name: "Generate Baseline Profiles"
runs-on: ubuntu-latest
permissions:
contents: write
timeout-minutes: 60
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Validate Gradle Wrapper
uses: gradle/wrapper-validation-action@v1
- name: Copy CI gradle.properties
run: mkdir -p ~/.gradle ; cp .github/ci-gradle.properties ~/.gradle/gradle.properties
- name: Set up JDK 17
uses: actions/setup-java@v4
with:
distribution: 'zulu'
java-version: 17
- name: Setup GMD
run: ./gradlew :benchmarks:pixel6Api33Setup
--info
-Pandroid.experimental.testOptions.managedDevices.emulator.showKernelLogging=true
-Pandroid.testoptions.manageddevices.emulator.gpu="swiftshader_indirect"
- name: Build all build type and flavor permutations including baseline profiles
run: ./gradlew :app:assemble
-Pandroid.testInstrumentationRunnerArguments.androidx.benchmark.enabledRules=baselineprofile
-Pandroid.testoptions.manageddevices.emulator.gpu="swiftshader_indirect"
-Pandroid.experimental.testOptions.managedDevices.emulator.showKernelLogging=true

@ -37,11 +37,17 @@ jobs:
validate-wrappers: true validate-wrappers: true
gradle-home-cache-cleanup: true gradle-home-cache-cleanup: true
- name: Install GMD image for baseline profile generation - name: Setup Android SDK
run: yes | "$ANDROID_HOME"/cmdline-tools/latest/bin/sdkmanager "system-images;android-33;aosp_atd;x86_64" uses: android-actions/setup-android@v3
- name: Accept Android licenses - name: Accept licenses
run: yes | "$ANDROID_HOME"/cmdline-tools/latest/bin/sdkmanager --licenses || true run: yes | sdkmanager --licenses || true
- name: Setup GMD
run: ./gradlew :benchmarks:pixel6Api33Setup
--info
-Pandroid.experimental.testOptions.managedDevices.emulator.showKernelLogging=true
-Pandroid.testoptions.manageddevices.emulator.gpu="swiftshader_indirect"
- name: Build release variant including baseline profile generation - name: Build release variant including baseline profile generation
run: ./gradlew :app:assembleDemoRelease run: ./gradlew :app:assembleDemoRelease

1
.gitignore vendored

@ -13,6 +13,7 @@ bin/
gen/ gen/
out/ out/
build/ build/
generated/
# Local configuration file (sdk path, etc) # Local configuration file (sdk path, etc)
local.properties local.properties

@ -79,7 +79,7 @@ androidx.lifecycle:lifecycle-viewmodel-ktx:2.8.3
androidx.lifecycle:lifecycle-viewmodel-savedstate:2.8.3 androidx.lifecycle:lifecycle-viewmodel-savedstate:2.8.3
androidx.lifecycle:lifecycle-viewmodel:2.8.3 androidx.lifecycle:lifecycle-viewmodel:2.8.3
androidx.loader:loader:1.0.0 androidx.loader:loader:1.0.0
androidx.metrics:metrics-performance:1.0.0-alpha04 androidx.metrics:metrics-performance:1.0.0-beta01
androidx.profileinstaller:profileinstaller:1.3.1 androidx.profileinstaller:profileinstaller:1.3.1
androidx.savedstate:savedstate-ktx:1.2.1 androidx.savedstate:savedstate-ktx:1.2.1
androidx.savedstate:savedstate:1.2.1 androidx.savedstate:savedstate:1.2.1

@ -138,6 +138,9 @@ baselineProfile {
// Don't build on every iteration of a full assemble. // Don't build on every iteration of a full assemble.
// Instead enable generation directly for the release build variant. // Instead enable generation directly for the release build variant.
automaticGenerationDuringBuild = false automaticGenerationDuringBuild = false
// Make use of Dex Layout Optimizations via Startup Profiles
dexLayoutOptimization = true
} }
dependencyGuard { dependencyGuard {

@ -105,7 +105,7 @@ androidx.lifecycle:lifecycle-viewmodel-savedstate:2.8.3
androidx.lifecycle:lifecycle-viewmodel:2.8.3 androidx.lifecycle:lifecycle-viewmodel:2.8.3
androidx.loader:loader:1.0.0 androidx.loader:loader:1.0.0
androidx.localbroadcastmanager:localbroadcastmanager:1.0.0 androidx.localbroadcastmanager:localbroadcastmanager:1.0.0
androidx.metrics:metrics-performance:1.0.0-alpha04 androidx.metrics:metrics-performance:1.0.0-beta01
androidx.navigation:navigation-common-ktx:2.8.0 androidx.navigation:navigation-common-ktx:2.8.0
androidx.navigation:navigation-common:2.8.0 androidx.navigation:navigation-common:2.8.0
androidx.navigation:navigation-compose:2.8.0 androidx.navigation:navigation-compose:2.8.0

File diff suppressed because it is too large Load Diff

@ -59,6 +59,7 @@ android {
baselineProfile { baselineProfile {
// This specifies the managed devices to use that you run the tests on. // This specifies the managed devices to use that you run the tests on.
managedDevices.clear()
managedDevices += "pixel6Api33" managedDevices += "pixel6Api33"
// Don't use a connected device but rely on a GMD for consistency between local and CI builds. // Don't use a connected device but rely on a GMD for consistency between local and CI builds.

@ -0,0 +1,50 @@
/*
* Copyright 2024 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.google.samples.apps.nowinandroid
import androidx.benchmark.macro.ExperimentalMetricApi
import androidx.benchmark.macro.StartupTimingMetric
import androidx.benchmark.macro.TraceSectionMetric
/**
* Custom Metrics to measure baseline profile effectiveness.
*/
class BaselineProfileMetrics {
companion object {
/**
* A [TraceSectionMetric] that tracks the time spent in JIT compilation.
*
* This number should go down when a baseline profile is applied properly.
*/
@OptIn(ExperimentalMetricApi::class)
val jitCompilationMetric = TraceSectionMetric("JIT Compiling %", label = "JIT compilation")
/**
* A [TraceSectionMetric] that tracks the time spent in class initialization.
*
* This number should go down when a baseline profile is applied properly.
*/
@OptIn(ExperimentalMetricApi::class)
val classInitMetric = TraceSectionMetric("L%/%;", label = "ClassInit")
/**
* Metrics relevant to startup and baseline profile effectiveness measurement.
*/
@OptIn(ExperimentalMetricApi::class)
val allMetrics = listOf(StartupTimingMetric(), jitCompilationMetric, classInitMetric)
}
}

@ -20,9 +20,9 @@ import androidx.benchmark.macro.BaselineProfileMode.Disable
import androidx.benchmark.macro.BaselineProfileMode.Require import androidx.benchmark.macro.BaselineProfileMode.Require
import androidx.benchmark.macro.CompilationMode import androidx.benchmark.macro.CompilationMode
import androidx.benchmark.macro.StartupMode.COLD import androidx.benchmark.macro.StartupMode.COLD
import androidx.benchmark.macro.StartupTimingMetric
import androidx.benchmark.macro.junit4.MacrobenchmarkRule import androidx.benchmark.macro.junit4.MacrobenchmarkRule
import androidx.test.internal.runner.junit4.AndroidJUnit4ClassRunner import androidx.test.internal.runner.junit4.AndroidJUnit4ClassRunner
import com.google.samples.apps.nowinandroid.BaselineProfileMetrics
import com.google.samples.apps.nowinandroid.PACKAGE_NAME import com.google.samples.apps.nowinandroid.PACKAGE_NAME
import com.google.samples.apps.nowinandroid.allowNotifications import com.google.samples.apps.nowinandroid.allowNotifications
import com.google.samples.apps.nowinandroid.foryou.forYouWaitForContent import com.google.samples.apps.nowinandroid.foryou.forYouWaitForContent
@ -58,7 +58,7 @@ class StartupBenchmark {
private fun startup(compilationMode: CompilationMode) = benchmarkRule.measureRepeated( private fun startup(compilationMode: CompilationMode) = benchmarkRule.measureRepeated(
packageName = PACKAGE_NAME, packageName = PACKAGE_NAME,
metrics = listOf(StartupTimingMetric()), metrics = BaselineProfileMetrics.allMetrics,
compilationMode = compilationMode, compilationMode = compilationMode,
// More iterations result in higher statistical significance. // More iterations result in higher statistical significance.
iterations = 20, iterations = 20,

@ -22,7 +22,7 @@ org.gradle.configureondemand=false
org.gradle.caching=true org.gradle.caching=true
# Enable configuration caching between builds. # Enable configuration caching between builds.
org.gradle.configuration-cache=true org.gradle.configuration-cache=false
# This option is set because of https://github.com/google/play-services-plugins/issues/246 # This option is set because of https://github.com/google/play-services-plugins/issues/246
# to generate the Configuration Cache regardless of incompatible tasks. # to generate the Configuration Cache regardless of incompatible tasks.
# See https://github.com/android/nowinandroid/issues/1022 before using it. # See https://github.com/android/nowinandroid/issues/1022 before using it.

@ -15,8 +15,8 @@ androidxDataStore = "1.0.0"
androidxEspresso = "3.5.1" androidxEspresso = "3.5.1"
androidxHiltNavigationCompose = "1.2.0" androidxHiltNavigationCompose = "1.2.0"
androidxLifecycle = "2.8.3" androidxLifecycle = "2.8.3"
androidxMacroBenchmark = "1.2.4" androidxMacroBenchmark = "1.3.0"
androidxMetrics = "1.0.0-alpha04" androidxMetrics = "1.0.0-beta01"
androidxNavigation = "2.8.0" androidxNavigation = "2.8.0"
androidxProfileinstaller = "1.3.1" androidxProfileinstaller = "1.3.1"
androidxTestCore = "1.5.0" androidxTestCore = "1.5.0"

Loading…
Cancel
Save