blob: 029f8f509135e9be2e5bfcce11353ce43bfe06e9 [file] [log] [blame] [view]
# MACRObenchmarking in AndroidX
[TOC]
<!-- Copied from macrobenchmark docs -->
<table>
<tr>
<td><strong>Macrobenchmark</strong></td>
<td><strong>Benchmark</strong></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>Configure compilation with <a href="https://developer.android.com/reference/androidx/benchmark/macro/CompilationMode">CompilationMode</a></td>
<td>Always fully AOT (<code>speed</code>) compiled.</td>
</tr>
<tr>
<td>Min API 23</td>
<td>Min API 19</td>
</tr>
<tr>
<td>Relatively lower stability measurements</td>
<td>Higher stability measurements</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](/docs/benchmarking.md).
### Writing the benchmark
Benchmarks are just regular instrumentation tests! Just use the
[`MacrobenchmarkRule`](https://developer.android.com/reference/kotlin/androidx/benchmark/macro/junit4/MacrobenchmarkRule)
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 = 10
) { // 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 = */ 10,
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 test module. In the AndroidX
repository, there are additional requirements:
1. Macrobenchmark test module path in `settings.gradle` **must** end with
`macrobenchmark` to run in CI.
1. Macrobenchmark target module path in `settings.gradle` **should** end with
`macrobenchmark-target` to follow convention.
1. Macrobenchmark modules **must** use project dependencies where available (so
`implementation(project(":activity:activity-ktx"))` rather than
`implementation("androidx.activity:activity-ktx:1.5.0")`). This prevents
accidentally testing against out-of-date versions, and increases coverage of
lower level libraries.
1. Each library group **must** declare its own in-group macrobenchmark test and
app module, with out using these modules for anything else (e.g. samples).
We want to be intentional about which changes affect measurements. More than
one of either is allowed, which is sometimes necessary to compare different
startup behaviors, see e.g.
`:emoji2:integration-tests:init-<disabled/enabled>-macrobenchmark-target`.
Note that comparing multiple app variants are not currently supported by CI.
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/)
Note: Compose macrobenchmarks are ideally 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 <code>settings.gradle</code></td>
<td>Both the macrobenchmark and target must be added for your group</td>
</tr>
<tr>
<td>The module name for the benchmark (<code>com.android.test</code>) module</td>
<td>Must end with <code>macrobenchmark</code></td>
</tr>
<tr>
<td>The module name for the app (<code>com.android.app</code>) module</td>
<td>Must end with <code>macrobenchmark-target</code></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>