1# SPDX-License-Identifier: Apache-2.0 2# 3# Copyright (C) 2017, ARM Limited, Google and contributors. 4# 5# Licensed under the Apache License, Version 2.0 (the "License"); you may 6# not use this file except in compliance with the License. 7# You may obtain a copy of the License at 8# 9# http://www.apache.org/licenses/LICENSE-2.0 10# 11# Unless required by applicable law or agreed to in writing, software 12# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 13# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14# See the License for the specific language governing permissions and 15# limitations under the License. 16# 17 18import os 19import re 20 21from subprocess import Popen, PIPE 22from time import sleep 23 24from android import Screen, System, Workload 25 26import pandas as pd 27 28 29class SysApp(Workload): 30 """ 31 Android system app jank test workload. 32 """ 33 34 packages = [ 35 Workload.WorkloadPackage("com.android.sysapp.janktests", 36 "data/app/SystemAppJankTests/SystemAppJankTests.apk", 37 "vendor/google_testing/integration/tests/jank/sysapp"), 38 Workload.WorkloadPackage("com.android.chrome", 39 "system/app/Chrome/Chrome.apk", 40 "vendor/unbundled_google/packages/Chrome"), 41 Workload.WorkloadPackage("com.google.android.youtube", 42 "system/app/Youtube/Youtube.apk", 43 "vendor/unbundled_google/packages/YouTube") 44 ] 45 46 test_package = packages[0].package_name 47 48 test_list = [ 49 "ChromeJankTests#testChromeOverflowMenuTap", 50 "YouTubeJankTests#testYouTubeRecomendationWindowFling" 51 ] 52 53 def __init__(self, test_env): 54 super(SysApp, self).__init__(test_env) 55 56 def get_test_list(self): 57 return SysApp.test_list 58 59 def _get_test_package(self, test_name): 60 name_start = test_name.partition('JankTests')[0] 61 name_map = { 62 "Chrome": "com.android.chrome", 63 "YouTube": "com.google.android.youtube", 64 } 65 return name_map[name_start] 66 67 def run(self, out_dir, test_name, iterations, collect=''): 68 """ 69 Run single system app jank test workload. 70 Performance statistics are stored in self.results, and can be retrieved 71 after the fact by calling SystemUi.get_results() 72 73 :param out_dir: Path to experiment directory where to store results. 74 :type out_dir: str 75 76 :param test_name: Name of the test to run 77 :type test_name: str 78 79 :param iterations: Run benchmark for this required number of iterations 80 :type iterations: int 81 82 :param collect: Specifies what to collect. Possible values: 83 - 'systrace' 84 - 'ftrace' 85 - 'gfxinfo' 86 - 'surfaceflinger' 87 - any combination of the above 88 :type collect: list(str) 89 """ 90 if "energy" in collect: 91 raise ValueError('System app workload does not support energy data collection') 92 93 activity = "." + test_name 94 package = self._get_test_package(test_name) 95 96 # Keep track of mandatory parameters 97 self.out_dir = out_dir 98 self.collect = collect 99 100 # Filter out test overhead 101 filter_prop = System.get_boolean_property(self._target, "debug.hwui.filter_test_overhead") 102 if not filter_prop: 103 System.set_property(self._target, "debug.hwui.filter_test_overhead", "true", restart=True) 104 105 # Unlock device screen (assume no password required) 106 Screen.unlock(self._target) 107 108 # Close and clear application 109 System.force_stop(self._target, package, clear=True) 110 111 # Set min brightness 112 Screen.set_brightness(self._target, auto=False, percent=0) 113 114 # Force screen in PORTRAIT mode 115 Screen.set_orientation(self._target, portrait=True) 116 117 # Delete old test results 118 self._target.remove("/sdcard/results.log") 119 120 # Clear logcat 121 self._target.execute("logcat -c") 122 123 # Regexps for benchmark synchronization 124 start_logline = r"TestRunner: started" 125 SYSAPP_BENCHMARK_START_RE = re.compile(start_logline) 126 self._log.debug("START string [%s]", start_logline) 127 128 finish_logline = r"TestRunner: finished" 129 SYSAPP_BENCHMARK_FINISH_RE = re.compile(finish_logline) 130 self._log.debug("FINISH string [%s]", finish_logline) 131 132 # Parse logcat output lines 133 logcat_cmd = self._adb("logcat TestRunner:* System.out:I *:S BENCH:*") 134 self._log.info("%s", logcat_cmd) 135 136 command = "am instrument -e iterations {} -e class {}{} -w {}".format( 137 iterations, self.test_package, activity, self.test_package) 138 139 logcat = Popen(logcat_cmd, shell=True, stdout=PIPE) 140 141 test_proc = self._target.background(command) 142 while True: 143 # read next logcat line (up to max 1024 chars) 144 message = logcat.stdout.readline(1024) 145 146 # Benchmark start 147 match = SYSAPP_BENCHMARK_START_RE.search(message) 148 if match: 149 self.tracingStart() 150 self._log.debug("Benchmark started!") 151 152 # Benchmark finish 153 match = SYSAPP_BENCHMARK_FINISH_RE.search(message) 154 if match: 155 self.tracingStop() 156 self._log.debug("Benchmark finished!") 157 test_proc.wait() 158 break 159 sleep(5) 160 self._target.pull("/sdcard/results.log", os.path.join(out_dir, "results.log")) 161 self.db_file = os.path.join(out_dir, "results.log") 162 self.results = self.get_results(out_dir) 163 164 # Close and clear application 165 System.force_stop(self._target, package, clear=True) 166 167 # Go back to home screen 168 System.home(self._target) 169 170 # Switch back to original settings 171 Screen.set_orientation(self._target, auto=True) 172 Screen.set_brightness(self._target, auto=True) 173 174 175 @staticmethod 176 def get_results(out_dir): 177 """ 178 Parse SysApp test output log and return a pandas dataframe of test results. 179 180 :param out_dir: Output directory for a run of the SysApp workload. 181 :type out_dir: str 182 """ 183 path = os.path.join(out_dir, "results.log") 184 with open(path, "r") as f: 185 lines = f.readlines() 186 cols = [] 187 vals = [] 188 for line in lines: 189 name, val = str.split(line) 190 if name == "Result": 191 cols.append("test-name") 192 vals.append(val) 193 elif name.startswith("gfx-"): 194 cols.append(name[4:]) 195 vals.append(float(val)) 196 else: 197 raise ValueError("Unrecognized line in results file") 198 return pd.DataFrame([vals], columns=cols) 199