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