|  | #!/usr/bin/env python2 | 
|  | # | 
|  | # Copyright 2017 The Chromium OS Authors. All rights reserved. | 
|  | # Use of this source code is governed by a BSD-style license that can be | 
|  | # found in the LICENSE file. | 
|  | # | 
|  | # pylint: disable=cros-logging-import | 
|  |  | 
|  | """Script to build the benchmark locally with toolchain settings.""" | 
|  | from __future__ import print_function | 
|  |  | 
|  | import argparse | 
|  | import config | 
|  | import logging | 
|  | import os | 
|  | import subprocess | 
|  | import sys | 
|  |  | 
|  | # 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): | 
|  | parser = argparse.ArgumentParser(description='Build benchmarks with ' | 
|  | 'specified toolchain settings') | 
|  |  | 
|  | parser.add_argument( | 
|  | '-b', | 
|  | '--bench', | 
|  | required=True, | 
|  | help='Select the benchmark to be built.') | 
|  |  | 
|  | parser.add_argument( | 
|  | '-c', | 
|  | '--compiler_dir', | 
|  | metavar='DIR', | 
|  | help='Specify the path to the compiler bin ' | 
|  | 'directory.') | 
|  |  | 
|  | parser.add_argument( | 
|  | '-o', | 
|  | '--build_os', | 
|  | help='Specify the host OS to build benchmark.') | 
|  |  | 
|  | parser.add_argument( | 
|  | '-l', | 
|  | '--llvm_prebuilts_version', | 
|  | help='Specify the version of prebuilt LLVM.') | 
|  |  | 
|  | parser.add_argument( | 
|  | '-f', | 
|  | '--cflags', | 
|  | help='Specify the optimization cflags for the toolchain.') | 
|  |  | 
|  | parser.add_argument( | 
|  | '--ldflags', | 
|  | help='Specify linker flags for the toolchain.') | 
|  |  | 
|  | return parser.parse_args(argv) | 
|  |  | 
|  |  | 
|  | # Set flags for compiling benchmarks, by changing the local | 
|  | # CFLAGS/LDFLAGS in the android makefile of each benchmark | 
|  | def set_flags(bench, cflags, ldflags): | 
|  | if not cflags: | 
|  | logging.info('No CFLAGS specified, using default settings.') | 
|  | cflags = '' | 
|  | else: | 
|  | logging.info('Cflags setting to "%s"...', cflags) | 
|  |  | 
|  | if not ldflags: | 
|  | logging.info('No LDFLAGS specifed, using default settings.') | 
|  | ldflags = '' | 
|  | else: | 
|  | logging.info('Ldflags setting to "%s"...', ldflags) | 
|  |  | 
|  | add_flags = config.bench_flags_dict[bench] | 
|  | add_flags(cflags, ldflags) | 
|  | logging.info('Flags set successfully!') | 
|  |  | 
|  |  | 
|  | def set_build_os(build_os): | 
|  | # Set $BUILD_OS variable for android makefile | 
|  | if build_os: | 
|  | os.environ['BUILD_OS'] = build_os | 
|  | logging.info('BUILD_OS set to "%s"...', build_os) | 
|  | else: | 
|  | logging.info('No BUILD_OS specified, using linux as default...') | 
|  |  | 
|  |  | 
|  | def set_llvm_prebuilts_version(llvm_prebuilts_version): | 
|  | # Set $LLVM_PREBUILTS_VERSION for android makefile | 
|  | if llvm_prebuilts_version: | 
|  | os.environ['LLVM_PREBUILTS_VERSION'] = llvm_prebuilts_version | 
|  | logging.info('LLVM_PREBUILTS_VERSION set to "%s"...', | 
|  | llvm_prebuilts_version) | 
|  | else: | 
|  | logging.info('No LLVM_PREBUILTS_VERSION specified, ' | 
|  | 'using default one...') | 
|  |  | 
|  |  | 
|  | def set_compiler(compiler): | 
|  | # If compiler_dir has been specified, copy the binaries to | 
|  | # a temporary location, set BUILD_OS and LLVM_PREBUILTS_VERSION | 
|  | # variables to the location | 
|  | if compiler: | 
|  | # Report error if path not exits | 
|  | if not os.path.isdir(compiler): | 
|  | logging.error('Error while setting compiler: ' | 
|  | 'Directory %s does not exist!', compiler) | 
|  | raise OSError('Directory %s not exist.' % compiler) | 
|  |  | 
|  | # Specify temporary directory for compiler | 
|  | tmp_dir = os.path.join(config.android_home, | 
|  | 'prebuilts/clang/host/linux-x86', 'clang-tmp') | 
|  |  | 
|  | compiler_content = os.path.join(compiler, '.') | 
|  |  | 
|  | # Copy compiler to new directory | 
|  | try: | 
|  | subprocess.check_call(['cp', '-rf', compiler_content, tmp_dir]) | 
|  | except subprocess.CalledProcessError: | 
|  | logging.error('Error while copying the compiler to ' | 
|  | 'temporary directory %s!', tmp_dir) | 
|  | raise | 
|  |  | 
|  | # Set environment variable | 
|  | os.environ['LLVM_PREBUILTS_VERSION'] = 'clang-tmp' | 
|  |  | 
|  | logging.info('Prebuilt Compiler set as %s.', os.path.abspath(compiler)) | 
|  |  | 
|  |  | 
|  | def set_compiler_env(bench, compiler, build_os, llvm_prebuilts_version, cflags, | 
|  | ldflags): | 
|  | logging.info('Setting compiler options for benchmark...') | 
|  |  | 
|  | # If no specific prebuilt compiler directory, use BUILD_OS and | 
|  | # LLVM_PREBUILTS_VERSION to set the compiler version. | 
|  | # Otherwise, use the new prebuilt compiler. | 
|  | if not compiler: | 
|  | set_build_os(build_os) | 
|  | set_llvm_prebuilts_version(llvm_prebuilts_version) | 
|  | else: | 
|  | set_compiler(compiler) | 
|  |  | 
|  | set_flags(bench, cflags, ldflags) | 
|  |  | 
|  | return 0 | 
|  |  | 
|  |  | 
|  | def remove_tmp_dir(): | 
|  | tmp_dir = os.path.join(config.android_home, | 
|  | 'prebuilts/clang/host/linux-x86', | 
|  | 'clang-tmp') | 
|  |  | 
|  | try: | 
|  | subprocess.check_call(['rm', '-r', tmp_dir]) | 
|  | except subprocess.CalledProcessError: | 
|  | logging.error('Error while removing the temporary ' | 
|  | 'compiler directory %s!', tmp_dir) | 
|  | raise | 
|  |  | 
|  |  | 
|  | # Recover the makefile/blueprint from our patch after building | 
|  | def restore_makefile(bench): | 
|  | pwd = os.path.join(config.android_home, config.bench_dict[bench]) | 
|  | mk_file = os.path.join(pwd, 'Android.mk') | 
|  | if not os.path.exists(mk_file): | 
|  | mk_file = os.path.join(pwd, 'Android.bp') | 
|  | subprocess.check_call(['mv', os.path.join(pwd, 'tmp_makefile'), mk_file]) | 
|  |  | 
|  |  | 
|  | # Run script to build benchmark | 
|  | def build_bench(bench, source_dir): | 
|  | logging.info('Start building benchmark...') | 
|  |  | 
|  | raw_cmd = ('cd {android_home} ' | 
|  | '&& source build/envsetup.sh ' | 
|  | '&& lunch {product_combo} ' | 
|  | '&& mmma {source_dir} -j48'.format( | 
|  | android_home=config.android_home, | 
|  | product_combo=config.product_combo, | 
|  | source_dir=source_dir)) | 
|  |  | 
|  | log_file = os.path.join(config.bench_suite_dir, 'build_log') | 
|  | with open(log_file, 'a') as logfile: | 
|  | log_head = 'Log for building benchmark: %s\n' % (bench) | 
|  | logfile.write(log_head) | 
|  | try: | 
|  | subprocess.check_call( | 
|  | ['bash', '-c', raw_cmd], stdout=logfile, stderr=logfile) | 
|  | except subprocess.CalledProcessError: | 
|  | logging.error('Error while running %s, please check ' | 
|  | '%s for more info.', raw_cmd, log_file) | 
|  | restore_makefile(bench) | 
|  | raise | 
|  |  | 
|  | logging.info('Logs for building benchmark %s are written to %s.', | 
|  | bench, log_file) | 
|  | logging.info('Benchmark built successfully!') | 
|  |  | 
|  |  | 
|  | def main(argv): | 
|  | arguments = _parse_arguments_internal(argv) | 
|  |  | 
|  | bench = arguments.bench | 
|  | compiler = arguments.compiler_dir | 
|  | build_os = arguments.build_os | 
|  | llvm_version = arguments.llvm_prebuilts_version | 
|  | cflags = arguments.cflags | 
|  | ldflags = arguments.ldflags | 
|  |  | 
|  | try: | 
|  | source_dir = config.bench_dict[bench] | 
|  | except KeyError: | 
|  | logging.error('Please select one benchmark from the list below:\n\t' + | 
|  | '\n\t'.join(config.bench_list)) | 
|  | raise | 
|  |  | 
|  | set_compiler_env(bench, compiler, build_os, llvm_version, cflags, ldflags) | 
|  |  | 
|  | build_bench(bench, source_dir) | 
|  |  | 
|  | # If flags has been set, remember to restore the makefile/blueprint to | 
|  | # original ones. | 
|  | restore_makefile(bench) | 
|  |  | 
|  | # If a tmp directory is used for compiler path, remove it after building. | 
|  | if compiler: | 
|  | remove_tmp_dir() | 
|  |  | 
|  |  | 
|  | if __name__ == '__main__': | 
|  | main(sys.argv[1:]) |