Last active
March 4, 2020 21:31
-
-
Save jimporter/8f4f14a0cbf7554fe41a4bfcbf30ef0f to your computer and use it in GitHub Desktop.
Get startup "fully drawn" numbers for several Fenix runs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python3 | |
import argparse | |
import json | |
import re | |
import statistics | |
import subprocess | |
import sys | |
import textwrap | |
import time | |
def quiet_call(args): | |
subprocess.check_call(args, stdout=subprocess.DEVNULL, | |
stderr=subprocess.DEVNULL) | |
def reset_fenix(app_name): | |
quiet_call(['adb', 'shell', 'pm', 'clear', app_name]) | |
def stop_fenix(app_name): | |
quiet_call(['adb', 'shell', 'am', 'force-stop', app_name]) | |
def start_fenix(app_name, page=None): | |
if page is None: | |
component_name = app_name + '/.App' | |
quiet_call([ | |
'adb', 'shell', 'am', 'start', | |
'-c', 'android.intent.category.LAUNCHER', | |
'-a', 'android.intent.action.MAIN', | |
'-n', component_name, | |
'--ez', 'performancetest', 'true' | |
]) | |
else: | |
component_name = app_name + '/org.mozilla.fenix.HomeActivity' | |
quiet_call([ | |
'adb', 'shell', 'am', 'start-activity', | |
'-t', 'text/html', '-d', page, | |
'-a', 'android.intent.action.VIEW', | |
app_name + '/org.mozilla.fenix.IntentReceiverActivity', | |
'--ez', 'performancetest', 'true' | |
]) | |
return component_name | |
def clear_logcat(): | |
quiet_call(['adb', 'logcat', '-c']) | |
def get_drawn_time(component_name): | |
logcat = subprocess.check_output([ | |
'adb', 'logcat', '-d' | |
], universal_newlines=True, stderr=subprocess.STDOUT) | |
for line in logcat.split('\n'): | |
if 'Fully drawn {}'.format(component_name) in line: | |
m = re.search(r""" | |
\+ # The leading '+' before the time | |
(?:(\d+)s)? # The seconds part of the time, if any | |
(?:(\d+)ms)? # The milliseconds part of the time, if any | |
\)?$ # The end of the line, maybe with a closing paren | |
""", line, re.VERBOSE) | |
if not m: | |
raise ValueError('unparseable line: {}\n'.format(line)) | |
return float(m.group(1) or 0) + float(m.group(2) or 0) / 1000 | |
raise ValueError('unable to find drawn time') | |
if __name__ == '__main__': | |
parser = argparse.ArgumentParser() | |
parser.add_argument('-n', '--num', type=int, default=10, metavar='N', | |
help='number of test runs (default: %(default)s)') | |
parser.add_argument('-S', '--start-time', type=float, default=3.0, | |
metavar='T', help=( | |
'time to wait after killing process, in seconds ' + | |
'(default: %(default)s)' | |
)) | |
parser.add_argument('-K', '--kill-time', type=float, default=1.0, | |
metavar='T', help=( | |
'time to wait for startup, in seconds ' + | |
'(default: %(default)s)' | |
)) | |
parser.add_argument('-s', '--skip', type=int, default=1, metavar='N', | |
help='number of test runs to skip before recording') | |
parser.add_argument('-p', '--page', metavar='URL', | |
help='page to load for app-link') | |
parser.add_argument('--no-reset', action='store_true', | |
help='preserve existing app data') | |
parser.add_argument('-j', '--json', action='store_true', | |
help='output results as JSON') | |
parser.add_argument('name', nargs='?', default='org.mozilla.fenix.beta', | |
help='application name (default: %(default)s)') | |
args = parser.parse_args() | |
results = [] | |
if not args.no_reset: | |
reset_fenix(args.name) | |
for i in range(args.num + args.skip): | |
if i < args.skip: | |
print('Pre run {}/{}... '.format(i + 1, args.skip), end='\r', | |
file=sys.stderr) | |
else: | |
print('Test run {}/{}... '.format(i + 1 - args.skip, args.num), | |
end='\r', file=sys.stderr) | |
clear_logcat() | |
stop_fenix(args.name) | |
time.sleep(args.kill_time) | |
finish_onboarding = i == 0 and args.skip > 0 | |
component_name = start_fenix(args.name, args.page, finish_onboarding) | |
time.sleep(args.start_time) | |
if i >= args.skip: | |
try: | |
results.append(get_drawn_time(component_name)) | |
except ValueError: | |
print('Failed to find launch time for run {}'.format( | |
i + 1 - args.skip | |
), file=sys.stderr) | |
print('Completed {} test runs! \n'.format(args.num), file=sys.stderr) | |
if args.json: | |
print(json.dumps(results)) | |
else: | |
print('Mean (s): {:0.3f}'.format(statistics.mean(results))) | |
print('Std Dev: {:0.3f}'.format(statistics.stdev(results))) | |
results_lines = textwrap.wrap(', '.join( | |
'{:0.3f}'.format(i) for i in results | |
)) | |
if len(results_lines) == 1: | |
print('Results: {}'.format(results_lines[0])) | |
else: | |
print('Results:\n{}'.format(textwrap.indent( | |
'\n'.join(results_lines), ' ') | |
)) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment