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