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             "AppTransitionReady",
56             "closeSurfaceTransaction",
57             "openSurfaceTransaction",
58             "performLayout",
59             "performSurfacePlacement",
60             "prepareSurfaces",
61             "updateInputWindows",
62             "WSA#startAnimation",
63             "activityIdle",
64             "activityPaused",
65             "activityStopped",
66             "activityDestroyed",
67             "finishActivity",
68             "startActivityInner");
69 
70     private boolean mIsProfiling;
71     private boolean mIsTraceStarted;
72 
73     @Test
74     @ManualBenchmarkTest(
75             targetTestDurationNs = 20 * TIME_1_S_IN_NS,
76             statsReport = @StatsReport(
77                     flags = StatsReport.FLAG_ITERATION | StatsReport.FLAG_MEAN
78                             | StatsReport.FLAG_MAX | StatsReport.FLAG_COEFFICIENT_VAR))
testLaunchAndFinishActivity()79     public void testLaunchAndFinishActivity() throws Throwable {
80         final ManualBenchmarkState state = mPerfStatusReporter.getBenchmarkState();
81         state.setCustomizedIterations(getProfilingIterations(), this);
82         long measuredTimeNs = 0;
83 
84         while (state.keepRunning(measuredTimeNs)) {
85             if (!mIsTraceStarted && !mIsProfiling && !state.isWarmingUp()) {
86                 startAsyncAtrace("wm");
87                 mIsTraceStarted = true;
88             }
89             final long startTime = SystemClock.elapsedRealtimeNanos();
90             mActivityRule.launchActivity();
91             mActivityRule.finishActivity();
92             mActivityRule.waitForIdleSync(Stage.DESTROYED);
93             measuredTimeNs = SystemClock.elapsedRealtimeNanos() - startTime;
94         }
95 
96         if (mIsTraceStarted) {
97             stopAsyncAtrace();
98         }
99 
100         mTraceMarkParser.forAllSlices((key, slices) -> {
101             if (slices.size() < 2) {
102                 Log.w(TAG, "No sufficient samples: " + key);
103                 return;
104             }
105             for (TraceMarkSlice slice : slices) {
106                 state.addExtraResult(key, (long) (slice.getDurationInSeconds() * NANOS_PER_S));
107             }
108         });
109 
110         Log.i(TAG, String.valueOf(mTraceMarkParser));
111     }
112 
stopAsyncAtrace()113     private void stopAsyncAtrace() {
114         final InputStream inputStream = stopAsyncAtraceWithStream();
115         try (BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream))) {
116             String line;
117             while ((line = reader.readLine()) != null) {
118                 mTraceMarkParser.visit(line);
119             }
120         } catch (IOException e) {
121             Log.w(TAG, "Failed to read the result of stopped atrace", e);
122         }
123     }
124 
125     @Override
onStart(int iteration)126     public void onStart(int iteration) {
127         if (mIsTraceStarted) {
128             // Do not capture trace when profiling because the result will be much slower.
129             stopAsyncAtrace();
130             mIsTraceStarted = false;
131         }
132         mIsProfiling = true;
133         startProfiling(InternalWindowOperationPerfTest.class.getSimpleName()
134                 + "_MethodTracing_" + iteration + ".trace");
135     }
136 
137     @Override
onFinished(int iteration)138     public void onFinished(int iteration) {
139         stopProfiling();
140         if (iteration >= getProfilingIterations() - 1) {
141             mIsProfiling = false;
142         }
143     }
144 }
145