blob: c54786abd3473f3e178144e131ba466563494747 [file] [log] [blame] [view]
AndroidX Core Team2e416b22020-12-03 22:58:07 +00001# Benchmarking in AndroidX
2
3[TOC]
4
5The public documentation at
6[d.android.com/benchmark](http://d.android.com/benchmark) explains how to use
7the library - this page focuses on specifics to writing libraries in the
8AndroidX repo, and our continuous testing / triage process.
9
AndroidX Core Team0e7745f2021-04-08 17:00:10 +000010This page is for MICRO benchmarks measuring CPU performance of small sections of
11code. If you're looking for measuring startup or jank, see the guide for
12MACRObenchmarks [here](macrobenchmarking).
13
AndroidX Core Team2e416b22020-12-03 22:58:07 +000014### Writing the benchmark
15
16Benchmarks are just regular instrumentation tests! Just use the
AndroidX Core Team408c27b2020-12-15 15:57:00 +000017[`BenchmarkRule`](https://android.googlesource.com/platform/frameworks/support/+/androidx-main/benchmark/junit4/src/main/java/androidx/benchmark/junit4/BenchmarkRule.kt)
AndroidX Core Team2e416b22020-12-03 22:58:07 +000018provided by the library:
19
20<section class="tabs">
21
22#### Kotlin {.new-tab}
23
24```kotlin
25@RunWith(AndroidJUnit4::class)
26class ViewBenchmark {
27 @get:Rule
28 val benchmarkRule = BenchmarkRule()
29
30 @Test
31 fun simpleViewInflate() {
32 val context = InstrumentationRegistry
33 .getInstrumentation().targetContext
34 val inflater = LayoutInflater.from(context)
35 val root = FrameLayout(context)
36
37 benchmarkRule.measure {
38 inflater.inflate(R.layout.test_simple_view, root, false)
39 }
40 }
41}
42```
43
44#### Java {.new-tab}
45
46```java
47@RunWith(AndroidJUnit4.class)
48public class ViewBenchmark {
49 @Rule
50 public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
51
52 @Test
53 public void simpleViewInflate() {
54 Context context = InstrumentationRegistry
55 .getInstrumentation().getTargetContext();
56 final BenchmarkState state = mBenchmarkRule.getState();
57 LayoutInflater inflater = LayoutInflater.from(context);
58 FrameLayout root = new FrameLayout(context);
59
60 while (state.keepRunning()) {
61 inflater.inflate(R.layout.test_simple_view, root, false);
62 }
63 }
64}
65```
66
67</section>
68
69## Project structure
70
71As in the public documentation, benchmarks in the AndroidX repo are test-only
72library modules. Differences for AndroidX repo:
73
AndroidX Core Team0e7745f2021-04-08 17:00:10 +0000741. Module must live in `integration-tests` group directory
AndroidX Core Team2e416b22020-12-03 22:58:07 +0000751. Module name must end with `-benchmark` in `settings.gradle`.
AndroidX Core Team2e416b22020-12-03 22:58:07 +000076
77### I'm lazy and want to start quickly
78
79Start by copying one of the following projects:
80
AndroidX Core Team408c27b2020-12-15 15:57:00 +000081* [navigation-benchmark](https://android.googlesource.com/platform/frameworks/support/+/refs/heads/androidx-main/navigation/benchmark/)
82* [recyclerview-benchmark](https://android.googlesource.com/platform/frameworks/support/+/refs/heads/androidx-main/recyclerview/recyclerview-benchmark/)
AndroidX Core Team2e416b22020-12-03 22:58:07 +000083
84### Compose
85
86Compose builds the benchmark from source, so usage matches the rest of the
87AndroidX project. See existing Compose benchmark projects:
88
AndroidX Core Team408c27b2020-12-15 15:57:00 +000089* [Compose UI benchmarks](https://cs.android.com/androidx/platform/frameworks/support/+/androidx-main:compose/integration-tests/benchmark/)
90* [Compose Runtime benchmarks](https://cs.android.com/androidx/platform/frameworks/support/+/androidx-main:compose/runtime/runtime/compose-runtime-benchmark/)
AndroidX Core Team2e416b22020-12-03 22:58:07 +000091
92## Profiling
93
94### Command Line
95
AndroidX Core Team5f312b62021-08-05 15:59:15 -070096The benchmark library supports capturing profiling information - stack sampling
97and method tracing - from the command line. Here's an example which runs the
98`androidx.compose.material.benchmark.CheckboxesInRowsBenchmark#draw` method with
99`StackSampling` profiling:
AndroidX Core Team2e416b22020-12-03 22:58:07 +0000100
101```
AndroidX Core Team5f312b62021-08-05 15:59:15 -0700102./gradlew compose:material:material-benchmark:cC \
103 -P android.testInstrumentationRunnerArguments.androidx.benchmark.profiling.mode=StackSampling \
104 -P android.testInstrumentationRunnerArguments.class=androidx.compose.material.benchmark.CheckboxesInRowsBenchmark#draw
AndroidX Core Team2e416b22020-12-03 22:58:07 +0000105```
106
107The command output will tell you where to look for the file on your host
108machine:
109
110```
11104:33:49 I/Benchmark: Benchmark report files generated at
AndroidX Core Team408c27b2020-12-15 15:57:00 +0000112/androidx-main/out/ui/ui/integration-tests/benchmark/build/outputs/connected_android_test_additional_output
AndroidX Core Team2e416b22020-12-03 22:58:07 +0000113```
114
115To inspect the captured trace, open the appropriate `*.trace` file in that
116directory with Android Studio, using `File > Open`.
117
AndroidX Core Team5f312b62021-08-05 15:59:15 -0700118NOTE For stack sampling, it's recommended to profile on Android Q(API 29) or
119higher, as this enables the benchmark library to use
120[Simpleperf](https://android.googlesource.com/platform/system/extras/+/master/simpleperf/doc/).
121Simpleperf previously required a
122[more complex setup process](https://issuetracker.google.com/issues/158303822) -
123this has been fixed!
124
125For more information on the `StackSampling` and `MethodTracing` profiling modes,
126see the
AndroidX Core Team2e416b22020-12-03 22:58:07 +0000127[Studio Profiler configuration docs](https://developer.android.com/studio/profile/cpu-profiler#configurations),
AndroidX Core Team5f312b62021-08-05 15:59:15 -0700128specifically "Sample C/C++ Functions" (a confusing name for Simpleperf), and
129Java Method Tracing.
AndroidX Core Team2e416b22020-12-03 22:58:07 +0000130
131![Sample flame chart](benchmarking_images/profiling_flame_chart.png "Sample flame chart")
132
AndroidX Core Team5f312b62021-08-05 15:59:15 -0700133NOTE Simpleperf captures stack traces from all threads, so click the test thread
134in the left profiler panel, and select flame chart on the right to see just
135samples from the test.
AndroidX Core Team2e416b22020-12-03 22:58:07 +0000136
137### Advanced: Studio Profiling
138
139Profiling for allocations and simpleperf profiling requires Studio to capture.
140
141Studio profiling tools require `debuggable=true`. First, temporarily override it
142in your benchmark's `androidTest/AndroidManifest.xml`.
143
144Next choose which profiling you want to do: Allocation, or Sampled (SimplePerf)
145
146`ConnectedAllocation` will help you measure the allocations in a single run of a
147benchmark loop, after warmup.
148
149`ConnectedSampled` will help you capture sampled profiling, but with the more
150detailed / accurate Simpleperf sampling.
151
152Set the profiling type in your benchmark module's `build.gradle`:
153
154```
155android {
156 defaultConfig {
157 // Local only, don't commit this!
158 testInstrumentationRunnerArgument 'androidx.benchmark.profiling.mode', 'ConnectedAllocation'
159 }
160}
161```
162
163Run `File > Sync Project with Gradle Files`, or sync if Studio asks you. Now any
164benchmark runs in that project will permit debuggable, and pause before and
165after the test, to allow you to connect a profiler and start recording, and then
166stop recording.
167
168#### Running and Profiling
169
170After the benchmark test starts, you have about 20 seconds to connect the
171profiler:
172
1731. Click the profiler tab at the bottom
1741. Click the plus button in the top left, `<device name>`, `<process name>`
1751. Next step depends on which you intend to capture
176
177#### Allocations
178
179Click the memory section, and right click the window, and select `Record
180allocations`. Approximately 20 seconds later, right click again and select `Stop
181recording`.