1#!/usr/bin/env python2 2# 3# Copyright 2017 The Chromium OS Authors. All rights reserved. 4# Use of this source code is governed by a BSD-style license that can be 5# found in the LICENSE file. 6# 7# pylint: disable=cros-logging-import 8 9"""Script to build the benchmark locally with toolchain settings.""" 10from __future__ import print_function 11 12import argparse 13import config 14import logging 15import os 16import subprocess 17import sys 18 19# Turn the logging level to INFO before importing other code, to avoid having 20# failed import logging messages confuse the user. 21logging.basicConfig(level=logging.INFO) 22 23 24def _parse_arguments_internal(argv): 25 parser = argparse.ArgumentParser(description='Build benchmarks with ' 26 'specified toolchain settings') 27 28 parser.add_argument( 29 '-b', '--bench', required=True, help='Select the benchmark to be built.') 30 31 parser.add_argument( 32 '-c', 33 '--compiler_dir', 34 metavar='DIR', 35 help='Specify the path to the compiler bin ' 36 'directory.') 37 38 parser.add_argument( 39 '-o', '--build_os', help='Specify the host OS to build benchmark.') 40 41 parser.add_argument( 42 '-l', 43 '--llvm_prebuilts_version', 44 help='Specify the version of prebuilt LLVM.') 45 46 parser.add_argument( 47 '-f', 48 '--cflags', 49 help='Specify the optimization cflags for ' 50 'the toolchain.') 51 52 parser.add_argument( 53 '--ldflags', help='Specify linker flags for the toolchain.') 54 55 return parser.parse_args(argv) 56 57 58# Set flags for compiling benchmarks, by changing the local 59# CFLAGS/LDFLAGS in the android makefile of each benchmark 60def set_flags(bench, cflags, ldflags): 61 if not cflags: 62 logging.info('No CFLAGS specified, using default settings.') 63 cflags = '' 64 else: 65 logging.info('Cflags setting to "%s"...', cflags) 66 67 if not ldflags: 68 logging.info('No LDFLAGS specifed, using default settings.') 69 ldflags = '' 70 else: 71 logging.info('Ldflags setting to "%s"...', ldflags) 72 73 add_flags = config.bench_flags_dict[bench] 74 add_flags(cflags, ldflags) 75 logging.info('Flags set successfully!') 76 77 78def set_build_os(build_os): 79 # Set $BUILD_OS variable for android makefile 80 if build_os: 81 os.environ['BUILD_OS'] = build_os 82 logging.info('BUILD_OS set to "%s"...', build_os) 83 else: 84 logging.info('No BUILD_OS specified, using linux as default...') 85 86 87def set_llvm_prebuilts_version(llvm_prebuilts_version): 88 # Set $LLVM_PREBUILTS_VERSION for android makefile 89 if llvm_prebuilts_version: 90 os.environ['LLVM_PREBUILTS_VERSION'] = llvm_prebuilts_version 91 logging.info('LLVM_PREBUILTS_VERSION set to "%s"...', 92 llvm_prebuilts_version) 93 else: 94 logging.info('No LLVM_PREBUILTS_VERSION specified, using default one...') 95 96 97def set_compiler(compiler): 98 # If compiler_dir has been specified, copy the binaries to 99 # a temporary location, set BUILD_OS and LLVM_PREBUILTS_VERSION 100 # variables to the location 101 if compiler: 102 # Report error if path not exits 103 if not os.path.isdir(compiler): 104 logging.error('Error while setting compiler: ' 105 'Directory %s does not exist!', compiler) 106 raise OSError('Directory %s not exist.' % compiler) 107 108 # Specify temporary directory for compiler 109 tmp_dir = os.path.join(config.android_home, 110 'prebuilts/clang/host/linux-x86', 'clang-tmp') 111 112 compiler_content = os.path.join(compiler, '.') 113 114 # Copy compiler to new directory 115 try: 116 subprocess.check_call(['cp', '-rf', compiler_content, tmp_dir]) 117 except subprocess.CalledProcessError: 118 logging.error('Error while copying the compiler to ' 119 'temporary directory %s!', tmp_dir) 120 raise 121 122 # Set environment variable 123 os.environ['LLVM_PREBUILTS_VERSION'] = 'clang-tmp' 124 125 logging.info('Prebuilt Compiler set as %s.', os.path.abspath(compiler)) 126 127 128def set_compiler_env(bench, compiler, build_os, llvm_prebuilts_version, cflags, 129 ldflags): 130 logging.info('Setting compiler options for benchmark...') 131 132 # If no specific prebuilt compiler directory, use BUILD_OS and 133 # LLVM_PREBUILTS_VERSION to set the compiler version. 134 # Otherwise, use the new prebuilt compiler. 135 if not compiler: 136 set_build_os(build_os) 137 set_llvm_prebuilts_version(llvm_prebuilts_version) 138 else: 139 set_compiler(compiler) 140 141 set_flags(bench, cflags, ldflags) 142 143 return 0 144 145 146def remove_tmp_dir(): 147 tmp_dir = os.path.join(config.android_home, 'prebuilts/clang/host/linux-x86', 148 'clang-tmp') 149 150 try: 151 subprocess.check_call(['rm', '-r', tmp_dir]) 152 except subprocess.CalledProcessError: 153 logging.error('Error while removing the temporary ' 154 'compiler directory %s!', tmp_dir) 155 raise 156 157 158# Recover the makefile/blueprint from our patch after building 159def restore_makefile(bench): 160 pwd = os.path.join(config.android_home, config.bench_dict[bench]) 161 mk_file = os.path.join(pwd, 'Android.mk') 162 if not os.path.exists(mk_file): 163 mk_file = os.path.join(pwd, 'Android.bp') 164 subprocess.check_call(['mv', os.path.join(pwd, 'tmp_makefile'), mk_file]) 165 166 167# Run script to build benchmark 168def build_bench(bench, source_dir): 169 logging.info('Start building benchmark...') 170 171 raw_cmd = ('cd {android_home} ' 172 '&& source build/envsetup.sh ' 173 '&& lunch {product_combo} ' 174 '&& mmma {source_dir} -j48'.format( 175 android_home=config.android_home, 176 product_combo=config.product_combo, 177 source_dir=source_dir)) 178 179 log_file = os.path.join(config.bench_suite_dir, 'build_log') 180 with open(log_file, 'a') as logfile: 181 log_head = 'Log for building benchmark: %s\n' % (bench) 182 logfile.write(log_head) 183 try: 184 subprocess.check_call( 185 ['bash', '-c', raw_cmd], stdout=logfile, stderr=logfile) 186 except subprocess.CalledProcessError: 187 logging.error('Error while running %s, please check ' 188 '%s for more info.', raw_cmd, log_file) 189 restore_makefile(bench) 190 raise 191 192 logging.info('Logs for building benchmark %s are written to %s.', bench, 193 log_file) 194 logging.info('Benchmark built successfully!') 195 196 197def main(argv): 198 arguments = _parse_arguments_internal(argv) 199 200 bench = arguments.bench 201 compiler = arguments.compiler_dir 202 build_os = arguments.build_os 203 llvm_version = arguments.llvm_prebuilts_version 204 cflags = arguments.cflags 205 ldflags = arguments.ldflags 206 207 try: 208 source_dir = config.bench_dict[bench] 209 except KeyError: 210 logging.error('Please select one benchmark from the list below:\n\t' + 211 '\n\t'.join(config.bench_list)) 212 raise 213 214 set_compiler_env(bench, compiler, build_os, llvm_version, cflags, ldflags) 215 216 build_bench(bench, source_dir) 217 218 # If flags has been set, remember to restore the makefile/blueprint to 219 # original ones. 220 restore_makefile(bench) 221 222 # If a tmp directory is used for compiler path, remove it after building. 223 if compiler: 224 remove_tmp_dir() 225 226 227if __name__ == '__main__': 228 main(sys.argv[1:]) 229