1#!/usr/bin/python 2 3# Script to generate and collect PGO data based on benchmark 4from __future__ import print_function 5 6import argparse 7import config 8import logging 9import os 10import subprocess 11import sys 12import tempfile 13 14# Turn the logging level to INFO before importing other code, to avoid having 15# failed import logging messages confuse the user. 16logging.basicConfig(level=logging.INFO) 17 18def _parse_arguments_internal(argv): 19 """ 20 Parse command line arguments 21 22 @param argv: argument list to parse 23 24 @returns: tuple of parsed arguments and argv suitable for remote runs 25 26 @raises SystemExit if arguments are malformed, or required arguments 27 are not present. 28 """ 29 30 parser = argparse.ArgumentParser(description='Run this script to collect ' 31 'PGO data.') 32 33 parser.add_argument('-b', '--bench', 34 help='Select which benchmark to collect profdata.') 35 36 parser.add_argument('-d', '--pathDUT', default='/data/local/tmp', 37 help='Specify where to generate PGO data on device, ' 38 'set to /data/local/tmp by default.') 39 40 parser.add_argument('-p', '--path', default=config.bench_suite_dir, 41 help='Specify the location to put the profdata, set ' 42 ' to bench_suite_dir by default.') 43 44 parser.add_argument('-s', '--serial', 45 help='Device serial number.') 46 47 parser.add_argument('-r', '--remote', default='localhost', 48 help='hostname[:port] if the ADB device is connected ' 49 'to a remote machine. Ensure this workstation ' 50 'is configured for passwordless ssh access as ' 51 'users "root" or "adb"') 52 return parser.parse_args(argv) 53 54# Call run.py to build benchmark with -fprofile-generate flags and run on DUT 55def run_suite(bench, serial, remote, pathDUT): 56 logging.info('Build and run instrumented benchmark...') 57 run_cmd = ['./run.py', '-b=' + bench] 58 if serial: 59 run_cmd.append('-s=' + serial) 60 run_cmd.append('-r=' + remote) 61 run_cmd.append('-f=-fprofile-generate=%s' % pathDUT) 62 run_cmd.append('--ldflags=-fprofile-generate=%s' % pathDUT) 63 try: 64 subprocess.check_call(run_cmd) 65 except subprocess.CalledProcessError: 66 logging.error('Error running %s.', run_cmd) 67 raise 68 69# Pull profraw data from device using pull_device.py script in autotest utils. 70def pull_result(bench, serial, remote, pathDUT, path): 71 logging.info('Pulling profraw data from device to local') 72 pull_cmd = [os.path.join(config.android_home, 73 config.autotest_dir, 74 'site_utils/pull_device.py')] 75 pull_cmd.append('-b=' + bench) 76 pull_cmd.append('-r=' + remote) 77 if serial: 78 pull_cmd.append('-s=' + serial) 79 pull_cmd.append('-p=' + path) 80 pull_cmd.append('-d=' + pathDUT) 81 try: 82 subprocess.check_call(pull_cmd) 83 except: 84 logging.error('Error while pulling profraw data.') 85 raise 86 87# Use llvm-profdata tool to convert profraw data to the format llvm can 88# recgonize. 89def merge(bench, pathDUT, path): 90 logging.info('Generate profdata for PGO...') 91 # Untar the compressed rawdata file collected from device 92 tmp_dir = tempfile.mkdtemp() 93 untar_cmd = ['tar', 94 '-xf', 95 os.path.join(path, bench + '_profraw.tar'), 96 '-C', 97 tmp_dir] 98 99 # call llvm-profdata to merge the profraw data 100 profdata = os.path.join(path, bench + '.profdata') 101 merge_cmd = ['llvm-profdata', 102 'merge', 103 '-output=' + profdata, 104 tmp_dir + pathDUT] 105 try: 106 subprocess.check_call(untar_cmd) 107 subprocess.check_call(merge_cmd) 108 logging.info('Profdata is generated successfully, located at %s', 109 profdata) 110 except: 111 logging.error('Error while merging profraw data.') 112 raise 113 finally: 114 subprocess.check_call(['rm', '-rf', tmp_dir]) 115 116def main(argv): 117 """ 118 Entry point for nightly_run script. 119 120 @param argv: arguments list 121 """ 122 arguments = _parse_arguments_internal(argv) 123 124 bench = arguments.bench 125 serial = arguments.serial 126 path = arguments.path 127 remote = arguments.remote 128 129 # Create a profraw directory to collect data 130 pathDUT = os.path.join(arguments.pathDUT, bench + '_profraw') 131 132 run_suite(bench, serial, remote, pathDUT) 133 134 pull_result(bench, serial, remote, pathDUT, path) 135 136 merge(bench, pathDUT, path) 137 138if __name__ == '__main__': 139 main(sys.argv[1:]) 140