| #!/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:]) |