1*a65addddSAndroid Build Coastguard Worker#!/usr/bin/env python3 2*a65addddSAndroid Build Coastguard Worker# Copyright 2016 Google Inc. All Rights Reserved. 3*a65addddSAndroid Build Coastguard Worker# 4*a65addddSAndroid Build Coastguard Worker# Licensed under the Apache License, Version 2.0 (the "License"); 5*a65addddSAndroid Build Coastguard Worker# you may not use this file except in compliance with the License. 6*a65addddSAndroid Build Coastguard Worker# You may obtain a copy of the License at 7*a65addddSAndroid Build Coastguard Worker# 8*a65addddSAndroid Build Coastguard Worker# http://www.apache.org/licenses/LICENSE-2.0 9*a65addddSAndroid Build Coastguard Worker# 10*a65addddSAndroid Build Coastguard Worker# Unless required by applicable law or agreed to in writing, software 11*a65addddSAndroid Build Coastguard Worker# distributed under the License is distributed on an "AS-IS" BASIS, 12*a65addddSAndroid Build Coastguard Worker# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13*a65addddSAndroid Build Coastguard Worker# See the License for the specific language governing permissions and 14*a65addddSAndroid Build Coastguard Worker# limitations under the License. 15*a65addddSAndroid Build Coastguard Worker 16*a65addddSAndroid Build Coastguard Workerimport random 17*a65addddSAndroid Build Coastguard Workerimport os 18*a65addddSAndroid Build Coastguard Worker 19*a65addddSAndroid Build Coastguard Workerimport fruit_source_generator 20*a65addddSAndroid Build Coastguard Workerimport boost_di_source_generator 21*a65addddSAndroid Build Coastguard Workerimport no_di_library_source_generator 22*a65addddSAndroid Build Coastguard Workerfrom makefile_generator import generate_makefile 23*a65addddSAndroid Build Coastguard Workerimport argparse 24*a65addddSAndroid Build Coastguard Workerimport networkx as nx 25*a65addddSAndroid Build Coastguard Worker 26*a65addddSAndroid Build Coastguard Worker 27*a65addddSAndroid Build Coastguard Workerdef generate_injection_graph(num_components_with_no_deps: int, 28*a65addddSAndroid Build Coastguard Worker num_components_with_deps: int, 29*a65addddSAndroid Build Coastguard Worker num_deps: int): 30*a65addddSAndroid Build Coastguard Worker injection_graph = nx.DiGraph() 31*a65addddSAndroid Build Coastguard Worker 32*a65addddSAndroid Build Coastguard Worker num_used_ids = 0 33*a65addddSAndroid Build Coastguard Worker is_toplevel = [True for i in range(0, num_components_with_no_deps + num_components_with_deps)] 34*a65addddSAndroid Build Coastguard Worker toplevel_components = set() 35*a65addddSAndroid Build Coastguard Worker for i in range(0, num_components_with_no_deps): 36*a65addddSAndroid Build Coastguard Worker id = num_used_ids 37*a65addddSAndroid Build Coastguard Worker num_used_ids += 1 38*a65addddSAndroid Build Coastguard Worker toplevel_components.add(id) 39*a65addddSAndroid Build Coastguard Worker 40*a65addddSAndroid Build Coastguard Worker # Then the rest have num_deps deps, chosen (pseudo-)randomly from the previous components. 41*a65addddSAndroid Build Coastguard Worker # The last few components depend more components with >1 deps, so that the last component transitively depends on 42*a65addddSAndroid Build Coastguard Worker # everything. 43*a65addddSAndroid Build Coastguard Worker for i in range(0, num_components_with_deps): 44*a65addddSAndroid Build Coastguard Worker deps = set() 45*a65addddSAndroid Build Coastguard Worker 46*a65addddSAndroid Build Coastguard Worker if len(toplevel_components) > (num_components_with_deps - 1 - i) * (num_deps - 1): 47*a65addddSAndroid Build Coastguard Worker # We need at least 1 dep with deps, otherwise the last few components will not be enough 48*a65addddSAndroid Build Coastguard Worker # to tie together all components. 49*a65addddSAndroid Build Coastguard Worker num_deps_with_deps = len(toplevel_components) - (num_components_with_deps - 1 - i) * (num_deps - 1) 50*a65addddSAndroid Build Coastguard Worker deps |= set(random.sample(toplevel_components, num_deps_with_deps)) 51*a65addddSAndroid Build Coastguard Worker 52*a65addddSAndroid Build Coastguard Worker # Add other deps to get to the desired num_deps. 53*a65addddSAndroid Build Coastguard Worker deps |= set(random.sample(range(0, num_components_with_no_deps + i), num_deps - len(deps))) 54*a65addddSAndroid Build Coastguard Worker 55*a65addddSAndroid Build Coastguard Worker toplevel_components -= deps 56*a65addddSAndroid Build Coastguard Worker for dep in deps: 57*a65addddSAndroid Build Coastguard Worker is_toplevel[dep] = False 58*a65addddSAndroid Build Coastguard Worker 59*a65addddSAndroid Build Coastguard Worker component_id = num_used_ids 60*a65addddSAndroid Build Coastguard Worker toplevel_components |= {component_id} 61*a65addddSAndroid Build Coastguard Worker num_used_ids += 1 62*a65addddSAndroid Build Coastguard Worker deps_list = list(deps) 63*a65addddSAndroid Build Coastguard Worker random.shuffle(deps_list) 64*a65addddSAndroid Build Coastguard Worker for dep in deps_list: 65*a65addddSAndroid Build Coastguard Worker injection_graph.add_edge(component_id, dep) 66*a65addddSAndroid Build Coastguard Worker 67*a65addddSAndroid Build Coastguard Worker assert len(toplevel_components) == 1, toplevel_components 68*a65addddSAndroid Build Coastguard Worker toplevel_component = num_used_ids - 1 69*a65addddSAndroid Build Coastguard Worker assert is_toplevel[toplevel_component] 70*a65addddSAndroid Build Coastguard Worker 71*a65addddSAndroid Build Coastguard Worker return injection_graph 72*a65addddSAndroid Build Coastguard Worker 73*a65addddSAndroid Build Coastguard Workerdef generate_benchmark( 74*a65addddSAndroid Build Coastguard Worker di_library: str, 75*a65addddSAndroid Build Coastguard Worker compiler: str, 76*a65addddSAndroid Build Coastguard Worker cxx_std: str, 77*a65addddSAndroid Build Coastguard Worker output_dir: str, 78*a65addddSAndroid Build Coastguard Worker num_components_with_no_deps: int, 79*a65addddSAndroid Build Coastguard Worker num_components_with_deps: int, 80*a65addddSAndroid Build Coastguard Worker num_deps: int, 81*a65addddSAndroid Build Coastguard Worker generate_runtime_bench_code: bool, 82*a65addddSAndroid Build Coastguard Worker use_exceptions: bool=True, 83*a65addddSAndroid Build Coastguard Worker use_rtti: bool=True, 84*a65addddSAndroid Build Coastguard Worker fruit_build_dir: str=None, 85*a65addddSAndroid Build Coastguard Worker fruit_sources_dir: str=None, 86*a65addddSAndroid Build Coastguard Worker boost_di_sources_dir: str=None, 87*a65addddSAndroid Build Coastguard Worker generate_debuginfo: bool=False, 88*a65addddSAndroid Build Coastguard Worker use_new_delete: bool=False, 89*a65addddSAndroid Build Coastguard Worker use_interfaces: bool=False, 90*a65addddSAndroid Build Coastguard Worker use_normalized_component: bool=False): 91*a65addddSAndroid Build Coastguard Worker """Generates a sample codebase using the specified DI library, meant for benchmarking. 92*a65addddSAndroid Build Coastguard Worker 93*a65addddSAndroid Build Coastguard Worker :param boost_di_sources_dir: this is only used if di_library=='boost_di', it can be None otherwise. 94*a65addddSAndroid Build Coastguard Worker """ 95*a65addddSAndroid Build Coastguard Worker 96*a65addddSAndroid Build Coastguard Worker if num_components_with_no_deps < num_deps: 97*a65addddSAndroid Build Coastguard Worker raise Exception( 98*a65addddSAndroid Build Coastguard Worker "Too few components with no deps. num_components_with_no_deps=%s but num_deps=%s." % (num_components_with_no_deps, num_deps)) 99*a65addddSAndroid Build Coastguard Worker if num_deps < 2: 100*a65addddSAndroid Build Coastguard Worker raise Exception("num_deps should be at least 2.") 101*a65addddSAndroid Build Coastguard Worker 102*a65addddSAndroid Build Coastguard Worker # This is a constant so that we always generate the same file (=> benchmark more repeatable). 103*a65addddSAndroid Build Coastguard Worker random.seed(42) 104*a65addddSAndroid Build Coastguard Worker 105*a65addddSAndroid Build Coastguard Worker injection_graph = generate_injection_graph(num_components_with_no_deps=num_components_with_no_deps, 106*a65addddSAndroid Build Coastguard Worker num_components_with_deps=num_components_with_deps, 107*a65addddSAndroid Build Coastguard Worker num_deps=num_deps) 108*a65addddSAndroid Build Coastguard Worker 109*a65addddSAndroid Build Coastguard Worker if di_library == 'fruit': 110*a65addddSAndroid Build Coastguard Worker file_content_by_name = fruit_source_generator.generate_files(injection_graph, generate_runtime_bench_code) 111*a65addddSAndroid Build Coastguard Worker include_dirs = [fruit_build_dir + '/include', fruit_sources_dir + '/include'] 112*a65addddSAndroid Build Coastguard Worker library_dirs = [fruit_build_dir + '/src'] 113*a65addddSAndroid Build Coastguard Worker link_libraries = ['fruit'] 114*a65addddSAndroid Build Coastguard Worker elif di_library == 'boost_di': 115*a65addddSAndroid Build Coastguard Worker file_content_by_name = boost_di_source_generator.generate_files(injection_graph, generate_runtime_bench_code) 116*a65addddSAndroid Build Coastguard Worker include_dirs = [boost_di_sources_dir + '/include', boost_di_sources_dir + '/extension/include'] 117*a65addddSAndroid Build Coastguard Worker library_dirs = [] 118*a65addddSAndroid Build Coastguard Worker link_libraries = [] 119*a65addddSAndroid Build Coastguard Worker elif di_library == 'none': 120*a65addddSAndroid Build Coastguard Worker file_content_by_name = no_di_library_source_generator.generate_files(injection_graph, use_new_delete, use_interfaces, generate_runtime_bench_code) 121*a65addddSAndroid Build Coastguard Worker include_dirs = [] 122*a65addddSAndroid Build Coastguard Worker library_dirs = [] 123*a65addddSAndroid Build Coastguard Worker link_libraries = [] 124*a65addddSAndroid Build Coastguard Worker else: 125*a65addddSAndroid Build Coastguard Worker raise Exception('Unrecognized di_library: %s' % di_library) 126*a65addddSAndroid Build Coastguard Worker 127*a65addddSAndroid Build Coastguard Worker include_flags = ' '.join(['-I%s' % include_dir for include_dir in include_dirs]) 128*a65addddSAndroid Build Coastguard Worker library_dirs_flags = ' '.join(['-L%s' % library_dir for library_dir in library_dirs]) 129*a65addddSAndroid Build Coastguard Worker rpath_flags = ' '.join(['-Wl,-rpath,%s' % library_dir for library_dir in library_dirs]) 130*a65addddSAndroid Build Coastguard Worker link_libraries_flags = ' '.join(['-l%s' % library for library in link_libraries]) 131*a65addddSAndroid Build Coastguard Worker other_compile_flags = [] 132*a65addddSAndroid Build Coastguard Worker if generate_debuginfo: 133*a65addddSAndroid Build Coastguard Worker other_compile_flags.append('-g') 134*a65addddSAndroid Build Coastguard Worker if not use_exceptions: 135*a65addddSAndroid Build Coastguard Worker other_compile_flags.append('-fno-exceptions') 136*a65addddSAndroid Build Coastguard Worker if not use_rtti: 137*a65addddSAndroid Build Coastguard Worker other_compile_flags.append('-fno-rtti') 138*a65addddSAndroid Build Coastguard Worker compile_command = '%s -std=%s -MMD -MP -O2 -W -Wall -DNDEBUG -ftemplate-depth=10000 %s %s' % (compiler, cxx_std, include_flags, ' '.join(other_compile_flags)) 139*a65addddSAndroid Build Coastguard Worker link_command = '%s -std=%s -O2 -W -Wall %s %s' % (compiler, cxx_std, rpath_flags, library_dirs_flags) 140*a65addddSAndroid Build Coastguard Worker # GCC requires passing the -lfruit flag *after* all object files to be linked for some reason. 141*a65addddSAndroid Build Coastguard Worker link_command_suffix = link_libraries_flags 142*a65addddSAndroid Build Coastguard Worker 143*a65addddSAndroid Build Coastguard Worker cpp_files = [file_name 144*a65addddSAndroid Build Coastguard Worker for file_name in file_content_by_name.keys() 145*a65addddSAndroid Build Coastguard Worker if file_name.endswith('.cpp')] 146*a65addddSAndroid Build Coastguard Worker 147*a65addddSAndroid Build Coastguard Worker file_content_by_name['Makefile'] = generate_makefile(cpp_files, 'main', compile_command, link_command, link_command_suffix) 148*a65addddSAndroid Build Coastguard Worker 149*a65addddSAndroid Build Coastguard Worker os.makedirs(output_dir, exist_ok=True) 150*a65addddSAndroid Build Coastguard Worker for file_name, file_content in file_content_by_name.items(): 151*a65addddSAndroid Build Coastguard Worker with open('%s/%s' % (output_dir, file_name), 'w') as file: 152*a65addddSAndroid Build Coastguard Worker file.write(file_content) 153*a65addddSAndroid Build Coastguard Worker 154*a65addddSAndroid Build Coastguard Worker return file_content_by_name.keys() 155*a65addddSAndroid Build Coastguard Worker 156*a65addddSAndroid Build Coastguard Workerdef main(): 157*a65addddSAndroid Build Coastguard Worker parser = argparse.ArgumentParser(description='Generates source files and a build script for benchmarks.') 158*a65addddSAndroid Build Coastguard Worker parser.add_argument('--di-library', default='fruit', help='DI library to use. One of {fruit, boost_di, none}. (default: fruit)') 159*a65addddSAndroid Build Coastguard Worker parser.add_argument('--compiler', help='Compiler to use') 160*a65addddSAndroid Build Coastguard Worker parser.add_argument('--fruit-sources-dir', help='Path to the fruit sources (only used when di_library==\'fruit\')') 161*a65addddSAndroid Build Coastguard Worker parser.add_argument('--fruit-build-dir', help='Path to the fruit build dir (only used with --di_library=\'fruit\')') 162*a65addddSAndroid Build Coastguard Worker parser.add_argument('--boost-di-sources-dir', help='Path to the Boost.DI sources (only used with --di-library==\'boost_di\')') 163*a65addddSAndroid Build Coastguard Worker parser.add_argument('--num-components-with-no-deps', default=10, help='Number of components with no deps that will be generated') 164*a65addddSAndroid Build Coastguard Worker parser.add_argument('--num-components-with-deps', default=90, help='Number of components with deps that will be generated') 165*a65addddSAndroid Build Coastguard Worker parser.add_argument('--num-deps', default=10, help='Number of deps in each component with deps that will be generated') 166*a65addddSAndroid Build Coastguard Worker parser.add_argument('--output-dir', help='Output directory for generated files') 167*a65addddSAndroid Build Coastguard Worker parser.add_argument('--cxx-std', default='c++11', 168*a65addddSAndroid Build Coastguard Worker help='Version of the C++ standard to use. Typically one of \'c++11\' and \'c++14\'. (default: \'c++11\')') 169*a65addddSAndroid Build Coastguard Worker parser.add_argument('--use-new-delete', default='false', help='Set this to \'true\' to use new/delete. Only relevant when --di_library=none.') 170*a65addddSAndroid Build Coastguard Worker parser.add_argument('--use-interfaces', default='false', help='Set this to \'true\' to use interfaces. Only relevant when --di_library=none.') 171*a65addddSAndroid Build Coastguard Worker parser.add_argument('--use-normalized-component', default='false', help='Set this to \'true\' to create a NormalizedComponent and create the injector from that. Only relevant when --di_library=fruit and --generate-runtime-bench-code=false.') 172*a65addddSAndroid Build Coastguard Worker parser.add_argument('--generate-runtime-bench-code', default='true', help='Set this to \'false\' for compile benchmarks.') 173*a65addddSAndroid Build Coastguard Worker parser.add_argument('--generate-debuginfo', default='false', help='Set this to \'true\' to generate debugging information (-g).') 174*a65addddSAndroid Build Coastguard Worker parser.add_argument('--use-exceptions', default='true', help='Set this to \'false\' to disable exceptions.') 175*a65addddSAndroid Build Coastguard Worker parser.add_argument('--use-rtti', default='true', help='Set this to \'false\' to disable RTTI.') 176*a65addddSAndroid Build Coastguard Worker 177*a65addddSAndroid Build Coastguard Worker args = parser.parse_args() 178*a65addddSAndroid Build Coastguard Worker 179*a65addddSAndroid Build Coastguard Worker if args.compiler is None: 180*a65addddSAndroid Build Coastguard Worker raise Exception('--compiler is required.') 181*a65addddSAndroid Build Coastguard Worker 182*a65addddSAndroid Build Coastguard Worker if args.di_library == 'fruit': 183*a65addddSAndroid Build Coastguard Worker if args.fruit_sources_dir is None: 184*a65addddSAndroid Build Coastguard Worker raise Exception('--fruit-sources-dir is required with --di-library=\'fruit\'.') 185*a65addddSAndroid Build Coastguard Worker if args.fruit_build_dir is None: 186*a65addddSAndroid Build Coastguard Worker raise Exception('--fruit-build-dir is required with --di-library=\'fruit\'.') 187*a65addddSAndroid Build Coastguard Worker elif args.di_library == 'boost_di': 188*a65addddSAndroid Build Coastguard Worker if args.boost_di_sources_dir is None: 189*a65addddSAndroid Build Coastguard Worker raise Exception('--boost-di-sources-dir is required with --di-library=\'boost_di\'.') 190*a65addddSAndroid Build Coastguard Worker elif args.di_library == 'none': 191*a65addddSAndroid Build Coastguard Worker pass 192*a65addddSAndroid Build Coastguard Worker else: 193*a65addddSAndroid Build Coastguard Worker raise Exception('Unrecognized --di-library: \'%s\'. Allowed values are %s' % (args.di_library, {'fruit', 'boost_di', 'none'})) 194*a65addddSAndroid Build Coastguard Worker 195*a65addddSAndroid Build Coastguard Worker num_components_with_deps = int(args.num_components_with_deps) 196*a65addddSAndroid Build Coastguard Worker num_components_with_no_deps = int(args.num_components_with_no_deps) 197*a65addddSAndroid Build Coastguard Worker num_deps = int(args.num_deps) 198*a65addddSAndroid Build Coastguard Worker 199*a65addddSAndroid Build Coastguard Worker if args.output_dir is None: 200*a65addddSAndroid Build Coastguard Worker raise Exception("output_dir must be specified.") 201*a65addddSAndroid Build Coastguard Worker 202*a65addddSAndroid Build Coastguard Worker generate_benchmark( 203*a65addddSAndroid Build Coastguard Worker di_library=args.di_library, 204*a65addddSAndroid Build Coastguard Worker fruit_sources_dir=args.fruit_sources_dir, 205*a65addddSAndroid Build Coastguard Worker boost_di_sources_dir=args.boost_di_sources_dir, 206*a65addddSAndroid Build Coastguard Worker output_dir=args.output_dir, 207*a65addddSAndroid Build Coastguard Worker compiler=args.compiler, 208*a65addddSAndroid Build Coastguard Worker cxx_std=args.cxx_std, 209*a65addddSAndroid Build Coastguard Worker num_components_with_deps=num_components_with_deps, 210*a65addddSAndroid Build Coastguard Worker num_components_with_no_deps=num_components_with_no_deps, 211*a65addddSAndroid Build Coastguard Worker fruit_build_dir=args.fruit_build_dir, 212*a65addddSAndroid Build Coastguard Worker num_deps=num_deps, 213*a65addddSAndroid Build Coastguard Worker generate_debuginfo=(args.generate_debuginfo == 'true'), 214*a65addddSAndroid Build Coastguard Worker use_new_delete=(args.use_new_delete == 'true'), 215*a65addddSAndroid Build Coastguard Worker use_interfaces=(args.use_interfaces == 'true'), 216*a65addddSAndroid Build Coastguard Worker use_normalized_component=(args.use_normalized_component == 'true'), 217*a65addddSAndroid Build Coastguard Worker generate_runtime_bench_code=(args.generate_runtime_bench_code == 'true'), 218*a65addddSAndroid Build Coastguard Worker use_exceptions=(args.use_exceptions == 'true'), 219*a65addddSAndroid Build Coastguard Worker use_rtti=(args.use_rtti == 'true')) 220*a65addddSAndroid Build Coastguard Worker 221*a65addddSAndroid Build Coastguard Worker 222*a65addddSAndroid Build Coastguard Workerif __name__ == "__main__": 223*a65addddSAndroid Build Coastguard Worker main() 224