1 # SPDX-License-Identifier: Apache-2.0 2 # 3 # Copyright (C) 2015, ARM Limited 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 18 import re 19 import os 20 import logging 21 22 from subprocess import Popen, PIPE 23 from time import sleep 24 25 from android import Screen, System, Workload 26 import pandas as pd 27 28 29 class UiBench(Workload): 30 """ 31 Android UiBench workload 32 """ 33 # Packages required by this workload 34 packages = [ 35 Workload.WorkloadPackage("com.android.test.uibench", 36 "data/app/UiBench/UiBench.apk", 37 "frameworks/base/tests/UiBench"), 38 Workload.WorkloadPackage("com.android.uibench.janktests", 39 "data/app/UiBenchJankTests/UiBenchJankTests.apk", 40 "platform_testing/tests/jank/uibench"), 41 ] 42 43 # Package required by this workload 44 package = packages[0].package_name 45 46 # Instrumentation required to run tests 47 test_package = packages[1].package_name 48 49 # Supported tests list 50 test_list = \ 51 ['UiBenchJankTests#testClippedListView', 52 'UiBenchJankTests#testDialogListFling', 53 'UiBenchJankTests#testFadingEdgeListViewFling', 54 'UiBenchJankTests#testFullscreenOverdraw', 55 'UiBenchJankTests#testGLTextureView', 56 'UiBenchJankTests#testInflatingListViewFling', 57 'UiBenchJankTests#testInvalidate', 58 'UiBenchJankTests#testInvalidateTree', 59 'UiBenchJankTests#testOpenNavigationDrawer', 60 'UiBenchJankTests#testOpenNotificationShade', 61 'UiBenchJankTests#testResizeHWLayer', 62 'UiBenchJankTests#testSaveLayerAnimation', 63 'UiBenchJankTests#testSlowBindRecyclerViewFling', 64 'UiBenchJankTests#testSlowNestedRecyclerViewFling', 65 'UiBenchJankTests#testSlowNestedRecyclerViewInitialFling', 66 'UiBenchJankTests#testTrivialAnimation', 67 'UiBenchJankTests#testTrivialListViewFling', 68 'UiBenchJankTests#testTrivialRecyclerListViewFling', 69 'UiBenchRenderingJankTests#testBitmapUploadJank', 70 'UiBenchRenderingJankTests#testShadowGridListFling', 71 'UiBenchTextJankTests#testEditTextTyping', 72 'UiBenchTextJankTests#testLayoutCacheHighHitrateFling', 73 'UiBenchTextJankTests#testLayoutCacheLowHitrateFling', 74 'UiBenchTransitionsJankTests#testActivityTransitionsAnimation', 75 'UiBenchWebView#testWebViewFling'] 76 77 def __init__(self, test_env): 78 super(UiBench, self).__init__(test_env) 79 self._log = logging.getLogger('UiBench') 80 self._log.debug('Workload created') 81 82 # Set of output data reported by UiBench 83 self.db_file = None 84 85 def get_test_list(self): 86 return UiBench.test_list 87 88 def run(self, out_dir, test_name, iterations=10, collect=''): 89 """ 90 Run single UiBench workload. 91 92 :param out_dir: Path to experiment directory where to store results. 93 :type out_dir: str 94 95 :param test_name: Name of the test to run 96 :type test_name: str 97 98 :param iterations: Run benchmak for this required number of iterations 99 :type iterations: int 100 101 :param collect: Specifies what to collect. Possible values: 102 - 'systrace' 103 - 'ftrace' 104 :type collect: list(str) 105 """ 106 107 if 'energy' in collect: 108 raise ValueError('UiBench workload does not support energy data collection') 109 110 activity = '.' + test_name 111 112 # Keep track of mandatory parameters 113 self.out_dir = out_dir 114 self.collect = collect 115 116 # Filter out test overhead 117 filter_prop = System.get_boolean_property(self._target, 'debug.hwui.filter_test_overhead') 118 if not filter_prop: 119 System.set_property( 120 self._target, 'debug.hwui.filter_test_overhead', 'true', restart=True) 121 122 # Unlock device screen (assume no password required) 123 Screen.unlock(self._target) 124 125 # Close and clear application 126 System.force_stop(self._target, self.package, clear=True) 127 128 # Set airplane mode 129 System.set_airplane_mode(self._target, on=True) 130 131 # Set min brightness 132 Screen.set_brightness(self._target, auto=False, percent=0) 133 134 # Force screen in PORTRAIT mode 135 Screen.set_orientation(self._target, portrait=True) 136 137 # Clear logcat 138 os.system(self._adb('logcat -c')); 139 140 # Regexps for benchmark synchronization 141 start_logline = r'TestRunner: started' 142 UIBENCH_BENCHMARK_START_RE = re.compile(start_logline) 143 self._log.debug("START string [%s]", start_logline) 144 145 finish_logline = r'TestRunner: finished' 146 UIBENCH_BENCHMARK_FINISH_RE = re.compile(finish_logline) 147 self._log.debug("FINISH string [%s]", start_logline) 148 149 # Parse logcat output lines 150 logcat_cmd = self._adb( 151 'logcat TestRunner:* System.out:I *:S BENCH:*'\ 152 .format(self._target.adb_name)) 153 self._log.info("%s", logcat_cmd) 154 155 command = "am instrument -e iterations {} -e class {}{} -w {}".format( 156 iterations, self.test_package, activity, self.test_package) 157 test_proc = self._target.background(command) 158 159 logcat = Popen(logcat_cmd, shell=True, stdout=PIPE) 160 while True: 161 162 # read next logcat line (up to max 1024 chars) 163 message = logcat.stdout.readline(1024) 164 165 # Benchmark start trigger 166 match = UIBENCH_BENCHMARK_START_RE.search(message) 167 if match: 168 self.tracingStart() 169 self._log.debug("Benchmark started!") 170 171 match = UIBENCH_BENCHMARK_FINISH_RE.search(message) 172 if match: 173 self.tracingStop() 174 self._log.debug("Benchmark finished!") 175 test_proc.wait() 176 break 177 178 # Get frame stats 179 self.db_file = os.path.join(out_dir, "framestats.txt") 180 with open(self.db_file, 'w') as f: 181 f.writelines(test_proc.stdout.readlines()) 182 self.results = self.get_results(out_dir) 183 184 # Close and clear application 185 System.force_stop(self._target, self.package, clear=True) 186 187 # Go back to home screen 188 System.home(self._target) 189 190 # Switch back to original settings 191 Screen.set_orientation(self._target, auto=True) 192 System.set_airplane_mode(self._target, on=False) 193 Screen.set_brightness(self._target, auto=True) 194 195 @staticmethod 196 def get_results(res_dir): 197 path = os.path.join(res_dir, 'framestats.txt') 198 with open(path, "r") as f: 199 lines = f.readlines() 200 201 values = [] 202 columns = [] 203 RESULTS_PARSE_RE = re.compile(r'gfx-([^=]+)=([0-9.]+)') 204 for line in lines: 205 matches = RESULTS_PARSE_RE.search(line) 206 if matches: 207 columns.append(matches.group(1)) 208 values.append(float(matches.group(2))) 209 return pd.DataFrame([values], columns=columns) 210 # vim :set tabstop=4 shiftwidth=4 expandtab 211