blob: 1d3ff06e6bf1ad38b982781ac6a674250cf3e671 [file] [log] [blame]
Jing Ji84121312019-10-17 15:36:57 -07001/*
2 * Copyright (C) 2019 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.frameworks.perftests.am.tests;
18
19
20import android.content.ContentResolver;
21import android.content.Context;
22import android.net.Uri;
23import android.os.HandlerThread;
24import android.perftests.utils.ManualBenchmarkState;
25import android.perftests.utils.PerfManualStatusReporter;
26import android.perftests.utils.TraceMarkParser;
27import android.perftests.utils.TraceMarkParser.TraceMarkLine;
28import android.perftests.utils.TraceMarkParser.TraceMarkSlice;
29
30import androidx.test.InstrumentationRegistry;
31import androidx.test.filters.LargeTest;
32
33import com.android.frameworks.perftests.am.util.AtraceUtils;
34import com.android.frameworks.perftests.am.util.TargetPackageUtils;
35import com.android.frameworks.perftests.am.util.Utils;
36
37import org.junit.After;
38import org.junit.Before;
39import org.junit.Rule;
40import org.junit.Test;
41import org.junit.runner.RunWith;
42import org.junit.runners.JUnit4;
43
44import java.util.ArrayList;
45import java.util.List;
46
47/**
48 * This benchmark test basically manipulates 3 test packages, let them bind to
49 * each other, send broadcast to each other, etc. All of these actions essentially
50 * triggers OomAdjuster to update the oom_adj scores and proc state of them.
51 * In the meanwhile it'll also monitor the atrace output, extract duration between
52 * the start and exit entries of the updateOomAdjLocked, include each of them
53 * into the stats; when there are enough samples in the stats, the test will
54 * stop and output the mean/stddev time spent on the updateOomAdjLocked.
55 */
56@RunWith(JUnit4.class)
57@LargeTest
58public final class OomAdjPerfTest {
59 private static final String TAG = "OomAdjPerfTest";
60 private static final boolean VERBOSE = true;
61
62 private static final String STUB_PACKAGE1_NAME = "com.android.stubs.am1";
63 private static final String STUB_PACKAGE2_NAME = "com.android.stubs.am2";
64 private static final String STUB_PACKAGE3_NAME = "com.android.stubs.am3";
65
66 private static final Uri STUB_PACKAGE1_URI = new Uri.Builder().scheme(
67 ContentResolver.SCHEME_CONTENT).authority("com.android.stubs.am1.testapp").build();
68 private static final Uri STUB_PACKAGE2_URI = new Uri.Builder().scheme(
69 ContentResolver.SCHEME_CONTENT).authority("com.android.stubs.am2.testapp").build();
70 private static final Uri STUB_PACKAGE3_URI = new Uri.Builder().scheme(
71 ContentResolver.SCHEME_CONTENT).authority("com.android.stubs.am3.testapp").build();
72 private static final long NANOS_PER_MICROSECOND = 1000L;
73
74 private static final String ATRACE_CATEGORY = "am";
75 private static final String ATRACE_OOMADJ_PREFIX = "updateOomAdj_";
76
77 @Rule
78 public PerfManualStatusReporter mPerfManualStatusReporter = new PerfManualStatusReporter();
79 private TraceMarkParser mTraceMarkParser = new TraceMarkParser(this::shouldFilterTraceLine);
80 private final ArrayList<Long> mDurations = new ArrayList<Long>();
81 private Context mContext;
82 private HandlerThread mHandlerThread;
83
84 @Before
85 public void setUp() {
86 mContext = InstrumentationRegistry.getTargetContext();
87 mHandlerThread = new HandlerThread("command receiver");
88 mHandlerThread.start();
89 TargetPackageUtils.initCommandResultReceiver(mHandlerThread.getLooper());
90
91 Utils.runShellCommand("cmd deviceidle whitelist +" + STUB_PACKAGE1_NAME);
92 Utils.runShellCommand("cmd deviceidle whitelist +" + STUB_PACKAGE2_NAME);
93 Utils.runShellCommand("cmd deviceidle whitelist +" + STUB_PACKAGE3_NAME);
94 TargetPackageUtils.startStubPackage(mContext, STUB_PACKAGE1_NAME);
95 TargetPackageUtils.startStubPackage(mContext, STUB_PACKAGE2_NAME);
96 TargetPackageUtils.startStubPackage(mContext, STUB_PACKAGE3_NAME);
97 }
98
99 @After
100 public void tearDown() {
101 TargetPackageUtils.stopStubPackage(mContext, STUB_PACKAGE1_NAME);
102 TargetPackageUtils.stopStubPackage(mContext, STUB_PACKAGE2_NAME);
103 TargetPackageUtils.stopStubPackage(mContext, STUB_PACKAGE3_NAME);
104 Utils.runShellCommand("cmd deviceidle whitelist -" + STUB_PACKAGE1_NAME);
105 Utils.runShellCommand("cmd deviceidle whitelist -" + STUB_PACKAGE2_NAME);
106 Utils.runShellCommand("cmd deviceidle whitelist -" + STUB_PACKAGE3_NAME);
107 mHandlerThread.quitSafely();
108 }
109
110 @Test
111 public void testOomAdj() {
112 final AtraceUtils atraceUtils = AtraceUtils.getInstance(
113 InstrumentationRegistry.getInstrumentation());
114 final ManualBenchmarkState state = mPerfManualStatusReporter.getBenchmarkState();
115 atraceUtils.startTrace(ATRACE_CATEGORY);
116 while (state.keepRunning(mDurations)) {
117 runCUJWithOomComputationOnce();
118
119 // Now kick off the trace dump
120 mDurations.clear();
121 atraceUtils.performDump(mTraceMarkParser, this::handleTraceMarkSlices);
122 }
123 atraceUtils.stopTrace();
124 }
125
126 private boolean shouldFilterTraceLine(final TraceMarkLine line) {
127 return line.name.startsWith(ATRACE_OOMADJ_PREFIX);
128 }
129
130 private void handleTraceMarkSlices(String key, List<TraceMarkSlice> slices) {
131 for (TraceMarkSlice slice: slices) {
132 mDurations.add(slice.getDurationInMicroseconds() * NANOS_PER_MICROSECOND);
133 }
134 }
135
136 /**
137 * This tries to mimic a user journey, involes multiple activity/service starts/stop,
138 * the time spent on oom adj computation would be different between all these samples,
139 * but with enough samples, we'll be able to know the overall distribution of the time
140 * spent on it.
141 */
142 private void runCUJWithOomComputationOnce() {
143 // Start activity from package1
144 TargetPackageUtils.startActivity(STUB_PACKAGE1_NAME, STUB_PACKAGE1_NAME);
145 // Start activity from package2
146 TargetPackageUtils.startActivity(STUB_PACKAGE2_NAME, STUB_PACKAGE2_NAME);
147 // Start activity from package3
148 TargetPackageUtils.startActivity(STUB_PACKAGE3_NAME, STUB_PACKAGE3_NAME);
149
150 // Stop activity in package1
151 TargetPackageUtils.stopActivity(STUB_PACKAGE1_NAME, STUB_PACKAGE1_NAME);
152 // Stop activity in package2
153 TargetPackageUtils.stopActivity(STUB_PACKAGE2_NAME, STUB_PACKAGE2_NAME);
154 // Stop activity in package3
155 TargetPackageUtils.stopActivity(STUB_PACKAGE3_NAME, STUB_PACKAGE3_NAME);
156
157 // Bind from package1 to package2
158 TargetPackageUtils.bindService(STUB_PACKAGE1_NAME, STUB_PACKAGE2_NAME,
159 Context.BIND_AUTO_CREATE);
160 // Acquire content provider from package 1 to package3
161 TargetPackageUtils.acquireProvider(STUB_PACKAGE1_NAME, STUB_PACKAGE3_NAME,
162 STUB_PACKAGE3_URI);
163 // Start activity from package1
164 TargetPackageUtils.startActivity(STUB_PACKAGE1_NAME, STUB_PACKAGE1_NAME);
165 // Bind from package2 to package3
166 TargetPackageUtils.bindService(STUB_PACKAGE2_NAME, STUB_PACKAGE3_NAME,
167 Context.BIND_AUTO_CREATE);
168 // Unbind from package 1 to package 2
169 TargetPackageUtils.unbindService(STUB_PACKAGE1_NAME, STUB_PACKAGE2_NAME, 0);
170 // Stop activity in package1
171 TargetPackageUtils.stopActivity(STUB_PACKAGE1_NAME, STUB_PACKAGE1_NAME);
172
173 // Send broadcast to all of them
174 TargetPackageUtils.sendBroadcast(STUB_PACKAGE1_NAME, STUB_PACKAGE1_NAME);
175 TargetPackageUtils.sendBroadcast(STUB_PACKAGE2_NAME, STUB_PACKAGE2_NAME);
176 TargetPackageUtils.sendBroadcast(STUB_PACKAGE3_NAME, STUB_PACKAGE3_NAME);
177
178 // Bind from package1 to package2 again
179 TargetPackageUtils.bindService(STUB_PACKAGE1_NAME, STUB_PACKAGE2_NAME,
180 Context.BIND_AUTO_CREATE);
181 // Create a cycle: package3 to package1
182 TargetPackageUtils.bindService(STUB_PACKAGE3_NAME, STUB_PACKAGE1_NAME,
183 Context.BIND_AUTO_CREATE);
184
185 // Send broadcast to all of them again
186 TargetPackageUtils.sendBroadcast(STUB_PACKAGE1_NAME, STUB_PACKAGE1_NAME);
187 TargetPackageUtils.sendBroadcast(STUB_PACKAGE2_NAME, STUB_PACKAGE2_NAME);
188 TargetPackageUtils.sendBroadcast(STUB_PACKAGE3_NAME, STUB_PACKAGE3_NAME);
189 // Start activity in package3
190 TargetPackageUtils.startActivity(STUB_PACKAGE3_NAME, STUB_PACKAGE3_NAME);
191
192 // Break the cycle: unbind from package3 to package1
193 TargetPackageUtils.unbindService(STUB_PACKAGE3_NAME, STUB_PACKAGE1_NAME, 0);
194
195 // Bind from package3 to package1 with waive priority
196 TargetPackageUtils.bindService(STUB_PACKAGE3_NAME, STUB_PACKAGE1_NAME,
197 Context.BIND_AUTO_CREATE | Context.BIND_WAIVE_PRIORITY);
198 // Release provider connection
199 TargetPackageUtils.releaseProvider(STUB_PACKAGE1_NAME, STUB_PACKAGE3_NAME,
200 STUB_PACKAGE3_URI);
201 // Unbind from package1 to package2
202 TargetPackageUtils.unbindService(STUB_PACKAGE1_NAME, STUB_PACKAGE2_NAME, 0);
203 // Unbind from package2 to packagae3
204 TargetPackageUtils.unbindService(STUB_PACKAGE2_NAME, STUB_PACKAGE3_NAME, 0);
205
206 // Bind from package3 to package2 with BIND_ABOVE_CLIENT
207 TargetPackageUtils.bindService(STUB_PACKAGE3_NAME, STUB_PACKAGE2_NAME,
208 Context.BIND_AUTO_CREATE | Context.BIND_ABOVE_CLIENT);
209 // Unbind from package3 to packagae2
210 TargetPackageUtils.unbindService(STUB_PACKAGE3_NAME, STUB_PACKAGE2_NAME, 0);
211
212 // Bind from package3 to package2 with BIND_ALLOW_OOM_MANAGEMENT
213 TargetPackageUtils.bindService(STUB_PACKAGE3_NAME, STUB_PACKAGE2_NAME,
214 Context.BIND_AUTO_CREATE | Context.BIND_ALLOW_OOM_MANAGEMENT);
215 // Unbind from package3 to packagae2
216 TargetPackageUtils.unbindService(STUB_PACKAGE3_NAME, STUB_PACKAGE2_NAME, 0);
217
218 // Bind from package3 to package2 with BIND_IMPORTANT
219 TargetPackageUtils.bindService(STUB_PACKAGE3_NAME, STUB_PACKAGE2_NAME,
220 Context.BIND_AUTO_CREATE | Context.BIND_IMPORTANT);
221 // Unbind from package3 to packagae2
222 TargetPackageUtils.unbindService(STUB_PACKAGE3_NAME, STUB_PACKAGE2_NAME, 0);
223
224 // Bind from package3 to package2 with BIND_NOT_FOREGROUND
225 TargetPackageUtils.bindService(STUB_PACKAGE3_NAME, STUB_PACKAGE2_NAME,
226 Context.BIND_AUTO_CREATE | Context.BIND_NOT_FOREGROUND);
227 // Unbind from package3 to packagae2
228 TargetPackageUtils.unbindService(STUB_PACKAGE3_NAME, STUB_PACKAGE2_NAME, 0);
229
230 // Bind from package3 to package2 with BIND_NOT_PERCEPTIBLE
231 TargetPackageUtils.bindService(STUB_PACKAGE3_NAME, STUB_PACKAGE2_NAME,
232 Context.BIND_AUTO_CREATE | Context.BIND_NOT_PERCEPTIBLE);
233 // Unbind from package3 to packagae2
234 TargetPackageUtils.unbindService(STUB_PACKAGE3_NAME, STUB_PACKAGE2_NAME, 0);
235
236 // Stop activity in package3
237 TargetPackageUtils.stopActivity(STUB_PACKAGE3_NAME, STUB_PACKAGE3_NAME);
238 // Unbind from package3 to package1
239 TargetPackageUtils.unbindService(STUB_PACKAGE3_NAME, STUB_PACKAGE1_NAME, 0);
240 }
241}