From e018b265190fb87e0a2971b30500595d36ac9fcf Mon Sep 17 00:00:00 2001 From: Michael McGeagh Date: Mon, 10 Apr 2017 15:41:48 +0100 Subject: [PATCH] gfxinfo: Poll framestats in a thread gfxinfo can be executed with an additional 'framestats' parameter that gives detailed timestamp information for the last 120 frames. Added a new parameter to expose this functionality. As this only captures the last 120 frames, to get all frame data across the workload we need to poll at least every 2 seconds (assuming 60Hz vsync) and append the data to the same file. New start and stop functions for doing this have been added to the workload class, similar to how tracing is currently handled. --- libs/utils/android/system.py | 11 +++++++--- libs/utils/android/workload.py | 29 +++++++++++++++++++++++++ libs/utils/android/workloads/uibench.py | 25 ++++++++++++++++----- 3 files changed, 56 insertions(+), 9 deletions(-) mode change 100644 => 100755 libs/utils/android/system.py mode change 100644 => 100755 libs/utils/android/workload.py diff --git a/libs/utils/android/system.py b/libs/utils/android/system.py old mode 100644 new mode 100755 index 42e8c4dec..1d01b55d5 --- a/libs/utils/android/system.py +++ b/libs/utils/android/system.py @@ -268,7 +268,7 @@ class System(object): target.execute('dumpsys gfxinfo {} reset'.format(apk_name)) @staticmethod - def gfxinfo_get(target, apk_name, out_file): + def gfxinfo_get(target, apk_name, out_file, framestats=False): """ Collect frame statistics for the given app. @@ -280,9 +280,14 @@ class System(object): :param out_file: output file name :type out_file: str + + :param framestats: collect framestats and *append* to out_file + :type framestats: bool """ - adb_command(target.adb_name, - GET_FRAMESTATS_CMD.format(apk_name, out_file)) + cmd = GET_FRAMESTATS_CMD.format(apk_name, out_file) + if framestats: + cmd = cmd.replace('>', 'framestats >>') + adb_command(target.adb_name, cmd) @staticmethod def monkey(target, apk_name, event_count=1): diff --git a/libs/utils/android/workload.py b/libs/utils/android/workload.py old mode 100644 new mode 100755 index 626b65d50..90c2ac393 --- a/libs/utils/android/workload.py +++ b/libs/utils/android/workload.py @@ -18,6 +18,7 @@ import logging import os import re +import threading from . import System @@ -43,6 +44,9 @@ class Workload(object): self.trace_file = None self.nrg_report = None + # Thread used for gfxinfo polling + self.gfxinfo_thread = None + def _adb(self, cmd): return 'adb -s {} {}'.format(self._target.adb_name, cmd) @@ -134,4 +138,29 @@ class Workload(object): # Dump a platform description self._te.platform_dump(self.out_dir) + def gfxinfoStart(self, out_file, timer=2.0): + # Reset gfxinfo + System.gfxinfo_reset(self._target, self.package) + # Remove existing file if it exists as we will be appending + if os.path.isfile(out_file): + os.remove(out_file) + # Create a timer thread to run _gfxinfoPoll every `timer` seconds + # Mark it as a daemon so it can run in the background independently + self.gfxinfo_thread = threading.Timer(timer, self._gfxinfoPoll, (out_file, timer)) + self.gfxinfo_thread.daemon = True + self.gfxinfo_thread.start() + + def gfxinfoStop(self): + # If the timer thread instance exists, issue a cancel command and remove the instance + if self.gfxinfo_thread: + self.gfxinfo_thread.cancel() + self.gfxinfo_thread = None + + def _gfxinfoPoll(self, out_file, timer): + # Run gfxinfo with the framestats parameter, appending to the `out_file` + System.gfxinfo_get(self._target, self.package, out_file, framestats=True) + if self.gfxinfo_thread: + # If the timer thread instance exists, re-run the timer thread again + threading.Timer(timer, self._gfxinfoPoll, (out_file, timer)).start() + # vim :set tabstop=4 shiftwidth=4 expandtab diff --git a/libs/utils/android/workloads/uibench.py b/libs/utils/android/workloads/uibench.py index bdba69fa8..c36d00efe 100755 --- a/libs/utils/android/workloads/uibench.py +++ b/libs/utils/android/workloads/uibench.py @@ -58,7 +58,7 @@ class UiBench(Workload): # Set of output data reported by UiBench self.db_file = None - def run(self, out_dir, test_name, duration_s, collect=''): + def run(self, out_dir, test_name, duration_s, collect='', framestats=False): """ Run single UiBench workload. @@ -77,6 +77,9 @@ class UiBench(Workload): - 'ftrace' - any combination of the above :type collect: list(str) + + :param framestats: poll gfxinfo framestats data + :type framestats: bool """ activity = '.' + test_name @@ -105,8 +108,15 @@ class UiBench(Workload): # Force screen in PORTRAIT mode Screen.set_orientation(self._target, portrait=True) - # Reset frame statistics - System.gfxinfo_reset(self._target, self.package) + # Output file used for gfxinfo + self.db_file = os.path.join(out_dir, "framestats.txt") + + if framestats: + # Begin frame statistics polling + self.gfxinfoStart(self.db_file) + else: + # Reset frame statistics + System.gfxinfo_reset(self._target, self.package) sleep(1) # Clear logcat @@ -147,9 +157,12 @@ class UiBench(Workload): self._log.debug("Benchmark done!") self.tracingStop() - # Get frame stats - self.db_file = os.path.join(out_dir, "framestats.txt") - System.gfxinfo_get(self._target, self.package, self.db_file) + if framestats: + # End frame statistics polling + self.gfxinfoStop() + else: + # Get frame stats + System.gfxinfo_get(self._target, self.package, self.db_file) # Close and clear application System.force_stop(self._target, self.package, clear=True) -- GitLab