def main(): """Main program to drive building of benchmarks.""" # Establish the root directory of the repository, since we know this file is # in that directory. gp['rootdir'] = os.path.abspath(os.path.dirname(__file__)) # Parse arguments using standard technology parser = build_parser() args = parser.parse_args() # Establish logging, using "build" as the log file prefix. gp['verbose'] = args.verbose setup_logging(args.logdir, 'build') log_args(args) # Establish build directory create_builddir(args.builddir, args.clean) # Check args are OK (have to have logging and build directory set up first) validate_args(args) # Find the benchmarks benchmarks = find_benchmarks() log_benchmarks(benchmarks) # Establish other global parameters set_parameters(args) log_parameters() log.debug('General log') log.debug('===========') # Set up additional environment variables. set_environ() # Track success successful = compile_support() if successful: log.debug('Compilation of support files successful') for bench in benchmarks: res = compile_benchmark(bench) successful &= res if res: log.debug('Compilation of benchmark "{bench}" successful'.format( bench=bench)) res = link_benchmark(bench) successful &= res if res: log.debug('Linking of benchmark "{bench}" successful'.format( bench=bench)) log.info(bench) if successful: log.info('All benchmarks built successfully')
def decode_results(stdout_str, stderr_str): """Extract the results from the output string of the run. Return the elapsed time in milliseconds or zero if the run failed.""" time_re = re.search('Bench time:(\\d+)', stdout_str, re.S) time = int(time_re.group(1)) if not time: log.debug('Warning: Failed to find timing') return 0.0 return time / cpu_mhz / 1000.0
def log_parameters(): """Record all the global parameters in the log""" log.debug('Global parameters') log.debug('=================') for key, val in gp.items(): log.debug(f'{key:<21}: {val}') log.debug('')
def compile_file(f_root, srcdir, bindir): """Compile a single C file, with the given file root, "f_root", 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}.c') 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(sep=' ')) arglist.extend(gp['cc_input_pattern'].format(abs_src).split(sep=' ')) # 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) ): try: res = subprocess.run( arglist, stdout=subprocess.PIPE, stderr=subprocess.PIPE, cwd=bindir, timeout=300, ) if res.returncode != 0: log.warning( f'Warning: Compilation of {f_root}.c from source directory ' + f'{srcdir} to binary directory {bindir} failed' ) succeeded = False except subprocess.TimeoutExpired: log.warning( f'Warning: Compilation of {f_root}.c from source directory ' + f'{srcdir} to binary directory {bindir} timed out' ) succeeded = False if not succeeded: log.debug('Args to subprocess:') log.debug(f'{arglist}') if res: log.debug(res.stdout.decode('utf-8')) log.debug(res.stderr.decode('utf-8')) return succeeded
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 decode_results(stdout_str, stderr_str): """Extract the results from the output string of the run. Return the elapsed time in milliseconds or zero if the run failed.""" # Return code is in standard output. We look for the string that means we # hit a breakpoint on _exit, then for the string returning the value. rcstr = re.search('Breakpoint 3,.*\$1 = (\d+)', stdout_str, re.S) if not rcstr: log.debug('Warning: Failed to find return code') return 0.0 # The start and end cycle counts are in the stderr string times = re.search('(\d+)\D+(\d+)', stderr_str, re.S) if times: ms_elapsed = float(int(times.group(2)) - int(times.group(1))) / 1000.0 return ms_elapsed # We must have failed to find a time log.debug('Warning: Failed to find timing') return 0.0
def decode_results(stdout_str, stderr_str): """Extract the results from the output string of the run. Return the elapsed time in milliseconds or zero if the run failed.""" # Return code is in standard output. We look for the string that means we # hit a breakpoint on _exit, then for the string returning the value. rcstr = re.search('Breakpoint 3 at.*exit\.c.*\$1 = (\d+)', stdout_str, re.S) if not rcstr: log.debug('Warning: Failed to find return code') return 0.0 # The start and end cycle counts are in the stderr string starttime = re.search('\$1 = (\d+)', stdout_str, re.S) endtime = re.search('\$2 = (\d+)', stdout_str, re.S) if not starttime or not endtime: log.debug('Warning: Failed to find timing') return 0.0 # Time from cycles to milliseconds global cpu_mhz return (int(endtime.group(1)) - int(starttime.group(1))) / cpu_mhz / 1000.0
def decode_results(stdout_str, stderr_str): """Extract the results from the output string of the run. Return the elapsed time in milliseconds or zero if the run failed.""" global cpu_per #check that simulation returned successfully if not re.search('SIMULATION PASSED', stdout_str, re.S): log.debug('Warning: Simulation reporting error') return 0.0 # Match "RES: <cycles>" rcstr = re.search('RES: (\d+)', stdout_str, re.S) if not rcstr: log.debug('Warning: Failed to find result') return 0.0 time = float(rcstr.group(1))*cpu_per time_ms = time * 1000 return time_ms # We must have failed to find a time log.debug('Warning: Failed to find timing') return 0.0
def decode_results(stdout_str, stderr_str): """Extract the results from the output string of the run. Return the elapsed time in milliseconds or zero if the run failed.""" proc = subprocess.Popen(["./terminal.py", "--speed", "115200", "/dev/ttyUSB1"], stdout=subprocess.PIPE) line = b"" while True: c = proc.stdout.read(1) if c != b'\n': line += c else: log.debug(line.decode("utf-8", errors="ignore").encode("ascii", errors="ignore")) line = line.decode("utf-8", errors="ignore") time_re = re.search('Bench time:(\\d+)', line, re.S) if time_re: time = int(time_re.group(1)) proc.kill() return time / cpu_mhz / 1000.0 line = b'' raise
def decode_results(stdout_str, stderr_str): """Extract the results from the output string of the run. Return the elapsed time in milliseconds or zero if the run failed.""" # See above in build_benchmark_cmd how we record the return value and # execution time. Return code is in standard output. Execution time is in # standard error. # Match "RET=rc" rcstr = re.search('^RET=(\d+)', stdout_str, re.M) if not rcstr: log.debug('Warning: Failed to find return code') return 0.0 # Match "Real time: dd.ddd" time = re.search('^Real time: (\d+)[.](\d+)', stdout_str, re.S) if time: ms_elapsed = float(time.group(1) + '.' + time.group(2)) # Return value cannot be zero (will be interpreted as error) return max(float(ms_elapsed), 0.001) # We must have failed to find a time log.debug('Warning: Failed to find timing') return 0.0
def decode_results(stdout_str, stderr_str): """Extract the results from the output string of the run. Return the elapsed time in milliseconds or zero if the run failed.""" #print("OUT") #print(stdout_str) #print("ERR") #print(stderr_str) # The start and end cycle counts are in the stderr string start_at = re.search('mTime 1 : (\d+)', stdout_str, re.S) end_at = re.search('mTime 2 : (\d+)', stdout_str, re.S) if not start_at or not end_at: log.debug('Warning: Failed to find timing') return 0.0 time = int(end_at.group(1)) - int(start_at.group(1)) # print(time) # Time from cycles to milliseconds global cpu_mhz return time / cpu_mhz / 1000.0
def decode_results(stdout_str, stderr_str): """Extract the results from the output string of the run. Return the elapsed time in milliseconds or zero if the run failed.""" # print("OUT") # print(stdout_str) # print("ERR") # print(stderr_str) # The start and end cycle counts are in the stderr string time = re.search('\$1 = (\d+)', stdout_str, re.S) main_result = re.search('\$2 = (\d+)', stdout_str, re.S) if not time or not main_result: log.debug('Warning: Failed to find timing') return 0.0 if main_result.group(1) != "0": log.debug('Warning: test failure') return 0.0 # print(time) # Time from cycles to milliseconds global cpu_mhz return (int(time.group(1))) / cpu_mhz / 1000.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 ' + 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
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 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(srcdir, '{root}{suff}'.format(root=f_root, suff=suffix)) abs_bin = os.path.join(bindir, '{root}.o'.format(root=f_root)) # Construct the argument list arglist = [gp["cc"]] arglist.extend(gp['cflags']) arglist.extend(gp['cc_output_pattern'].format( '{root}.o'.format(root=f_root)).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('Compiling in directory {bin}'.format(bin=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( 'Warning: Compilation of {root}{suff} from source directory {src} to binary directory {bin} failed' .format(root=f_root, suff=suffix, src=srcdir, bin=bindir)) succeeded = False except subprocess.TimeoutExpired: log.warning( 'Warning: Compilation of {root}{suff} from source directory {src} to binary directory {bin} timed out' .format(root=f_root, suff=suffix, src=srcdir, bin=bindir)) succeeded = False if not succeeded: log.debug('Command was:') log.debug(arglist_to_str(arglist)) log.debug(res.stdout.decode('utf-8')) log.debug(res.stderr.decode('utf-8')) return succeeded