DEV Community

myougaTheAxo
myougaTheAxo

Posted on

Macrobenchmark Complete Guide — Startup Time/Scroll/Baseline Profile Generation

What You'll Learn

Macrobenchmark (app startup time measurement, scroll performance, automatic Baseline Profile generation, CI measurement) explained.


Setup

// benchmark/build.gradle.kts
plugins {
    id("com.android.test")
    id("org.jetbrains.kotlin.android")
}
android {
    namespace = "com.example.benchmark"
    compileSdk = 35
    defaultConfig {
        minSdk = 28
        testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
    }
    targetProjectPath = ":app"
    experimentalProperties["android.experimental.self-instrumenting"] = true
}
dependencies {
    implementation("androidx.benchmark:benchmark-macro-junit4:1.3.3")
}
Enter fullscreen mode Exit fullscreen mode

Startup Time Benchmark

@RunWith(AndroidJUnit4::class)
class StartupBenchmark {
    @get:Rule
    val benchmarkRule = MacrobenchmarkRule()

    @Test
    fun startupCold() = benchmarkRule.measureRepeated(
        packageName = "com.example.app",
        metrics = listOf(StartupTimingMetric()),
        iterations = 5,
        startupMode = StartupMode.COLD
    ) {
        pressHome()
        startActivityAndWait()
    }

    @Test
    fun startupWarm() = benchmarkRule.measureRepeated(
        packageName = "com.example.app",
        metrics = listOf(StartupTimingMetric()),
        iterations = 5,
        startupMode = StartupMode.WARM
    ) {
        pressHome()
        startActivityAndWait()
    }
}
Enter fullscreen mode Exit fullscreen mode

Scroll Benchmark

@RunWith(AndroidJUnit4::class)
class ScrollBenchmark {
    @get:Rule
    val benchmarkRule = MacrobenchmarkRule()

    @Test
    fun scrollList() = benchmarkRule.measureRepeated(
        packageName = "com.example.app",
        metrics = listOf(FrameTimingMetric()),
        iterations = 5,
        startupMode = StartupMode.COLD
    ) {
        startActivityAndWait()

        val list = device.findObject(By.res("item_list"))
        list.setGestureMargin(device.displayWidth / 5)

        repeat(3) {
            list.fling(Direction.DOWN)
            device.waitForIdle()
        }
    }
}
Enter fullscreen mode Exit fullscreen mode

Baseline Profile Generation

@RunWith(AndroidJUnit4::class)
class BaselineProfileGenerator {
    @get:Rule
    val rule = BaselineProfileRule()

    @Test
    fun generateBaselineProfile() = rule.collect(
        packageName = "com.example.app"
    ) {
        // Startup
        pressHome()
        startActivityAndWait()

        // Main user flow
        device.findObject(By.text("Home")).click()
        device.waitForIdle()

        // List scroll
        val list = device.findObject(By.res("item_list"))
        list?.fling(Direction.DOWN)
        device.waitForIdle()

        // Detail screen
        device.findObject(By.res("list_item"))?.click()
        device.waitForIdle()

        // Settings
        device.pressBack()
        device.findObject(By.text("Settings")).click()
        device.waitForIdle()
    }
}
Enter fullscreen mode Exit fullscreen mode

CI Integration

# .github/workflows/benchmark.yml
name: Benchmark
on:
  pull_request:
    paths: ['app/**']
jobs:
  benchmark:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-java@v4
        with:
          java-version: '17'
          distribution: 'temurin'
      - uses: reactivecircus/android-emulator-runner@v2
        with:
          api-level: 34
          arch: x86_64
          script: ./gradlew :benchmark:connectedCheck
      - uses: actions/upload-artifact@v4
        with:
          name: benchmark-results
          path: benchmark/build/outputs/connected_android_test_additional_output/
Enter fullscreen mode Exit fullscreen mode

Summary

Metric Measures
StartupTimingMetric Startup time
FrameTimingMetric Frame timing
TraceSectionMetric Custom section
BaselineProfileRule Profile generation
  • MacrobenchmarkRule for device benchmark
  • Cold/Warm/Hot startup measurement
  • FrameTimingMetric detects jank
  • BaselineProfileRule auto-generates profile

Ready-Made Android App Templates

8 production-ready Android app templates with Jetpack Compose, MVVM, Hilt, and Material 3.

Browse templatesGumroad

Top comments (0)