blob: 86d0536ef3591f4c2dd3d517fb2e2a24b079d6b9 [file] [log] [blame] [view]
# Benchmarking in AndroidX
[TOC]
<!-- Copied from macrobenchmark docs -->
<table>
<tr>
<td><strong>Macrobenchmark</strong> (new!)</td>
<td><strong>Benchmark</strong> (existing!)</td>
</tr>
<tr>
<td>Measure high-level entry points (Activity launch / Scrolling a list)</td>
<td>Measure individual functions</td>
</tr>
<tr>
<td>Out-of-process test of full app</td>
<td>In-process test of CPU work</td>
</tr>
<tr>
<td>Slow iteration speed (Often more than a minute)</td>
<td>Fast iteration speed (Often less than 10 seconds)</td>
</tr>
<tr>
<td>Results come with profiling traces</td>
<td>Optional stack sampling/method tracing</td>
</tr>
<tr>
<td>Min API 23</td>
<td>Min API 14</td>
</tr>
</table>
The
[public documentation](https://developer.android.com/studio/profile/macrobenchmark)
for macrobenchmark explains how to use the library. This page focuses on
specifics to writing library macrobenchmarks in the AndroidX repo. If you're
looking for measuring CPU perf of individual functions, see the guide for
MICRObenchmarks [here](/company/teams/androidx/benchmarking.md).
### Writing the benchmark
Benchmarks are just regular instrumentation tests! Just use the
[`MacrobenchmarkRule`](https://cs.android.com/androidx/platform/frameworks/support/+/androidx-main:benchmark/macro-junit4/src/main/java/androidx/benchmark/macro/junit4/MacrobenchmarkRule.kt)
provided by the library:
<section class="tabs">
#### Kotlin {.new-tab}
```kotlin
@get:Rule
val benchmarkRule = MacrobenchmarkRule()
@Test
fun startup() = benchmarkRule.measureRepeated(
packageName = "mypackage.myapp",
metrics = listOf(StartupTimingMetric()),
startupMode = StartupMode.COLD,
iterations = 5
) { // this = MacrobenchmarkScope
pressHome()
val intent = Intent()
intent.setPackage("mypackage.myapp")
intent.setAction("mypackage.myapp.myaction")
startActivityAndWait(intent)
}
```
#### Java {.new-tab}
```java
@Rule
public MacrobenchmarkRule mBenchmarkRule = MacrobenchmarkRule()
@Test
public void startup() {
mBenchmarkRule.measureRepeated(
"mypackage.myapp",
Collections.singletonList(new StartupTimingMetric()),
StartupMode.COLD,
/* iterations = */ 5,
scope -> {
scope.pressHome();
Intent intent = Intent();
intent.setPackage("mypackage.myapp");
intent.setAction("mypackage.myapp.myaction");
scope.startActivityAndWait(intent);
return Unit.INSTANCE;
}
);
}
```
</section>
## Project structure
As in the public documentation, macrobenchmarks in the AndroidX repo are
comprised of an app, and a separate macrobenchmark module. Additional setups
steps/constraints for the AndroidX repository are listed below.
1. App and macrobenchmark modules must be unique, and map 1:1.
1. Target app path in `settings.gradle` must end with
`:integration-tests:macrobenchmark-target`.
1. Macrobenchmark library path must be at the same path, but instead ending
with `:integration-tests:macrobenchmark`
1. An entry should be placed in AffectedModuleDetector to recognize
macrobenchmark dependency on target app module,
[for example](https://cs.android.com/androidx/platform/frameworks/support/+/androidx-main:buildSrc/src/main/kotlin/androidx/build/dependencyTracker/AffectedModuleDetector.kt;l=518;drc=cfb504756386b6225a2176d1d6efe2f55d4fa564)
Compose Macrobenchmark Examples:
* [`:compose:integration-tests:macrobenchmark-target`](https://cs.android.com/androidx/platform/frameworks/support/+/androidx-main:compose/integration-tests/macrobenchmark-target/)
* [`:compose:integration-tests:macrobenchmark`](https://cs.android.com/androidx/platform/frameworks/support/+/androidx-main:compose/integration-tests/macrobenchmark/)
* [AffectedModuleDetector Entry](https://cs.android.com/androidx/platform/frameworks/support/+/androidx-main:buildSrc/src/main/kotlin/androidx/build/dependencyTracker/AffectedModuleDetector.kt;l=526;drc=cfb504756386b6225a2176d1d6efe2f55d4fa564)
Note: Compose macrobenchmarks are generally duplicated with View system
counterparts, defined in `:benchmark:integration-tests:macrobenchmark-target`.
This is how we compare performance of the two systems.
### Setup checklist
<table>
<tr>
<td><strong>Did you setup...</strong></td>
<td><strong>Required setup</strong></td>
</tr>
<tr>
<td>Two modules in settings.gradle</td>
<td>Both the macrobenchmark and target must be defined in sibling
modules</td>
</tr>
<tr>
<td>The module name for the benchmark (test) module</td>
<td>It must match /.*:integration-tests:.*macrobenchmark/</td>
</tr>
<tr>
<td>The module name for the target (integration app) module</td>
<td>It must match /.*:integration-tests:.*macrobenchmark-target</td>
</tr>
<tr>
<td>Register the modules in AffectedModuleDetector.kt</td>
<td>It must link the modules (see docs above)</td>
</tr>
<tr>
<td>Name the test class in a discoverable way</td>
<td>Test classes should have standalone names for easy discovery in the
web UI. E.g EmojiStartupTest instead of StartupTest.</td>
</tr>
</table>