140 lines
4.6 KiB
Python
140 lines
4.6 KiB
Python
|
#!/usr/bin/python
|
||
|
|
||
|
# Script to generate and collect PGO data based on benchmark
|
||
|
from __future__ import print_function
|
||
|
|
||
|
import argparse
|
||
|
import config
|
||
|
import logging
|
||
|
import os
|
||
|
import subprocess
|
||
|
import sys
|
||
|
import tempfile
|
||
|
|
||
|
# Turn the logging level to INFO before importing other code, to avoid having
|
||
|
# failed import logging messages confuse the user.
|
||
|
logging.basicConfig(level=logging.INFO)
|
||
|
|
||
|
def _parse_arguments_internal(argv):
|
||
|
"""
|
||
|
Parse command line arguments
|
||
|
|
||
|
@param argv: argument list to parse
|
||
|
|
||
|
@returns: tuple of parsed arguments and argv suitable for remote runs
|
||
|
|
||
|
@raises SystemExit if arguments are malformed, or required arguments
|
||
|
are not present.
|
||
|
"""
|
||
|
|
||
|
parser = argparse.ArgumentParser(description='Run this script to collect '
|
||
|
'PGO data.')
|
||
|
|
||
|
parser.add_argument('-b', '--bench',
|
||
|
help='Select which benchmark to collect profdata.')
|
||
|
|
||
|
parser.add_argument('-d', '--pathDUT', default='/data/local/tmp',
|
||
|
help='Specify where to generate PGO data on device, '
|
||
|
'set to /data/local/tmp by default.')
|
||
|
|
||
|
parser.add_argument('-p', '--path', default=config.bench_suite_dir,
|
||
|
help='Specify the location to put the profdata, set '
|
||
|
' to bench_suite_dir by default.')
|
||
|
|
||
|
parser.add_argument('-s', '--serial',
|
||
|
help='Device serial number.')
|
||
|
|
||
|
parser.add_argument('-r', '--remote', default='localhost',
|
||
|
help='hostname[:port] if the ADB device is connected '
|
||
|
'to a remote machine. Ensure this workstation '
|
||
|
'is configured for passwordless ssh access as '
|
||
|
'users "root" or "adb"')
|
||
|
return parser.parse_args(argv)
|
||
|
|
||
|
# Call run.py to build benchmark with -fprofile-generate flags and run on DUT
|
||
|
def run_suite(bench, serial, remote, pathDUT):
|
||
|
logging.info('Build and run instrumented benchmark...')
|
||
|
run_cmd = ['./run.py', '-b=' + bench]
|
||
|
if serial:
|
||
|
run_cmd.append('-s=' + serial)
|
||
|
run_cmd.append('-r=' + remote)
|
||
|
run_cmd.append('-f=-fprofile-generate=%s' % pathDUT)
|
||
|
run_cmd.append('--ldflags=-fprofile-generate=%s' % pathDUT)
|
||
|
try:
|
||
|
subprocess.check_call(run_cmd)
|
||
|
except subprocess.CalledProcessError:
|
||
|
logging.error('Error running %s.', run_cmd)
|
||
|
raise
|
||
|
|
||
|
# Pull profraw data from device using pull_device.py script in autotest utils.
|
||
|
def pull_result(bench, serial, remote, pathDUT, path):
|
||
|
logging.info('Pulling profraw data from device to local')
|
||
|
pull_cmd = [os.path.join(config.android_home,
|
||
|
config.autotest_dir,
|
||
|
'site_utils/pull_device.py')]
|
||
|
pull_cmd.append('-b=' + bench)
|
||
|
pull_cmd.append('-r=' + remote)
|
||
|
if serial:
|
||
|
pull_cmd.append('-s=' + serial)
|
||
|
pull_cmd.append('-p=' + path)
|
||
|
pull_cmd.append('-d=' + pathDUT)
|
||
|
try:
|
||
|
subprocess.check_call(pull_cmd)
|
||
|
except:
|
||
|
logging.error('Error while pulling profraw data.')
|
||
|
raise
|
||
|
|
||
|
# Use llvm-profdata tool to convert profraw data to the format llvm can
|
||
|
# recgonize.
|
||
|
def merge(bench, pathDUT, path):
|
||
|
logging.info('Generate profdata for PGO...')
|
||
|
# Untar the compressed rawdata file collected from device
|
||
|
tmp_dir = tempfile.mkdtemp()
|
||
|
untar_cmd = ['tar',
|
||
|
'-xf',
|
||
|
os.path.join(path, bench + '_profraw.tar'),
|
||
|
'-C',
|
||
|
tmp_dir]
|
||
|
|
||
|
# call llvm-profdata to merge the profraw data
|
||
|
profdata = os.path.join(path, bench + '.profdata')
|
||
|
merge_cmd = ['llvm-profdata',
|
||
|
'merge',
|
||
|
'-output=' + profdata,
|
||
|
tmp_dir + pathDUT]
|
||
|
try:
|
||
|
subprocess.check_call(untar_cmd)
|
||
|
subprocess.check_call(merge_cmd)
|
||
|
logging.info('Profdata is generated successfully, located at %s',
|
||
|
profdata)
|
||
|
except:
|
||
|
logging.error('Error while merging profraw data.')
|
||
|
raise
|
||
|
finally:
|
||
|
subprocess.check_call(['rm', '-rf', tmp_dir])
|
||
|
|
||
|
def main(argv):
|
||
|
"""
|
||
|
Entry point for nightly_run script.
|
||
|
|
||
|
@param argv: arguments list
|
||
|
"""
|
||
|
arguments = _parse_arguments_internal(argv)
|
||
|
|
||
|
bench = arguments.bench
|
||
|
serial = arguments.serial
|
||
|
path = arguments.path
|
||
|
remote = arguments.remote
|
||
|
|
||
|
# Create a profraw directory to collect data
|
||
|
pathDUT = os.path.join(arguments.pathDUT, bench + '_profraw')
|
||
|
|
||
|
run_suite(bench, serial, remote, pathDUT)
|
||
|
|
||
|
pull_result(bench, serial, remote, pathDUT, path)
|
||
|
|
||
|
merge(bench, pathDUT, path)
|
||
|
|
||
|
if __name__ == '__main__':
|
||
|
main(sys.argv[1:])
|