| # SPDX-License-Identifier: Apache-2.0 |
| # |
| # Copyright (C) 2017, ARM Limited, Google and contributors. |
| # |
| # Licensed under the Apache License, Version 2.0 (the "License"); you may |
| # not use this file except in compliance with the License. |
| # You may obtain a copy of the License at |
| # |
| # http://www.apache.org/licenses/LICENSE-2.0 |
| # |
| # Unless required by applicable law or agreed to in writing, software |
| # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT |
| # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| # See the License for the specific language governing permissions and |
| # limitations under the License. |
| # |
| |
| import re |
| import os |
| import logging |
| |
| from subprocess import Popen, PIPE |
| from time import sleep |
| |
| from android import Screen, System, Workload |
| |
| import pandas as pd |
| |
| class SystemUi(Workload): |
| """ |
| Android SystemUi jank test workload |
| """ |
| |
| # Packages required by this workload |
| packages = [ |
| Workload.WorkloadPackage("android.platform.systemui.tests.jank", |
| "data/app/UbSystemUiJankTests/UbSystemUiJankTests.apk", |
| "platform_testing/tests/jank/UbSystemUiJankTests") |
| ] |
| |
| # Instrumentation required to run tests |
| test_package = packages[0].package_name |
| |
| test_list = \ |
| ["LauncherJankTests#testOpenAllAppsContainer", |
| "LauncherJankTests#testAllAppsContainerSwipe", |
| "LauncherJankTests#testHomeScreenSwipe", |
| "LauncherJankTests#testWidgetsContainerFling", |
| "SettingsJankTests#testSettingsFling", |
| "SystemUiJankTests#testRecentAppsFling", |
| "SystemUiJankTests#testRecentAppsDismiss", |
| "SystemUiJankTests#testNotificationListPull", |
| "SystemUiJankTests#testNotificationListPull_manyNotifications", |
| "SystemUiJankTests#testQuickSettingsPull", |
| "SystemUiJankTests#testUnlock", |
| "SystemUiJankTests#testExpandGroup", |
| "SystemUiJankTests#testClearAll", |
| "SystemUiJankTests#testChangeBrightness", |
| "SystemUiJankTests#testNotificationAppear", |
| "SystemUiJankTests#testCameraFromLockscreen", |
| "SystemUiJankTests#testAmbientWakeUp", |
| "SystemUiJankTests#testGoToFullShade", |
| "SystemUiJankTests#testInlineReply", |
| "SystemUiJankTests#testPinAppearance", |
| "SystemUiJankTests#testLaunchSettings"] |
| |
| def __init__(self, test_env): |
| super(SystemUi, self).__init__(test_env) |
| self._log = logging.getLogger('SystemUi') |
| self._log.debug('Workload created') |
| |
| # Set of output data reported by SystemUi |
| self.db_file = None |
| |
| def get_test_list(self): |
| return SystemUi.test_list |
| |
| def run(self, out_dir, test_name, iterations, collect=''): |
| """ |
| Run single SystemUi jank test workload. |
| Performance statistics are stored in self.results, and can be retrieved after |
| the fact by calling SystemUi.get_results() |
| |
| :param out_dir: Path to experiment directory where to store results. |
| :type out_dir: str |
| |
| :param test_name: Name of the test to run |
| :type test_name: str |
| |
| :param iterations: Run benchmark for this required number of iterations |
| :type iterations: int |
| |
| :param collect: Specifies what to collect. Possible values: |
| - 'systrace' |
| - 'ftrace' |
| - 'gfxinfo' |
| - 'surfaceflinger' |
| - any combination of the above |
| :type collect: list(str) |
| """ |
| if 'energy' in collect: |
| raise ValueError('SystemUi workload does not support energy data collection') |
| |
| activity = '.' + test_name |
| |
| # Keep track of mandatory parameters |
| self.out_dir = out_dir |
| self.collect = collect |
| |
| # Filter out test overhead |
| filter_prop = System.get_boolean_property(self._target, 'debug.hwui.filter_test_overhead') |
| if not filter_prop: |
| System.set_property(self._target, 'debug.hwui.filter_test_overhead', 'true', restart=True) |
| |
| # Unlock device screen (assume no password required) |
| Screen.unlock(self._target) |
| |
| # Set airplane mode |
| System.set_airplane_mode(self._target, on=True) |
| |
| # Set min brightness |
| Screen.set_brightness(self._target, auto=False, percent=0) |
| |
| # Force screen in PORTRAIT mode |
| Screen.set_orientation(self._target, portrait=True) |
| |
| # Delete old test results |
| self._target.remove('/sdcard/results.log') |
| |
| # Clear logcat |
| os.system(self._adb('logcat -c')); |
| |
| # Regexps for benchmark synchronization |
| start_logline = r'TestRunner: started' |
| SYSTEMUI_BENCHMARK_START_RE = re.compile(start_logline) |
| self._log.debug("START string [%s]", start_logline) |
| |
| finish_logline = r'TestRunner: finished' |
| SYSTEMUI_BENCHMARK_FINISH_RE = re.compile(finish_logline) |
| self._log.debug("FINISH string [%s]", finish_logline) |
| |
| # Parse logcat output lines |
| logcat_cmd = self._adb( |
| 'logcat TestRunner:* System.out:I *:S BENCH:*'\ |
| .format(self._target.adb_name)) |
| self._log.info("%s", logcat_cmd) |
| |
| command = "nohup am instrument -e iterations {} -e class {}{} -w {}".format( |
| iterations, self.test_package, activity, self.test_package) |
| |
| print "command: {}".format(command) |
| |
| self._target.background(command) |
| |
| logcat = Popen(logcat_cmd, shell=True, stdout=PIPE) |
| while True: |
| # read next logcat line (up to max 1024 chars) |
| message = logcat.stdout.readline(1024) |
| |
| # Benchmark start trigger |
| match = SYSTEMUI_BENCHMARK_START_RE.search(message) |
| if match: |
| self.tracingStart() |
| self._log.debug("Benchmark started!") |
| |
| match = SYSTEMUI_BENCHMARK_FINISH_RE.search(message) |
| if match: |
| self.tracingStop() |
| self._log.debug("Benchmark finished!") |
| break |
| |
| sleep(5) |
| self._target.pull('/sdcard/results.log', os.path.join(out_dir, 'results.log')) |
| self._target.remove('/sdcard/results.log') |
| self.results = self.get_results(out_dir) |
| |
| # Go back to home screen |
| System.home(self._target) |
| |
| # Switch back to original settings |
| Screen.set_orientation(self._target, auto=True) |
| System.set_airplane_mode(self._target, on=False) |
| Screen.set_brightness(self._target, auto=True) |
| |
| |
| @staticmethod |
| def get_results(out_dir): |
| """ |
| Parse SystemUi test output log and return a pandas dataframe of test results. |
| |
| :param out_dir: Output directory for a run of the SystemUi workload. |
| :type out_dir: str |
| """ |
| path = os.path.join(out_dir, 'results.log') |
| with open(path, "r") as f: |
| lines = f.readlines() |
| data = {} |
| for line in lines: |
| key, val = str.split(line) |
| if key == 'Result': |
| key = 'test-name' |
| elif key.startswith('gfx-'): |
| key = key[4:] |
| val = float(val) |
| else: |
| raise ValueError('Unrecognized line in results file') |
| data[key] = val |
| columns, values = zip(*((k,v) for k,v in data.iteritems())) |
| return pd.DataFrame([values], columns=columns) |