普通文本  |  140行  |  4.63 KB

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