1 /*
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 
17 package android.wm;
18 
19 import static android.perftests.utils.ManualBenchmarkState.StatsReport;
20 
21 import android.os.SystemClock;
22 import android.perftests.utils.ManualBenchmarkState;
23 import android.perftests.utils.ManualBenchmarkState.ManualBenchmarkTest;
24 import android.perftests.utils.PerfManualStatusReporter;
25 import android.perftests.utils.TraceMarkParser;
26 import android.perftests.utils.TraceMarkParser.TraceMarkSlice;
27 import android.util.Log;
28 
29 import androidx.test.filters.LargeTest;
30 import androidx.test.runner.lifecycle.Stage;
31 
32 import org.junit.Rule;
33 import org.junit.Test;
34 
35 import java.io.BufferedReader;
36 import java.io.IOException;
37 import java.io.InputStream;
38 import java.io.InputStreamReader;
39 
40 /** Measure the performance of internal methods in window manager service by trace tag. */
41 @LargeTest
42 public class InternalWindowOperationPerfTest extends WindowManagerPerfTestBase
43         implements ManualBenchmarkState.CustomizedIterationListener {
44     private static final String TAG = InternalWindowOperationPerfTest.class.getSimpleName();
45 
46     @Rule
47     public final PerfManualStatusReporter mPerfStatusReporter = new PerfManualStatusReporter();
48 
49     @Rule
50     public final PerfTestActivityRule mActivityRule = new PerfTestActivityRule();
51 
52     private final TraceMarkParser mTraceMarkParser = new TraceMarkParser(
53             "applyPostLayoutPolicy",
54             "applySurfaceChanges",
55             "onTransactionReady",
56             "applyTransaction",
57             "performLayout",
58             "performSurfacePlacement",
59             "prepareSurfaces",
60             "updateInputWindows",
61             "WSA#startAnimation",
62             "activityIdle",
63             "activityPaused",
64             "activityStopped",
65             "activityDestroyed",
66             "finishActivity",
67             "startActivityInner");
68 
69     private boolean mIsProfiling;
70     private boolean mIsTraceStarted;
71 
72     @Test
73     @ManualBenchmarkTest(
74             targetTestDurationNs = 20 * TIME_1_S_IN_NS,
75             statsReport = @StatsReport(
76                     flags = StatsReport.FLAG_ITERATION | StatsReport.FLAG_MEAN
77                             | StatsReport.FLAG_MAX | StatsReport.FLAG_COEFFICIENT_VAR))
testLaunchAndFinishActivity()78     public void testLaunchAndFinishActivity() throws Throwable {
79         final ManualBenchmarkState state = mPerfStatusReporter.getBenchmarkState();
80         state.setCustomizedIterations(getProfilingIterations(), this);
81         long measuredTimeNs = 0;
82 
83         while (state.keepRunning(measuredTimeNs)) {
84             if (!mIsTraceStarted && !mIsProfiling && !state.isWarmingUp()) {
85                 startAsyncAtrace("wm");
86                 mIsTraceStarted = true;
87             }
88             final long startTime = SystemClock.elapsedRealtimeNanos();
89             mActivityRule.launchActivity();
90             mActivityRule.finishActivity();
91             mActivityRule.waitForIdleSync(Stage.DESTROYED);
92             measuredTimeNs = SystemClock.elapsedRealtimeNanos() - startTime;
93         }
94 
95         if (mIsTraceStarted) {
96             stopAsyncAtrace();
97         }
98 
99         mTraceMarkParser.forAllSlices((key, slices) -> {
100             if (slices.size() < 2) {
101                 Log.w(TAG, "No sufficient samples: " + key);
102                 return;
103             }
104             for (TraceMarkSlice slice : slices) {
105                 state.addExtraResult(key, (long) (slice.getDurationInSeconds() * NANOS_PER_S));
106             }
107         });
108 
109         Log.i(TAG, String.valueOf(mTraceMarkParser));
110     }
111 
stopAsyncAtrace()112     private void stopAsyncAtrace() {
113         final InputStream inputStream = stopAsyncAtraceWithStream();
114         try (BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream))) {
115             String line;
116             while ((line = reader.readLine()) != null) {
117                 mTraceMarkParser.visit(line);
118             }
119         } catch (IOException e) {
120             Log.w(TAG, "Failed to read the result of stopped atrace", e);
121         }
122     }
123 
124     @Override
onStart(int iteration)125     public void onStart(int iteration) {
126         if (mIsTraceStarted) {
127             // Do not capture trace when profiling because the result will be much slower.
128             stopAsyncAtrace();
129             mIsTraceStarted = false;
130         }
131         mIsProfiling = true;
132         startProfiling(InternalWindowOperationPerfTest.class.getSimpleName()
133                 + "_MethodTracing_" + iteration + ".trace");
134     }
135 
136     @Override
onFinished(int iteration)137     public void onFinished(int iteration) {
138         stopProfiling();
139         if (iteration >= getProfilingIterations() - 1) {
140             mIsProfiling = false;
141         }
142     }
143 }
144