def compile_file(f_root, srcdir, bindir, suffix='.c'): """Compile a single C or assembler file, with the given file root, "f_root", suffix "suffix", from the source directory, "srcdir", in to the bin directory, "bindir" using the general preprocessor and C compilation flags. Return True if the compilation success, False if it fails. Log everything in the event of failure """ abs_src = os.path.join(f'{srcdir}', f'{f_root}{suffix}') abs_bin = os.path.join(f'{bindir}', f'{f_root}.o') # Construct the argument list arglist = [f'{gp["cc"]}'] arglist.extend(gp['cflags']) arglist.extend(gp['cc_output_pattern'].format(f'{f_root}.o').split()) arglist.extend(gp['cc_input_pattern'].format(abs_src).split()) # Run the compilation, but only if the source file is newer than the # binary. succeeded = True res = None if not os.path.isfile(abs_bin) or ( os.path.getmtime(abs_src) > os.path.getmtime(abs_bin) ): if gp['verbose']: log.debug(f'Compiling in directory {bindir}') log.debug(arglist_to_str(arglist)) try: res = subprocess.run( arglist, stdout=subprocess.PIPE, stderr=subprocess.PIPE, cwd=bindir, timeout=gp['timeout'], ) if res.returncode != 0: log.warning( f'Warning: Compilation of {f_root}{suffix} from source ' + f'directory {srcdir} to binary directory {bindir} failed' ) succeeded = False except subprocess.TimeoutExpired: log.warning( f'Warning: Compilation of {f_root}{suffix} from source ' + f'directory {srcdir} to binary directory {bindir} timed out' ) succeeded = False if not succeeded: log.debug('Command was:') log.debug(arglist_to_str(arglist)) if res: log.debug(res.stdout.decode('utf-8')) log.debug(res.stderr.decode('utf-8')) return succeeded
def compile_benchmark(bench): """Compile the benchmark, "bench". Return True if all files compile successfully, False otherwise.""" abs_src_b = os.path.join(gp['benchdir'], bench) abs_bd_b = os.path.join(gp['bd_benchdir'], bench) succeeded = True if not os.path.isdir(abs_bd_b): try: os.makedirs(abs_bd_b) except PermissionError: log.warning( 'Warning: Unable to create build directory for ' + f'benchmark {bench}' ) return False # Compile each file in the benchmark for filename in os.listdir(abs_src_b): f_root, ext = os.path.splitext(filename) if ext == '.c': succeeded &= compile_file(f_root, abs_src_b, abs_bd_b) return succeeded
def compile_support(): """Compile all the support code. Return True if all files compile successfully, False otherwise.""" succeeded = True # First the general support if not os.path.isdir(gp['bd_supportdir']): try: os.makedirs(gp['bd_supportdir']) except PermissionError: log.warning( 'Warning: Unable to create support build directory ' + f'{gp["bd_supportdir"]}' ) return False # Compile each general support file in the benchmark succeeded &= compile_file('beebsc', gp['supportdir'], gp['bd_supportdir']) succeeded &= compile_file('main', gp['supportdir'], gp['bd_supportdir']) # Compile dummy files that are needed for dlib in gp['dummy_libs']: succeeded &= compile_file( 'dummy-' + dlib, gp['supportdir'], gp['bd_supportdir'] ) # Compile architecture, chip and board specific files. Note that we only # create the build directory if it is needed here. for dirtype in ['arch', 'chip', 'board']: # Support directory we are interested in dirname = gp[dirtype + 'dir'] # List of files/subdirectories in that directory filelist = os.listdir(dirname) # Compile every C or assembler source file for filename in filelist: root, ext = os.path.splitext(filename) full_fn = os.path.join(dirname, filename) if (os.path.isfile(full_fn) and (ext == '.c' or ext == '.s' or ext == '.S')): # Create build directory builddir = gp['bd_' + dirtype + 'dir'] if not os.path.isdir(builddir): try: os.makedirs(builddir) except PermissionError: log.warning( 'Warning: Unable to create build directory ' + f'for {dirname}, "{builddir}' ) return False succeeded &= compile_file(root, dirname, builddir, suffix=ext) return succeeded
def create_link_binlist(abs_bd): """ Create a list of all the binaries to be linked, including those in the specified absolute directory, abs_bd. The binaries in this directory can be specified as relative filenames. All others will all be absolute addresses, since ultimately we will link in the abs_bd directory. Return the result binlist, or an empty list on failure. There is a nasty gotcha here. The ordering of files matters, since that is the order they will get packed into the executable, which in turn may affect branch distances. We therefore explicitly order files. """ # Find the object files in alphabetical order binlist = [] for binf in sorted(os.listdir(abs_bd), key=lambda objf: objf): if binf.endswith('.o'): binlist.extend(gp['ld_input_pattern'].format(binf).split()) # Add arch, chip and board binaries for dirtype in ['arch', 'chip', 'board']: # Build directory bindir = gp['bd_{dirtype}dir'.format(dirtype=dirtype)] # List of files in the build directory in alphabetical order filelist = sorted(os.listdir(bindir), key=lambda objf: objf) # Add every object file for filename in filelist: root, ext = os.path.splitext(filename) binf = os.path.join(bindir, filename) if (os.path.isfile(binf) and (ext == '.o')): binlist.extend(gp['ld_input_pattern'].format(binf).split()) # Add generic support for supp in ['main.o', 'beebsc.o']: binf = os.path.join(gp['bd_supportdir'], supp) if os.path.isfile(binf): binlist.extend(gp['ld_input_pattern'].format(binf).split()) else: log.warning( 'Warning: Unable to find support library {binf}'.format( binf=binf)) return [] # Add dummy binaries. These must be sorted in alphabetical order for dlib in sorted(gp['dummy_libs'], key=lambda lib: lib): binf = os.path.join(gp['bd_supportdir'], 'dummy-{dlib}.o'.format(dlib=dlib)) if os.path.isfile(binf): binlist.extend(gp['ld_input_pattern'].format(binf).split()) else: log.warning('Warning: Unable to find dummy library {binf}'.format( binf=binf)) return [] return binlist
def compile_support(): """Compile all the support code. Return True if all files compile successfully, False otherwise.""" succeeded = True # First the general support if not os.path.isdir(gp['bd_supportdir']): try: os.makedirs(gp['bd_supportdir']) except PermissionError: log.warning( 'Warning: Unable to create support build directory ' + f'{gp["bd_supportdir"]}' ) return False # Compile each general support file in the benchmark succeeded &= compile_file('beebsc', gp['supportdir'], gp['bd_supportdir']) succeeded &= compile_file('main', gp['supportdir'], gp['bd_supportdir']) # Compile dummy files that are needed for dlib in gp['dummy_libs']: succeeded &= compile_file( 'dummy-' + dlib, gp['supportdir'], gp['bd_supportdir'] ) # Compile architecture, chip and board specific files. Note that we only # create the build directory if it is needed here. for dirname in ['arch', 'chip', 'board']: filename = os.path.join(gp[dirname + 'dir'], dirname + 'support.c') if os.path.isfile(filename): # Create build directory builddir = gp['bd_' + dirname + 'dir'] if not os.path.isdir(builddir): try: os.makedirs(builddir) except PermissionError: log.warning( 'Warning: Unable to create build directory ' + f'for {dirname}, "{builddir}' ) return False succeeded &= compile_file( dirname + 'support', gp[dirname + 'dir'], gp['bd_' + dirname + 'dir'], ) return succeeded
def create_link_binlist(abs_bd): """Create a list of all the binaries to be linked, including those in the specified absolute directory, abs_bd. The binaries in this directory can be specified as relative filenames. All others will all be absolute addresses, since ultimately we will link in the abs_bd directory. Return the result binlist, or an empty list on failure.""" binlist = [] for binf in os.listdir(abs_bd): if binf.endswith('.o'): binlist.extend(gp['ld_input_pattern'].format(binf).split()) # Add arch, chip and board binaries for dirtype in ['arch', 'chip', 'board']: # Build directory bindir = gp[f'bd_{dirtype}dir'] # List of files in the build directory filelist = os.listdir(bindir) # Add every object file for filename in filelist: root, ext = os.path.splitext(filename) binf = os.path.join(bindir, filename) if (os.path.isfile(binf) and (ext == '.o')): binlist.extend( gp['ld_input_pattern'].format(binf).split() ) # Add generic support for supp in ['main.o', 'beebsc.o']: binf = os.path.join(gp['bd_supportdir'], supp) if os.path.isfile(binf): binlist.extend(gp['ld_input_pattern'].format(binf).split()) else: log.warning(f'Warning: Unable to find support library {binf}') return [] # Add dummy binaries for dlib in gp['dummy_libs']: binf = os.path.join(gp['bd_supportdir'], f'dummy-{dlib}.o') if os.path.isfile(binf): binlist.extend(gp['ld_input_pattern'].format(binf).split()) else: log.warning(f'Warning: Unable to find dummy library {binf}') return [] return binlist
def benchmark_speed(bench, target_args): """Time the benchmark. "target_args" is a namespace of arguments specific to the target. Result is a time in milliseconds, or zero on failure. For the parallel option, this method must be thread-safe.""" succeeded = True appdir = os.path.join(gp['bd_benchdir'], bench) appexe = os.path.join(appdir, bench) if os.path.isfile(appexe): arglist = build_benchmark_cmd(bench, target_args) try: res = subprocess.run( arglist, stdout=subprocess.PIPE, stderr=subprocess.PIPE, cwd=appdir, timeout=gp['timeout'], ) if res.returncode != 0: log.warning(f'Warning: Run of {bench} failed.') succeeded = False except subprocess.TimeoutExpired: log.warning(f'Warning: Run of {bench} timed out.') succeeded = False else: log.warning(f'Warning: {bench} executable not found.') succeeded = False # Process results if succeeded: exec_time = decode_results(res.stdout.decode('utf-8'), res.stderr.decode('utf-8')) succeeded = exec_time > 0 if succeeded: return exec_time else: for arg in arglist: if arg == arglist[0]: comm = arg elif arg == '-ex': comm += ' ' + arg else: comm += " '" + arg + "'" log.debug('Args to subprocess:') log.debug(f'{comm}') if 'res' in locals(): log.debug(res.stdout.decode('utf-8')) log.debug(res.stderr.decode('utf-8')) return 0.0
def link_benchmark(bench): """Link the benchmark, "bench". Return True if link is successful, False otherwise.""" abs_bd_b = os.path.join(gp['bd_benchdir'], bench) if not os.path.isdir(abs_bd_b): log.warning( 'Warning: Unable to find build directory for benchmark {bench}'. format(bench=bench)) return False # Use a flag to track warnings, but keep going through warnings. succeeded = True # Create the argument list binlist = create_link_binlist(abs_bd_b) if not binlist: succeeded = False arglist = create_link_arglist(bench, binlist) # Run the link if gp['verbose']: log.debug('Linking in directory {abs_bd_b}'.format(abs_bd_b=abs_bd_b)) log.debug(arglist_to_str(arglist)) try: res = subprocess.run( arglist, stdout=subprocess.PIPE, stderr=subprocess.PIPE, cwd=abs_bd_b, timeout=gp['timeout'], ) if res.returncode != 0: log.warning('Warning: Link of benchmark "{bench}" failed'.format( bench=bench)) succeeded = False log.debug(res.stdout.decode('utf-8')) log.debug(res.stderr.decode('utf-8')) except subprocess.TimeoutExpired: log.warning('Warning: link of benchmark "{bench}" timed out'.format( bench=bench)) succeeded = False if not succeeded: log.debug('In directory "' + abs_bd_b + '"') log.debug('Command was:') log.debug(arglist_to_str(arglist)) return succeeded
def link_benchmark(bench): """Link the benchmark, "bench". Return True if link is successful, False otherwise.""" abs_bd_b = os.path.join(gp['bd_benchdir'], bench) if not os.path.isdir(abs_bd_b): log.warning( 'Warning: Unable to find build directory for ' + f'benchmark {bench}' ) return False # Use a flag to track warnings, but keep going through warnings. succeeded = True # Create the argument list binlist = create_link_binlist(abs_bd_b) if not binlist: succeeded = False arglist = create_link_arglist(bench, binlist) # Run the link try: res = subprocess.run( arglist, stdout=subprocess.PIPE, stderr=subprocess.PIPE, cwd=abs_bd_b, timeout=300, ) if res.returncode != 0: log.warning(f'Warning: Link of benchmark "{bench}" failed') succeeded = False except subprocess.TimeoutExpired: log.warning(f'Warning: link of benchmark "{bench}" timed out') succeeded = False if not succeeded: log.debug('Args to subprocess:') log.debug(f'{arglist}') log.debug(res.stdout.decode('utf-8')) log.debug(res.stderr.decode('utf-8')) return succeeded