### Setup Environment Variables Source: https://github.com/android/performance-samples.git/blob/main/MacrobenchmarkSample/functions/README.md Example of setting environment variables for package name and device configurations. ```bash # Example: Setup Environment Variables. package_name="com.example.macrobenchmark.target" device_configurations='["flame-30-en-portrait"]' ``` -------------------------------- ### Macrobenchmark Startup Timing Source: https://context7.com/android/performance-samples.git/llms.txt Measures application startup performance using `MacrobenchmarkRule.measureRepeated`. This example focuses on capturing `StartupTimingMetric`. ```kotlin // MacrobenchmarkSample — SampleStartupBenchmark.kt @LargeTest @RunWith(AndroidJUnit4::class) class SampleStartupBenchmark { @get:Rule val benchmarkRule = MacrobenchmarkRule() @Test fun startup() = benchmarkRule.measureRepeated( packageName = "com.example.macrobenchmark.target", metrics = listOf(StartupTimingMetric()), iterations = 5, ) { uiAutomator { startApp("com.example.macrobenchmark.target") } } } // Output example: // SampleStartupBenchmark_startup // timeToInitialDisplayMs P50 312.4, P90 340.1, P99 390.2 ``` -------------------------------- ### GitHub Workflow: Checkout and Setup Source: https://github.com/android/performance-samples.git/blob/main/MacrobenchmarkSample/ftl/README.md These steps in the GitHub workflow are responsible for setting up the build environment. It includes checking out the repository code, setting up the Java Development Kit (JDK) version 11, and preparing the Gradle environment. ```yaml - name: Checkout uses: actions/checkout@v2 with: fetch-depth: 1 - name: Setup JDK id: setup-java uses: actions/setup-java@v1 with: java-version: "11" - name: Build Macrobenchmark Sample uses: eskatos/gradle-command-action@v1 env: JAVA_HOME: ${{ steps.setup-java.outputs.path }} with: arguments: build build-root-directory: ${{ github.workspace }}/... gradle-executable: ${{ github.workspace }}/.../gradlew wrapper-directory: ${{ github.workspace }}/.../gradle/wrapper ``` -------------------------------- ### Benchmark Non-Exported Activities Source: https://context7.com/android/performance-samples.git/llms.txt Benchmark non-exported activities by navigating to them from the default launch activity within the `setupBlock`. This example demonstrates scrolling a RecyclerView within a non-exported activity. ```kotlin // MacrobenchmarkSample — NonExportedActivityBenchmark.kt @LargeTest @RunWith(AndroidJUnit4::class) class NonExportedActivityBenchmark { @get:Rule val benchmarkRule = MacrobenchmarkRule() @Test fun nonExportedActivityScrollList() { benchmarkRule.measureRepeated( packageName = TARGET_PACKAGE, metrics = listOf(FrameTimingMetric()), compilationMode = CompilationMode.None(), startupMode = StartupMode.WARM, iterations = DEFAULT_ITERATIONS, setupBlock = { uiAutomator { startApp(TARGET_PACKAGE) // launch exported entry point onElement { textAsString() == "RecyclerView" }.click() // navigate in-app waitForStableInActiveWindow() } } ) { uiAutomator { onElement { className == "androidx.recyclerview.widget.RecyclerView" }.run { repeat(3) { fling(Direction.DOWN) } } } } } } ``` -------------------------------- ### Example Baseline Profile Generation (Kotlin) Source: https://github.com/android/performance-samples.git/blob/main/MacrobenchmarkSample/README.md This Kotlin code demonstrates how to generate baseline profiles. It defines generators for different user journeys and app startup, utilizing the src/main/baselineProfiles folder for storing multiple profile files. ```kotlin package com.example.macrobenchmark.baselineprofile import androidx.benchmark.macro.MacrobenchmarkScope import androidx.benchmark.macro.startup.StartupMode import androidx.benchmark.macro.startup.StartupTimingMetric import androidx.benchmark.macro.junit4.Macrobenchmark import androidx.test.ext.junit.runners.AndroidJUnit4 import org.junit.Test @RunWith(AndroidJUnit4::class) class StartupProfiles { @get:Rule val macrobenchmarkRule = MacrobenchmarkRule() @Test fun startupWithMemory() = macrobenchmarkRule.measureRepeated( packageName = "com.example.macrobenchmark", metrics = listOf(StartupTimingMetric()), // More parameters here ... ) { // Press fully drawn pressHome() // Given a warm start interaction startActivityAndWait(StartupMode.COLD) } } ``` -------------------------------- ### Exclude Setup Code from Timing in Microbenchmark Source: https://context7.com/android/performance-samples.git/llms.txt Use runWithTimingDisabled within measureRepeated for per-iteration setup that should not be counted towards the benchmark result. This is crucial when the code under test needs fresh input each iteration. ```kotlin import androidx.benchmark.junit4.BenchmarkRule import androidx.test.ext.junit.runners.AndroidJUnit4 import org.junit.Rule import org.junit.Test import org.junit.runner.RunWith import kotlin.random.Random @RunWith(AndroidJUnit4::class) class SortingBenchmarks { @get:Rule val benchmarkRule = BenchmarkRule() private val random = Random(0) // fixed seed → reproducible data private val unsorted = IntArray(10_000) { random.nextInt() } @Test fun benchmark_quickSort() { var listToSort = intArrayOf() benchmarkRule.measureRepeated { // copy excluded from timing; sort is measured listToSort = runWithTimingDisabled { unsorted.copyOf() } SortingAlgorithms.quickSort(listToSort) } assertTrue(listToSort.isSorted) // assert once, outside benchmark loop } @Test fun benchmark_bubbleSort() { var listToSort = intArrayOf() benchmarkRule.measureRepeated { listToSort = runWithTimingDisabled { unsorted.copyOf() } SortingAlgorithms.bubbleSort(listToSort) } assertTrue(listToSort.isSorted) } } ``` -------------------------------- ### Profile a Login Flow with BaselineProfileRule Source: https://context7.com/android/performance-samples.git/llms.txt Generate a focused baseline profile for a single user journey, such as login, to keep profiles granular and maintainable. This example uses uiAutomator to simulate login actions. ```kotlin // MacrobenchmarkSample — LoginBaselineProfileGenerator.kt @RunWith(AndroidJUnit4ClassRunner::class) class LoginBaselineProfileGenerator { @get:Rule val rule = BaselineProfileRule() @Test fun generate() { rule.collect(packageName = TARGET_PACKAGE, maxIterations = 15, stableIterations = 3) { uiAutomator { startIntent(Intent("$packageName.LOGIN_ACTIVITY")) onElement { isEditable and !isPassword }.text = "user" onElement { isEditable && isPassword }.text = "password" onElement { textAsString() == "Login" }.click() } } } } ``` -------------------------------- ### Example Frame Timing Benchmark (Kotlin) Source: https://github.com/android/performance-samples.git/blob/main/MacrobenchmarkSample/README.md This Kotlin code defines a benchmark for measuring frame timing metrics. It targets the scrollable Compose list and captures frame duration and overrun statistics. ```kotlin package com.example.macrobenchmark.startup import androidx.benchmark.macro.FrameTimingMetric import androidx.benchmark.macro.MacrobenchmarkScope import androidx.benchmark.macro.junit4.MacrobenchmarkRule import androidx.benchmark.macro.startup.StartupTimingMetric import androidx.test.ext.junit.runners.AndroidJUnit4 import org.junit.Rule import org.junit.Test import org.junit.runner.RunWith @RunWith(AndroidJUnit4::class) class FrameTimingBenchmark { @get:Rule val macrobenchmarkRule = MacrobenchmarkRule() @Test fun scrollComposeList() = macrobenchmarkRule.measureRepeated( packageName = "com.example.macrobenchmark", metrics = listOf( FrameTimingMetric(), // Add other metrics if needed ) ) { // Perform scroll action on the list // ... } } ``` -------------------------------- ### Initialize Project with gcloud Source: https://github.com/android/performance-samples.git/blob/main/MacrobenchmarkSample/functions/README.md Sets the active Google Cloud project for subsequent gcloud commands. ```bash gcloud config set project macrobenchmark-samples-6670d ``` -------------------------------- ### Measure Cold/Warm/Hot App Startup with Different Compilation Modes Source: https://context7.com/android/performance-samples.git/llms.txt Abstract base class for testing startup performance across various compilation modes and startup types. Requires defining TARGET_PACKAGE and DEFAULT_ITERATIONS. ```kotlin abstract class AbstractStartupBenchmark(private val startupMode: StartupMode) { @get:Rule val benchmarkRule = MacrobenchmarkRule() @Test fun startupNoCompilation() = startup(CompilationMode.None()) @Test fun startupPartialCompilation() = startup( CompilationMode.Partial( baselineProfileMode = BaselineProfileMode.Disable, warmupIterations = 3 ) ) @Test fun startupPartialWithBaselineProfiles() = startup(CompilationMode.Partial(baselineProfileMode = BaselineProfileMode.Require)) @Test fun startupFullCompilation() = startup(CompilationMode.Full()) private fun startup(compilationMode: CompilationMode) = benchmarkRule.measureRepeated( packageName = TARGET_PACKAGE, metrics = listOf(StartupTimingMetric()), compilationMode = compilationMode, iterations = DEFAULT_ITERATIONS, startupMode = startupMode, ) { uiAutomator { startApp(TARGET_PACKAGE) } } } @RunWith(AndroidJUnit4ClassRunner::class) class ColdStartupBenchmark : AbstractStartupBenchmark(StartupMode.COLD) @RunWith(AndroidJUnit4ClassRunner::class) class WarmStartupBenchmark : AbstractStartupBenchmark(StartupMode.WARM) ``` -------------------------------- ### Running Gradle Benchmarks from Command Line Source: https://context7.com/android/performance-samples.git/llms.txt Commands to execute different types of benchmarks and related tasks using Gradle. Includes commands for microbenchmarks, macrobenchmarks, baseline profile generation, and CPU clock locking. ```bash # Microbenchmark ./gradlew benchmark:connectedCheck # Macrobenchmark ./gradlew macrobenchmark:cC # Generate Baseline Profiles (macrobenchmark module) ./gradlew generateBaselineProfile # Lock CPU clocks (rooted device only — microbenchmark) ./gradlew lockClocks ./gradlew unlockClocks ``` -------------------------------- ### GitHub Workflow: Build and Run Macrobenchmarks Source: https://github.com/android/performance-samples.git/blob/main/MacrobenchmarkSample/ftl/README.md This YAML snippet defines a GitHub Actions workflow for building and running Macrobenchmark tests. It triggers on push events to the 'macrobenchmark' branch or manual dispatch. The workflow checks out code, sets up Java, builds the Macrobenchmark sample using Gradle, configures Google Cloud SDK, and runs the benchmarks on Firebase Test Lab. ```yaml name: Build and Run Macrobenchmarkson: push: branches: [ macrobenchmark ] workflow_dispatch: jobs: build: runs-on: ubuntu-latest steps: - name: Checkout uses: actions/checkout@v2 with: fetch-depth: 1 - name: Setup JDK id: setup-java uses: actions/setup-java@v1 with: java-version: "11" - name: Build Macrobenchmark Sample uses: eskatos/gradle-command-action@v1 env: JAVA_HOME: ${{ steps.setup-java.outputs.path }} with: arguments: build build-root-directory: ${{ github.workspace }}/... gradle-executable: ${{ github.workspace }}/.../gradlew wrapper-directory: ${{ github.workspace }}/.../gradle/wrapper - name: Set up Cloud SDK uses: google-github-actions/setup-gcloud@master with: project_id: ${{ secrets.GCP_PROJECT_ID }} service_account_key: ${{ secrets.GCP_SA_KEY }} export_default_credentials: true - name: Run Macrobenchmarks run: | gcloud firebase test android run \ --type instrumentation \ --app ${{ github.workspace }}/MacrobenchmarkSample/app/build/outputs/apk/benchmark/app-benchmark.apk \ --test ${{ github.workspace }}/MacrobenchmarkSample/macrobenchmark/build/outputs/apk/benchmark/macrobenchmark-benchmark.apk \ --device model=redfin,version=30,locale=en,orientation=portrait \ --directories-to-pull /sdcard/Download \ --results-bucket gs://macrobenchmark-results \ --environment-variables additionalTestOutputDir=/sdcard/Download,no-isolated-storage=true \ --timeout 20m ``` -------------------------------- ### Measure Frame Rendering Smoothness Source: https://context7.com/android/performance-samples.git/llms.txt Captures per-frame CPU timing and frameOverrunMs during UI interaction. Use setupBlock to navigate to the target screen before the timed block begins. Requires RecyclerView activity. ```kotlin @LargeTest @RunWith(AndroidJUnit4::class) class FrameTimingBenchmark { @get:Rule val benchmarkRule = MacrobenchmarkRule() @Test fun scrollList() { benchmarkRule.measureRepeated( packageName = TARGET_PACKAGE, metrics = listOf(FrameTimingMetric()), compilationMode = CompilationMode.None(), startupMode = StartupMode.WARM, iterations = DEFAULT_ITERATIONS, setupBlock = { uiAutomator { startIntent(Intent("$packageName.RECYCLER_VIEW_ACTIVITY")) } } ) { uiAutomator { val recycler = onElement { className == "androidx.recyclerview.widget.RecyclerView" } repeat(3) { recycler.fling(Direction.DOWN) } } } } } // Output: // FrameTimingBenchmark_scrollList // frameDurationCpuMs P50 4.8, P90 6.8, P95 8.9, P99 15.3 // frameOverrunMs P50 -9.2, P90 -1.9, P95 266.9, P99 310.9 ``` -------------------------------- ### GitHub Workflow: Running Macrobenchmarks with Gcloud Source: https://github.com/android/performance-samples.git/blob/main/MacrobenchmarkSample/ftl/README.md This step executes the Macrobenchmark tests using the Google Cloud SDK's 'gcloud' command. It specifies the application and test APKs, device configuration (model, Android version, locale, orientation), directories to pull results from, the GCS bucket for results, environment variables, and a timeout. ```bash gcloud firebase test android run \ --type instrumentation \ --app ${{ github.workspace }}/MacrobenchmarkSample/app/build/outputs/apk/benchmark/app-benchmark.apk \ --test ${{ github.workspace }}/MacrobenchmarkSample/macrobenchmark/build/outputs/apk/benchmark/macrobenchmark-benchmark.apk \ --device model=redfin,version=30,locale=en,orientation=portrait \ --directories-to-pull /sdcard/Download \ --results-bucket gs://macrobenchmark-results \ --environment-variables additionalTestOutputDir=/sdcard/Download,no-isolated-storage=true \ --timeout 20m ``` -------------------------------- ### Set up gcloud CLI for Firebase Test Lab Source: https://github.com/android/performance-samples.git/blob/main/MacrobenchmarkSample/ftl/README.md Configures the Google Cloud SDK within a GitHub Actions workflow, authenticating with provided service account credentials. This is a prerequisite for interacting with Google Cloud services like Firebase Test Lab. ```yaml - name: Set up Cloud SDK uses: google-github-actions/setup-gcloud@master with: project_id: ${{ secrets.GCP_PROJECT_ID }} service_account_key: ${{ secrets.GCP_SA_KEY }} export_default_credentials: true ``` -------------------------------- ### Run Macrobenchmark from Terminal Source: https://github.com/android/performance-samples.git/blob/main/MacrobenchmarkSample/README.md This command executes the Macrobenchmark task from the terminal using Gradle. It's a convenient way to run benchmarks without Android Studio. ```bash ./gradlew macrobenchmark:cC ``` -------------------------------- ### Initialize and Deploy Google Cloud Function Source: https://github.com/android/performance-samples.git/blob/main/MacrobenchmarkSample/ftl/README.md Commands to set up and deploy a Google Cloud Function for processing Firebase Test Lab results. It includes logging into gcloud and Firebase CLIs, setting the default project, and deploying the function. Ensure the Firebase project ID is updated in `.firebaserc`. ```bash # Initialize gcloud CLI with a GCP admin credentials/ # Will launch a browser and complete an OAuth flow. gcloud auth login # Login to firebase using the CLI. # Will launch a browser and complete an OAuth flow. firebase login # Choose a default GCP project gcloud config set project # Will deploy the cloud functions for the selected GCP project. firebase deploy --only functions ``` -------------------------------- ### Version Catalog for MacrobenchmarkSample Source: https://context7.com/android/performance-samples.git/llms.txt Defines library versions for the MacrobenchmarkSample project using a TOML file. Includes versions for Android Gradle Plugin, benchmark, Kotlin, and Compose BOM. ```toml # MacrobenchmarkSample/gradle/libs.versions.toml [versions] agp = "8.13.1" benchmark = "1.4.1" # androidx.benchmark:benchmark-macro-junit4 kotlin = "2.2.21" composeBom = "2025.11.00" [libraries] benchmark-junit = { group = "androidx.benchmark", name = "benchmark-macro-junit4", version.ref = "benchmark" } ui-automator = { group = "androidx.test.uiautomator", name = "uiautomator", version.ref = "uiAutomator" } profileinstaller = { group = "androidx.profileinstaller", name = "profileinstaller", version.ref = "profileInstaller" } [plugins] baselineprofile = { id = "androidx.baselineprofile", version.ref = "benchmark" } ``` -------------------------------- ### Enable Composition Tracing in Macrobenchmark Source: https://github.com/android/performance-samples.git/blob/main/MacrobenchmarkSample/README.md This snippet shows how to enable composition tracing when running a macrobenchmark. It requires setting an instrumentation argument to true, which allows detailed analysis of UI composition performance. ```properties androidx.benchmark.perfettoSdkTracing.enable=true ``` -------------------------------- ### Measure Time-to-Fully-Drawn Startup Source: https://context7.com/android/performance-samples.git/llms.txt Measures the time it takes for an app to become fully drawn, using reportFullyDrawn() signal. Requires a specific activity to be launched and an element to be visible. ```kotlin @LargeTest @RunWith(AndroidJUnit4::class) class FullyDrawnStartupBenchmark { @get:Rule val benchmarkRule = MacrobenchmarkRule() @Test fun startup() = benchmarkRule.measureRepeated( packageName = TARGET_PACKAGE, metrics = listOf(StartupTimingMetric()), startupMode = StartupMode.COLD, iterations = DEFAULT_ITERATIONS, ) { uiAutomator { startIntent(Intent("$TARGET_PACKAGE.FULLY_DRAWN_STARTUP_ACTIVITY")) // Block until the "Fully Drawn" element is visible — matches reportFullyDrawn() onElement { textAsString() == "Fully Drawn" && isVisibleToUser } } } } ``` -------------------------------- ### Microbenchmark Bitmap Pixel Access (Single vs. Bulk JNI) Source: https://context7.com/android/performance-samples.git/llms.txt Benchmark comparing single pixel access (many JNI calls) versus bulk pixel access (one JNI call) for a Bitmap. Use BenchmarkRule to measure performance differences. ```kotlin import android.graphics.Bitmap import android.graphics.BitmapFactory import androidx.benchmark.junit4.BenchmarkRule import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.LargeTest import androidx.test.platform.app.InstrumentationRegistry import org.junit.Rule import org.junit.Test import org.junit.runner.RunWith @LargeTest @RunWith(AndroidJUnit4::class) class BitmapBenchmark { @get:Rule val benchmarkRule = BenchmarkRule() private val context = InstrumentationRegistry.getInstrumentation().targetContext private val bitmap: Bitmap = context.assets.open("images/jetpack.png").use { BitmapFactory.decodeStream(it) } /** Many cheap JNI calls — one per pixel */ @Test fun bitmapGetPixelBenchmark() { val pixels = IntArray(100) { it } benchmarkRule.measureRepeated { pixels.map { bitmap.getPixel(it, 0) } } } /** Single expensive JNI call — fetches all 100 pixels at once */ @Test fun bitmapGetPixelsBenchmark() { val pixels = IntArray(100) { it } benchmarkRule.measureRepeated { bitmap.getPixels(pixels, 0, 100, 0, 0, 100, 1) } } } // bitmapGetPixelsBenchmark is typically >10× faster than bitmapGetPixelBenchmark ``` -------------------------------- ### Generate Baseline Profiles with BaselineProfileRule Source: https://context7.com/android/performance-samples.git/llms.txt Use BaselineProfileRule to run representative user journeys, collect ART profiles, and write them to src/main/baselineProfiles/. This helps pre-compile critical code paths for reduced startup time and jank. ```kotlin // MacrobenchmarkSample — SampleBaselineProfileGenerator.kt @RunWith(AndroidJUnit4ClassRunner::class) class SampleBaselineProfileGenerator { @get:Rule val rule = BaselineProfileRule() @Test fun generate() { rule.collect( packageName = TARGET_PACKAGE, maxIterations = 15, stableIterations = 3 ) { uiAutomator { startApp(TARGET_PACKAGE) listOf( "Login", "ListView", "Compose", "ScrollView", "Fully Drawn", "RecyclerView", "Nested RecyclerView", "Nested RecyclerView with Pools" ).forEach { onElement { textAsString() == it }.click() pressBack() } } } } } // Run via: ./gradlew macrobenchmark:generateBaselineProfile // Output written to: app/src/main/baselineProfiles/ ``` -------------------------------- ### Version Catalog for MicrobenchmarkSample Source: https://context7.com/android/performance-samples.git/llms.txt Defines the benchmark library version for the MicrobenchmarkSample project. ```toml # MicrobenchmarkSample/gradle/libs.versions.toml [versions] benchmark = "1.4.0" # androidx.benchmark:benchmark-junit4 [libraries] benchmark = { group = "androidx.benchmark", name = "benchmark-junit4", version.ref = "benchmark" } ``` -------------------------------- ### Configure Cloud Function Environment Variables Source: https://github.com/android/performance-samples.git/blob/main/MacrobenchmarkSample/ftl/README.md Illustrates setting environment variables for a Google Cloud Function named `completionHandler`. These variables, `package_name` and `device_configurations`, are crucial for the function to correctly process test results from Firebase Test Lab. ```bash # The Macrobenchmark target app package name # Example: package_name = "com.example.macrobenchmark" # The device configurations you are interested in tracking metrics for. # This should match the device that you are testing on in the GitHub workflow. # Example: device_configurations = ["redfin-30-en-portrait"] ``` -------------------------------- ### Create and Track JankStats for Per-Frame Monitoring Source: https://context7.com/android/performance-samples.git/llms.txt Create a JankStats instance tied to a Window to monitor jank on a per-frame basis. Enable/disable tracking in onResume/onPause to collect data only when the window is interactive. The listener fires after every frame with timing data and a jank flag. ```kotlin // JankStatsSample — JankLoggingActivity.kt class JankLoggingActivity : AppCompatActivity() { private lateinit var jankStats: JankStats // Fires on every rendered frame private val jankFrameListener = JankStats.OnFrameListener { frameData -> // frameData.isJank == true when the frame exceeded the jank threshold Log.v("JankStatsSample", frameData.toString()) // Real usage: buffer and upload to analytics backend } override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(binding.root) val metricsStateHolder = PerformanceMetricsState.getHolderForHierarchy(binding.root) jankStats = JankStats.createAndTrack(window, jankFrameListener) metricsStateHolder.state?.putState("Activity", javaClass.simpleName) } override fun onResume() { super.onResume(); jankStats.isTrackingEnabled = true } override fun onPause() { super.onPause(); jankStats.isTrackingEnabled = false } } ``` -------------------------------- ### Measure Touch-to-Click Latency with ClickLatencyBenchmark Source: https://context7.com/android/performance-samples.git/llms.txt Measure the time between touch-up and the click listener firing using `TraceSectionMetric("ClickTrace")`. This benchmark works across various UI components like RecyclerView, ListView, ScrollView, and Compose LazyColumn. ```kotlin // MacrobenchmarkSample — ClickLatencyBenchmark.kt @LargeTest @RunWith(AndroidJUnit4::class) @OptIn(ExperimentalMetricApi::class) class ClickLatencyBenchmark { @get:Rule val benchmarkRule = MacrobenchmarkRule() @Test fun recyclerViewClick() { var firstStart = true benchmarkRule.measureRepeated( packageName = TARGET_PACKAGE, metrics = listOf(TraceSectionMetric("ClickTrace")), compilationMode = CompilationMode.Full(), startupMode = null, iterations = DEFAULT_ITERATIONS, setupBlock = { if (firstStart) { uiAutomator { startIntent(Intent("$packageName.RECYCLER_VIEW_ACTIVITY")) } firstStart = false } } ) { uiAutomator { onElement { textAsString() == "Item 0" }.click() onElement { textAsString() == "Item clicked" && isVisibleToUser } pressBack() } } } } ``` -------------------------------- ### Deploy Firebase Functions Source: https://github.com/android/performance-samples.git/blob/main/MacrobenchmarkSample/functions/README.md Deploys only the functions to your Firebase project. ```bash firebase deploy --only functions ``` -------------------------------- ### Microbenchmark with BenchmarkRule Source: https://context7.com/android/performance-samples.git/llms.txt Use BenchmarkRule as a JUnit rule for microbenchmarks. It handles warmup, clock stabilization, and result reporting. Call measureRepeated with the code under test inside the lambda. ```kotlin import androidx.benchmark.junit4.BenchmarkRule import androidx.test.ext.junit.runners.AndroidJUnit4 import org.junit.Rule import org.junit.Test import org.junit.runner.RunWith @RunWith(AndroidJUnit4::class) class SampleBenchmark { @get:Rule val benchmarkRule = BenchmarkRule() @Test fun benchmarkSomeWork() { benchmarkRule.measureRepeated { doSomeWork() // the function under measurement } } } // Expected output (Android Studio / logcat): // SampleBenchmark_benchmarkSomeWork // median 100.1 ms, min 100.0 ms, max 101.3 ms ``` -------------------------------- ### Firebase Project Configuration Source: https://github.com/android/performance-samples.git/blob/main/MacrobenchmarkSample/ftl/README.md Configuration file for the Firebase CLI, specifying the default Google Cloud project ID. This file is essential for the `firebase deploy` command to target the correct project. ```json { "projects": { "default": "" } } ``` -------------------------------- ### View Inflation Benchmark Source: https://context7.com/android/performance-samples.git/llms.txt Measures the cost of inflating Android views. This benchmark focuses solely on the inflation process itself. ```kotlin // MicrobenchmarkSample/microbenchmark/src/androidTest/java/com/example/benchmark/ViewInflateBenchmark.kt @RunWith(AndroidJUnit4::class) class ViewInflateBenchmark { @get:Rule val benchmarkRule = BenchmarkRule() @Test fun benchmarkViewInflate() { val context = InstrumentationRegistry.getInstrumentation().context val inflater = LayoutInflater.from(context) val root = FrameLayout(context) benchmarkRule.measureRepeated { val inflated = inflater.inflate(R.layout.item_card, root, false) } } } ``` -------------------------------- ### View Measure/Layout Benchmark Source: https://context7.com/android/performance-samples.git/llms.txt Compares `measure()` and `layout()` pass costs for ConstraintLayout vs. traditional hierarchies under different measure specs. Uses `runWithTimingDisabled` to re-inflate before each measurement to prevent view cache reuse. ```kotlin // MicrobenchmarkSample/microbenchmark/src/androidTest/java/com/example/benchmark/ViewMeasureLayoutBenchmark.kt @LargeTest @RunWith(AndroidJUnit4::class) @OrderWith(Alphanumeric::class) class ViewMeasureLayoutBenchmark { @get:Rule val benchmarkRule = BenchmarkRule() @Test fun constraintLayoutHierarchy_AT_MOST() = benchmarkMeasureLayout(R.layout.activity_constraintlayout, MeasureSpec.AT_MOST) @Test fun constraintLayoutHierarchy_EXACTLY() = benchmarkMeasureLayout(R.layout.activity_constraintlayout, MeasureSpec.EXACTLY) @Test fun traditionalViewHierarchy_AT_MOST() = benchmarkMeasureLayout(R.layout.activity_traditional, MeasureSpec.AT_MOST) @Test fun traditionalViewHierarchy_EXACTLY() = benchmarkMeasureLayout(R.layout.activity_traditional, MeasureSpec.EXACTLY) private fun benchmarkMeasureLayout(layoutRes: Int, mode: Int) { val context = InstrumentationRegistry.getInstrumentation().context val inflater = LayoutInflater.from(context) benchmarkRule.measureRepeated { val container = runWithTimingDisabled { inflater.inflate(layoutRes, null) } val widthSpec = MeasureSpec.makeMeasureSpec(1080, mode) val heightSpec = MeasureSpec.makeMeasureSpec(1920, mode) container.measure(widthSpec, heightSpec) container.layout(0, 0, container.measuredWidth, container.measuredHeight) } } } ``` -------------------------------- ### Run Android Macrobenchmarks with Firebase Test Lab Source: https://github.com/android/performance-samples.git/blob/main/MacrobenchmarkSample/ftl/README.md Executes Android instrumentation tests using Firebase Test Lab via the gcloud CLI. It specifies test APKs, target devices, output directories, a results bucket, environment variables for the Macrobenchmark Library, and a timeout. ```yaml - name: Run Macrobenchmarks run: | gcloud firebase test android run \ --type instrumentation \ --app ${{ github.workspace }}/.../benchmark/app-benchmark.apk \ --test ${{ github.workspace }}/.../macrobenchmark-benchmark.apk \ --device model=redfin,version=30,locale=en,orientation=portrait \ --directories-to-pull /sdcard/Download \ --results-bucket gs://macrobenchmark-results \ --environment-variables additionalTestOutputDir=/sdcard/Download,no-isolated-storage=true \ --timeout 20m ``` -------------------------------- ### Attach App Context to Frames with PerformanceMetricsState Source: https://context7.com/android/performance-samples.git/llms.txt Use PerformanceMetricsState.putState and removeState to attach key-value state strings to frames. This allows correlating janky frames with application state, such as the current screen or scroll progress. State is automatically included in JankStats.OnFrameListener callbacks. ```kotlin // JankStatsSample — JankLoggingActivity.kt (navigation state) val metricsStateHolder = PerformanceMetricsState.getHolderForHierarchy(binding.root) // Attach current destination to every frame for the lifetime of that navigation navController.addOnDestinationChangedListener { _, destination, arguments -> metricsStateHolder.state?.putState( "Navigation", "Args(${arguments.toString()}), $destination" ) } // metricsStateHolder.state?.removeState("Navigation") — call when state no longer applies ``` -------------------------------- ### Version Catalog for JankStatsSample Source: https://context7.com/android/performance-samples.git/llms.txt Specifies the version for the JankStats library in the JankStatsSample project. ```toml # JankStatsSample/gradle/libs.versions.toml [versions] jankstats = "1.0.0-beta02" # androidx.metrics:metrics-performance [libraries] jankstats = { group = "androidx.metrics", name = "metrics-performance", version.ref = "jankstats" } ``` -------------------------------- ### RecyclerView Scroll Benchmark Source: https://context7.com/android/performance-samples.git/llms.txt Measures the attach/detach/bind/layout cost per RecyclerView item. Requires `@UiThreadTest` to drive RecyclerView synchronously and forces the list height to 1px to reveal one item at a time. ```kotlin // MicrobenchmarkSample/microbenchmark/src/androidTest/java/com/example/benchmark/RecyclerViewBenchmark.kt @LargeTest @RunWith(AndroidJUnit4::class) class RecyclerViewBenchmark { @get:Rule val benchmarkRule = BenchmarkRule() @get:Rule val activityRule = ActivityScenarioRule(MainActivity::class.java) @Before fun setup() { activityRule.scenario.onActivity { // Force height = 1 px so exactly one item is visible at a time it.recyclerView.layoutParams = FrameLayout.LayoutParams(MATCH_PARENT, 1) it.adapter.submitList(null) it.adapter.submitList(LazyComputedList { buildRandomParagraph() }) } } @UiThreadTest @Test fun scroll() { activityRule.scenario.onActivity { val recyclerView = it.recyclerView benchmarkRule.measureRepeated { // Each call triggers: attach new item, detach old item, bind, layout recyclerView.scrollBy(0, recyclerView.getLastChild().height) } } } } ``` -------------------------------- ### Measure Custom Trace Sections with TraceSectionMetric Source: https://context7.com/android/performance-samples.git/llms.txt Use `TraceSectionMetric` to capture the total duration and occurrence count of named trace sections. Supports exact names and wildcard matching for Compose composition tracing. ```kotlin // MacrobenchmarkSample — FrameTimingBenchmark.kt (scrollComposeList) @OptIn(ExperimentalMetricApi::class) @Test fun scrollComposeList() { benchmarkRule.measureRepeated( packageName = TARGET_PACKAGE, metrics = listOf( FrameTimingMetric(), // Exact trace section name — counts calls and sums duration TraceSectionMetric("EntryRowCustomTrace", TraceSectionMetric.Mode.Sum), // SQL wildcard — matches composable trace sections from composition tracing TraceSectionMetric("%EntryRow (%", TraceSectionMetric.Mode.Sum), ), compilationMode = CompilationMode.None(), startupMode = StartupMode.WARM, iterations = DEFAULT_ITERATIONS, setupBlock = { uiAutomator { startIntent(Intent("$packageName.COMPOSE_ACTIVITY")) } } ) { uiAutomator { onElement { isScrollable }.fling(Direction.DOWN) } } } ``` -------------------------------- ### GitHub Workflow: Triggering Events Source: https://github.com/android/performance-samples.git/blob/main/MacrobenchmarkSample/ftl/README.md This YAML snippet defines the events that trigger the GitHub workflow. It's configured to run automatically when code is pushed to the 'macrobenchmark' branch or can be manually triggered using 'workflow_dispatch'. ```yaml name: Build and Run Macrobenchmarks on: push: branches: [ macrobenchmark ] workflow_dispatch: ``` -------------------------------- ### JankStatsAggregator for Batching Jank Reports Source: https://context7.com/android/performance-samples.git/llms.txt A utility class that accumulates janky-frame data and calls OnJankReportListener only when issueJankReport() is called or the internal buffer is exceeded. This reduces listener call volume in production telemetry. ```kotlin // JankStatsSample — JankStatsAggregator.kt / JankAggregatorActivity.kt // Listener fires on issueJankReport(), NOT per frame private val jankReportListener = JankStatsAggregator.OnJankReportListener { reason, totalFrames, jankFrameData -> Log.v( "JankStatsSample", "*** Jank Report ($reason), " + "totalFrames = $totalFrames, jankFrames = ${jankFrameData.size}" ) jankFrameData.forEach { frameData -> Log.v("JankStatsSample", frameData.toString()) } } class JankAggregatorActivity : AppCompatActivity() { private lateinit var jankStatsAggregator: JankStatsAggregator override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(binding.root) val metricsStateHolder = PerformanceMetricsState.getHolderForHierarchy(binding.root) jankStatsAggregator = JankStatsAggregator(window, jankReportListener) metricsStateHolder.state?.putState("Activity", javaClass.simpleName) } override fun onResume() { super.onResume() jankStatsAggregator.jankStats.isTrackingEnabled = true } override fun onPause() { super.onPause() // Flushes accumulated data with a labelled reason before disabling tracking jankStatsAggregator.issueJankReport("Activity paused") jankStatsAggregator.jankStats.isTrackingEnabled = false } } ``` -------------------------------- ### Remember JankStats State Holder in Compose Source: https://context7.com/android/performance-samples.git/llms.txt Retrieves and remembers the PerformanceMetricsState.Holder for the current view hierarchy in Jetpack Compose. Use within LaunchedEffect and snapshotFlow to report scroll state without triggering recomposition. ```kotlin @Composable fun rememberMetricsStateHolder(): PerformanceMetricsState.Holder { val view = LocalView.current return remember(view) { PerformanceMetricsState.getHolderForHierarchy(view) } } @Composable fun MessageList(onItemClick: () -> Unit) { val listState = rememberLazyListState() val metricsStateHolder = rememberMetricsStateHolder() // Report scroll state from a side effect — avoids spurious recompositions LaunchedEffect(metricsStateHolder, listState) { snapshotFlow { listState.isScrollInProgress }.collect { isScrolling -> if (isScrolling) { metricsStateHolder.state?.putState("LazyList", "Scrolling") } else { metricsStateHolder.state?.removeState("LazyList") } } } LazyColumn(state = listState) { items(100) { index -> MessageItem(index, onItemClick) } } } ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.