From 2afb91596fe0d507483b8d7e0dfb60dbc4a075d7 Mon Sep 17 00:00:00 2001 From: Ganesh Gore Date: Sat, 11 Feb 2023 18:04:54 -0700 Subject: [PATCH 1/2] Refactored run_openfpga_task.py --- openfpga_flow/scripts/run_fpga_task.py | 120 ++++++++++++++++++------- 1 file changed, 89 insertions(+), 31 deletions(-) diff --git a/openfpga_flow/scripts/run_fpga_task.py b/openfpga_flow/scripts/run_fpga_task.py index 093d32db3..bb223effa 100644 --- a/openfpga_flow/scripts/run_fpga_task.py +++ b/openfpga_flow/scripts/run_fpga_task.py @@ -67,10 +67,14 @@ parser.add_argument( ) parser.add_argument("--config", help="Override default configuration") parser.add_argument( - "--test_run", action="store_true", help="Dummy run shows final generated VPR commands" + "--test_run", + action="store_true", + help="Dummy run shows final generated VPR commands", ) parser.add_argument("--debug", action="store_true", help="Run script in debug mode") -parser.add_argument("--continue_on_fail", action="store_true", help="Exit script with return code") +parser.add_argument( + "--continue_on_fail", action="store_true", help="Exit script with return code" +) parser.add_argument( "--show_thread_logs", action="store_true", help="Skips logs from running thread" ) @@ -83,13 +87,24 @@ task_script_dir = os.path.dirname(os.path.abspath(__file__)) script_env_vars = { "PATH": { "OPENFPGA_FLOW_PATH": task_script_dir, - "ARCH_PATH": os.path.join("${PATH:OPENFPGA_PATH}", "arch"), - "OPENFPGA_SHELLSCRIPT_PATH": os.path.join("${PATH:OPENFPGA_PATH}", "OpenFPGAShellScripts"), - "BENCH_PATH": os.path.join("${PATH:OPENFPGA_PATH}", "benchmarks"), - "TECH_PATH": os.path.join("${PATH:OPENFPGA_PATH}", "tech"), + "VPR_ARCH_PATH": os.path.join( + "${PATH:OPENFPGA_PATH}", "openfpga_flow", "vpr_arch" + ), + "OF_ARCH_PATH": os.path.join( + "${PATH:OPENFPGA_PATH}", "openfpga_flow", "openfpga_arch" + ), + "OPENFPGA_SHELLSCRIPT_PATH": os.path.join( + "${PATH:OPENFPGA_PATH}", "openfpga_flow", "OpenFPGAShellScripts" + ), + "BENCH_PATH": os.path.join( + "${PATH:OPENFPGA_PATH}", "openfpga_flow", "benchmarks" + ), + "TECH_PATH": os.path.join("${PATH:OPENFPGA_PATH}", "openfpga_flow", "tech"), "SPICENETLIST_PATH": os.path.join("${PATH:OPENFPGA_PATH}", "SpiceNetlists"), "VERILOG_PATH": os.path.join("${PATH:OPENFPGA_PATH}", "VerilogNetlists"), - "OPENFPGA_PATH": os.path.abspath(os.path.join(task_script_dir, os.pardir, os.pardir)), + "OPENFPGA_PATH": os.path.abspath( + os.path.join(task_script_dir, os.pardir, os.pardir) + ), } } config = ConfigParser(interpolation=ExtendedInterpolation()) @@ -237,7 +252,8 @@ def generate_each_task_actions(taskname): missing_section = list(set(required_sec) - set(task_conf.sections())) if missing_section: clean_up_and_exit( - "Missing sections %s" % " ".join(missing_section) + " in task configuration file" + "Missing sections %s" % " ".join(missing_section) + + " in task configuration file" ) # Declare varibles to access sections @@ -258,7 +274,9 @@ def generate_each_task_actions(taskname): clean_up_and_exit("Found duplicate architectures in config file") # Get Flow information - logger.info('Running "%s" flow', GeneralSection.get("fpga_flow", fallback="yosys_vpr")) + logger.info( + 'Running "%s" flow', GeneralSection.get("fpga_flow", fallback="yosys_vpr") + ) # Check if specified benchmark files exist benchmark_list = [] @@ -272,7 +290,8 @@ def generate_each_task_actions(taskname): files = glob.glob(eachpath) if not len(files): clean_up_and_exit( - ("No files added benchmark %s" % bech_name) + " with path %s " % (eachpath) + ("No files added benchmark %s" % bech_name) + + " with path %s " % (eachpath) ) bench_files += files @@ -308,11 +327,15 @@ def generate_each_task_actions(taskname): yosys_params_common = {} for param in yosys_params: - yosys_params_common[param.upper()] = SynthSection.get("bench_" + param + "_common") + yosys_params_common[param.upper()] = SynthSection.get( + "bench_" + param + "_common" + ) # Individual benchmark configuration CurrBenchPara["files"] = bench_files - CurrBenchPara["top_module"] = SynthSection.get(bech_name + "_top", fallback="top") + CurrBenchPara["top_module"] = SynthSection.get( + bech_name + "_top", fallback="top" + ) CurrBenchPara["ys_script"] = SynthSection.get( bech_name + "_yosys", fallback=ys_for_task_common ) @@ -337,7 +360,8 @@ def generate_each_task_actions(taskname): if GeneralSection.getboolean("power_analysis"): if not SynthSection.get(bech_name + "_act"): clean_up_and_exit( - "Missing argument %s" % (bech_name + "_act") + "for vpr_blif flow" + "Missing argument %s" % (bech_name + "_act") + + "for vpr_blif flow" ) CurrBenchPara["activity_file"] = SynthSection.get(bech_name + "_act") else: @@ -345,7 +369,9 @@ def generate_each_task_actions(taskname): if not SynthSection.get(bech_name + "_act"): CurrBenchPara["activity_file"] = bech_name + "_act" else: - CurrBenchPara["activity_file"] = SynthSection.get(bech_name + "_act") + CurrBenchPara["activity_file"] = SynthSection.get( + bech_name + "_act" + ) # Check if base verilog file exists if not SynthSection.get(bech_name + "_verilog"): @@ -381,13 +407,16 @@ def generate_each_task_actions(taskname): # architecture, benchmark and parameters # Create run_job object [arch, bench, run_dir, commnad] flow_run_cmd_list = [] - for indx, arch in enumerate(archfile_list): - for bench in benchmark_list: + for bench in benchmark_list: + for indx, arch in enumerate(archfile_list): for lbl, param in bench["script_params"].items(): if benchmark_top_module_count.count(bench["top_module"]) > 1: flow_run_dir = get_flow_rundir( arch, - "bench" + str(benchmark_list.index(bench)) + "_" + bench["top_module"], + "bench" + + str(benchmark_list.index(bench)) + + "_" + + bench["top_module"], lbl, ) else: @@ -400,6 +429,7 @@ def generate_each_task_actions(taskname): param=param, task_conf=task_conf, ) + command += ["--flow_config", curr_task_conf_file] flow_run_cmd_list.append( { "arch": arch, @@ -506,13 +536,21 @@ def create_run_command(curr_job_dir, archfile, benchmark_obj, param, task_conf): if args.debug: command += ["--debug"] + return command def strip_child_logger_info(line): try: logtype, message = line.split(" - ", 1) - lognumb = {"CRITICAL": 50, "ERROR": 40, "WARNING": 30, "INFO": 20, "DEBUG": 10, "NOTSET": 0} + lognumb = { + "CRITICAL": 50, + "ERROR": 40, + "WARNING": 30, + "INFO": 20, + "DEBUG": 10, + "NOTSET": 0, + } logger.log(lognumb[logtype.strip().upper()], message) except: logger.info(line) @@ -555,7 +593,11 @@ def run_single_script(s, eachJob, job_list): os._exit(1) eachJob["endtime"] = time.time() timediff = timedelta(seconds=(eachJob["endtime"] - eachJob["starttime"])) - timestr = humanize.naturaldelta(timediff) if "humanize" in sys.modules else str(timediff) + timestr = ( + humanize.naturaldelta(timediff) + if "humanize" in sys.modules + else str(timediff) + ) logger.info( "%s Finished with returncode %d, Time Taken %s ", thread_name, @@ -572,7 +614,9 @@ def run_actions(job_list): thread_list = [] for _, eachjob in enumerate(job_list): t = threading.Thread( - target=run_single_script, name=eachjob["name"], args=(thread_sema, eachjob, job_list) + target=run_single_script, + name=eachjob["name"], + args=(thread_sema, eachjob, job_list), ) t.start() thread_list.append(t) @@ -581,6 +625,9 @@ def run_actions(job_list): def collect_results(job_run_list): + """ + Collect performance numbers from vpr_stat.result file + """ task_result = [] for run in job_run_list: if not run["status"]: @@ -588,25 +635,36 @@ def collect_results(job_run_list): continue # Check if any result file exist if not glob.glob(os.path.join(run["run_dir"], "*.result")): - logger.info("No result files found for %s" % run["name"]) + logger.info("No result files found for %s", run["name"]) + continue # Read and merge result file - vpr_res = ConfigParser(allow_no_value=True, interpolation=ExtendedInterpolation()) - vpr_res.read_file(open(os.path.join(run["run_dir"], "vpr_stat.result"))) + vpr_res = ConfigParser( + allow_no_value=True, interpolation=ExtendedInterpolation() + ) + vpr_result_file = os.path.join(run["run_dir"], "vpr_stat.result") + vpr_res.read_file(open(vpr_result_file, encoding="UTF-8")) result = OrderedDict() result["name"] = run["name"] result["TotalRunTime"] = int(run["endtime"] - run["starttime"]) result.update(vpr_res["RESULTS"]) task_result.append(result) - colnames = [] - for eachLbl in task_result: - colnames.extend(eachLbl.keys()) - if len(task_result): - with open("task_result.csv", "w", newline="") as csvfile: - writer = csv.DictWriter(csvfile, extrasaction="ignore", fieldnames=list(colnames)) + + colnames = [] + # Extract all column names + for each_metric in task_result: + colnames.extend(set(each_metric.keys()) - {"name", "TotalRunTime"}) + colnames = sorted(list(set(colnames))) + if len(task_result) > 0: + with open("task_result.csv", "w", encoding="UTF-8", newline="") as csvfile: + writer = csv.DictWriter( + csvfile, + extrasaction="ignore", + fieldnames=["name", "TotalRunTime"] + colnames, + ) writer.writeheader() - for eachResult in task_result: - writer.writerow(eachResult) + for each in task_result: + writer.writerow(each) if __name__ == "__main__": From a6263c44af549749d75124d9b844fd116dd44487 Mon Sep 17 00:00:00 2001 From: Ganesh Gore Date: Sat, 11 Feb 2023 18:12:04 -0700 Subject: [PATCH 2/2] Updated format --- openfpga_flow/scripts/run_fpga_flow.py | 4 +- openfpga_flow/scripts/run_fpga_task.py | 60 +++++++------------------- 2 files changed, 17 insertions(+), 47 deletions(-) diff --git a/openfpga_flow/scripts/run_fpga_flow.py b/openfpga_flow/scripts/run_fpga_flow.py index 3a936b9e7..23a655e02 100644 --- a/openfpga_flow/scripts/run_fpga_flow.py +++ b/openfpga_flow/scripts/run_fpga_flow.py @@ -395,7 +395,7 @@ def main(): def check_required_file(): - """ Function ensure existace of all required files for the script """ + """Function ensure existace of all required files for the script""" files_dict = { "CAD TOOL PATH": os.path.join( flow_script_dir, os.pardir, "misc", "fpgaflow_default_tool_path.conf" @@ -407,7 +407,7 @@ def check_required_file(): def read_script_config(): - """ This fucntion reads default CAD tools path from configuration file """ + """This fucntion reads default CAD tools path from configuration file""" global config, cad_tools config = ConfigParser(interpolation=ExtendedInterpolation()) config.read_dict(script_env_vars) diff --git a/openfpga_flow/scripts/run_fpga_task.py b/openfpga_flow/scripts/run_fpga_task.py index bb223effa..e215a3f50 100644 --- a/openfpga_flow/scripts/run_fpga_task.py +++ b/openfpga_flow/scripts/run_fpga_task.py @@ -72,9 +72,7 @@ parser.add_argument( help="Dummy run shows final generated VPR commands", ) parser.add_argument("--debug", action="store_true", help="Run script in debug mode") -parser.add_argument( - "--continue_on_fail", action="store_true", help="Exit script with return code" -) +parser.add_argument("--continue_on_fail", action="store_true", help="Exit script with return code") parser.add_argument( "--show_thread_logs", action="store_true", help="Skips logs from running thread" ) @@ -87,24 +85,16 @@ task_script_dir = os.path.dirname(os.path.abspath(__file__)) script_env_vars = { "PATH": { "OPENFPGA_FLOW_PATH": task_script_dir, - "VPR_ARCH_PATH": os.path.join( - "${PATH:OPENFPGA_PATH}", "openfpga_flow", "vpr_arch" - ), - "OF_ARCH_PATH": os.path.join( - "${PATH:OPENFPGA_PATH}", "openfpga_flow", "openfpga_arch" - ), + "VPR_ARCH_PATH": os.path.join("${PATH:OPENFPGA_PATH}", "openfpga_flow", "vpr_arch"), + "OF_ARCH_PATH": os.path.join("${PATH:OPENFPGA_PATH}", "openfpga_flow", "openfpga_arch"), "OPENFPGA_SHELLSCRIPT_PATH": os.path.join( "${PATH:OPENFPGA_PATH}", "openfpga_flow", "OpenFPGAShellScripts" ), - "BENCH_PATH": os.path.join( - "${PATH:OPENFPGA_PATH}", "openfpga_flow", "benchmarks" - ), + "BENCH_PATH": os.path.join("${PATH:OPENFPGA_PATH}", "openfpga_flow", "benchmarks"), "TECH_PATH": os.path.join("${PATH:OPENFPGA_PATH}", "openfpga_flow", "tech"), "SPICENETLIST_PATH": os.path.join("${PATH:OPENFPGA_PATH}", "SpiceNetlists"), "VERILOG_PATH": os.path.join("${PATH:OPENFPGA_PATH}", "VerilogNetlists"), - "OPENFPGA_PATH": os.path.abspath( - os.path.join(task_script_dir, os.pardir, os.pardir) - ), + "OPENFPGA_PATH": os.path.abspath(os.path.join(task_script_dir, os.pardir, os.pardir)), } } config = ConfigParser(interpolation=ExtendedInterpolation()) @@ -252,8 +242,7 @@ def generate_each_task_actions(taskname): missing_section = list(set(required_sec) - set(task_conf.sections())) if missing_section: clean_up_and_exit( - "Missing sections %s" % " ".join(missing_section) - + " in task configuration file" + "Missing sections %s" % " ".join(missing_section) + " in task configuration file" ) # Declare varibles to access sections @@ -274,9 +263,7 @@ def generate_each_task_actions(taskname): clean_up_and_exit("Found duplicate architectures in config file") # Get Flow information - logger.info( - 'Running "%s" flow', GeneralSection.get("fpga_flow", fallback="yosys_vpr") - ) + logger.info('Running "%s" flow', GeneralSection.get("fpga_flow", fallback="yosys_vpr")) # Check if specified benchmark files exist benchmark_list = [] @@ -290,8 +277,7 @@ def generate_each_task_actions(taskname): files = glob.glob(eachpath) if not len(files): clean_up_and_exit( - ("No files added benchmark %s" % bech_name) - + " with path %s " % (eachpath) + ("No files added benchmark %s" % bech_name) + " with path %s " % (eachpath) ) bench_files += files @@ -327,15 +313,11 @@ def generate_each_task_actions(taskname): yosys_params_common = {} for param in yosys_params: - yosys_params_common[param.upper()] = SynthSection.get( - "bench_" + param + "_common" - ) + yosys_params_common[param.upper()] = SynthSection.get("bench_" + param + "_common") # Individual benchmark configuration CurrBenchPara["files"] = bench_files - CurrBenchPara["top_module"] = SynthSection.get( - bech_name + "_top", fallback="top" - ) + CurrBenchPara["top_module"] = SynthSection.get(bech_name + "_top", fallback="top") CurrBenchPara["ys_script"] = SynthSection.get( bech_name + "_yosys", fallback=ys_for_task_common ) @@ -360,8 +342,7 @@ def generate_each_task_actions(taskname): if GeneralSection.getboolean("power_analysis"): if not SynthSection.get(bech_name + "_act"): clean_up_and_exit( - "Missing argument %s" % (bech_name + "_act") - + "for vpr_blif flow" + "Missing argument %s" % (bech_name + "_act") + "for vpr_blif flow" ) CurrBenchPara["activity_file"] = SynthSection.get(bech_name + "_act") else: @@ -369,9 +350,7 @@ def generate_each_task_actions(taskname): if not SynthSection.get(bech_name + "_act"): CurrBenchPara["activity_file"] = bech_name + "_act" else: - CurrBenchPara["activity_file"] = SynthSection.get( - bech_name + "_act" - ) + CurrBenchPara["activity_file"] = SynthSection.get(bech_name + "_act") # Check if base verilog file exists if not SynthSection.get(bech_name + "_verilog"): @@ -413,10 +392,7 @@ def generate_each_task_actions(taskname): if benchmark_top_module_count.count(bench["top_module"]) > 1: flow_run_dir = get_flow_rundir( arch, - "bench" - + str(benchmark_list.index(bench)) - + "_" - + bench["top_module"], + "bench" + str(benchmark_list.index(bench)) + "_" + bench["top_module"], lbl, ) else: @@ -593,11 +569,7 @@ def run_single_script(s, eachJob, job_list): os._exit(1) eachJob["endtime"] = time.time() timediff = timedelta(seconds=(eachJob["endtime"] - eachJob["starttime"])) - timestr = ( - humanize.naturaldelta(timediff) - if "humanize" in sys.modules - else str(timediff) - ) + timestr = humanize.naturaldelta(timediff) if "humanize" in sys.modules else str(timediff) logger.info( "%s Finished with returncode %d, Time Taken %s ", thread_name, @@ -639,9 +611,7 @@ def collect_results(job_run_list): continue # Read and merge result file - vpr_res = ConfigParser( - allow_no_value=True, interpolation=ExtendedInterpolation() - ) + vpr_res = ConfigParser(allow_no_value=True, interpolation=ExtendedInterpolation()) vpr_result_file = os.path.join(run["run_dir"], "vpr_stat.result") vpr_res.read_file(open(vpr_result_file, encoding="UTF-8")) result = OrderedDict()