Skip to content

Instantly share code, notes, and snippets.

@jimporter
Last active March 4, 2020 21:31
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jimporter/8f4f14a0cbf7554fe41a4bfcbf30ef0f to your computer and use it in GitHub Desktop.
Save jimporter/8f4f14a0cbf7554fe41a4bfcbf30ef0f to your computer and use it in GitHub Desktop.
Get startup "fully drawn" numbers for several Fenix runs
#!/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