From 614ecd8f4ec0b34b04da0114ddab73a161a89cee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=98yvind=20Harboe?= Date: Mon, 7 Jul 2025 19:46:54 +0200 Subject: [PATCH 1/3] synthesis: more consistent naming of logs and results MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Øyvind Harboe --- flow/Makefile | 12 ++++++------ flow/scripts/synth.tcl | 4 ++-- flow/scripts/synth_canonicalize.tcl | 2 +- flow/scripts/synth_metrics.tcl | 2 +- flow/scripts/synth_preamble.tcl | 4 ++-- flow/util/genMetrics.py | 2 +- 6 files changed, 13 insertions(+), 13 deletions(-) diff --git a/flow/Makefile b/flow/Makefile index c96bf8f3c6..329df67452 100644 --- a/flow/Makefile +++ b/flow/Makefile @@ -258,7 +258,7 @@ synth-report: synth .PHONY: do-synth-report do-synth-report: - ($(TIME_CMD) $(OPENROAD_CMD) $(SCRIPTS_DIR)/synth_metrics.tcl) 2>&1 | tee $(abspath $(LOG_DIR)/1_1_yosys_metrics.log) + ($(TIME_CMD) $(OPENROAD_CMD) $(SCRIPTS_DIR)/synth_metrics.tcl) 2>&1 | tee $(abspath $(LOG_DIR)/1_2_yosys_metrics.log) .PHONY: memory memory: @@ -282,24 +282,24 @@ yosys-dependencies: $(YOSYS_DEPENDENCIES) .PHONY: do-yosys do-yosys: $(DONT_USE_SC_LIB) - $(SCRIPTS_DIR)/synth.sh $(SYNTH_SCRIPT) $(LOG_DIR)/1_1_yosys.log + $(SCRIPTS_DIR)/synth.sh $(SYNTH_SCRIPT) $(LOG_DIR)/1_2_yosys.log .PHONY: do-yosys-canonicalize do-yosys-canonicalize: yosys-dependencies $(DONT_USE_SC_LIB) $(SCRIPTS_DIR)/synth.sh $(SCRIPTS_DIR)/synth_canonicalize.tcl $(LOG_DIR)/1_1_yosys_canonicalize.log -$(RESULTS_DIR)/1_synth.rtlil: $(YOSYS_DEPENDENCIES) +$(RESULTS_DIR)/1_1_yosys_canonicalize.rtlil: $(YOSYS_DEPENDENCIES) $(UNSET_AND_MAKE) do-yosys-canonicalize -$(RESULTS_DIR)/1_1_yosys.v: $(RESULTS_DIR)/1_synth.rtlil +$(RESULTS_DIR)/1_2_yosys.v: $(RESULTS_DIR)/1_1_yosys_canonicalize.rtlil $(UNSET_AND_MAKE) do-yosys .PHONY: do-synth do-synth: mkdir -p $(RESULTS_DIR) $(LOG_DIR) $(REPORTS_DIR) - cp $(RESULTS_DIR)/1_1_yosys.v $(RESULTS_DIR)/1_synth.v + cp $(RESULTS_DIR)/1_2_yosys.v $(RESULTS_DIR)/1_synth.v -$(RESULTS_DIR)/1_synth.v: $(RESULTS_DIR)/1_1_yosys.v +$(RESULTS_DIR)/1_synth.v: $(RESULTS_DIR)/1_2_yosys.v $(UNSET_AND_MAKE) do-synth .PHONY: clean_synth diff --git a/flow/scripts/synth.tcl b/flow/scripts/synth.tcl index 9a6b75d0be..a6c9807af5 100644 --- a/flow/scripts/synth.tcl +++ b/flow/scripts/synth.tcl @@ -1,5 +1,5 @@ source $::env(SCRIPTS_DIR)/synth_preamble.tcl -read_checkpoint $::env(RESULTS_DIR)/1_synth.rtlil +read_checkpoint $::env(RESULTS_DIR)/1_1_yosys_canonicalize.rtlil hierarchy -check -top $::env(DESIGN_NAME) @@ -145,7 +145,7 @@ if { ![env_var_exists_and_non_empty SYNTH_WRAPPED_OPERATORS] } { } # Write synthesized design -write_verilog -nohex -nodec $::env(RESULTS_DIR)/1_1_yosys.v +write_verilog -nohex -nodec $::env(RESULTS_DIR)/1_2_yosys.v # One day a more sophisticated synthesis will write out a modified # .sdc file after synthesis. For now, just copy the input .sdc file, # making synthesis more consistent with other stages. diff --git a/flow/scripts/synth_canonicalize.tcl b/flow/scripts/synth_canonicalize.tcl index f53ca13219..3c167d7797 100644 --- a/flow/scripts/synth_canonicalize.tcl +++ b/flow/scripts/synth_canonicalize.tcl @@ -10,4 +10,4 @@ hierarchy -check -top $::env(DESIGN_NAME) # Get rid of unused modules opt_clean -purge # The hash of this file will not change if files not part of synthesis do not change -write_rtlil $::env(RESULTS_DIR)/1_synth.rtlil +write_rtlil $::env(RESULTS_DIR)/1_1_yosys_canonicalize.rtlil diff --git a/flow/scripts/synth_metrics.tcl b/flow/scripts/synth_metrics.tcl index f24a05e80e..d2fe0ab500 100644 --- a/flow/scripts/synth_metrics.tcl +++ b/flow/scripts/synth_metrics.tcl @@ -1,5 +1,5 @@ utl::set_metrics_stage "synth__{}" source $::env(SCRIPTS_DIR)/load.tcl -load_design 1_1_yosys.v 1_synth.sdc +load_design 1_2_yosys.v 1_synth.sdc report_metrics 1 "Post synthesis" false false diff --git a/flow/scripts/synth_preamble.tcl b/flow/scripts/synth_preamble.tcl index a148fd9460..22dcb2aefb 100644 --- a/flow/scripts/synth_preamble.tcl +++ b/flow/scripts/synth_preamble.tcl @@ -8,11 +8,11 @@ erase_non_stage_variables synth # floorplan step to be re-executed. if { [env_var_exists_and_non_empty SYNTH_NETLIST_FILES] } { if { [llength $::env(SYNTH_NETLIST_FILES)] == 1 } { - log_cmd exec cp -p $::env(SYNTH_NETLIST_FILES) $::env(RESULTS_DIR)/1_1_yosys.v + log_cmd exec cp -p $::env(SYNTH_NETLIST_FILES) $::env(RESULTS_DIR)/1_2_yosys.v } else { # The date should be the most recent date of the files, but to # keep things simple we just use the creation date - log_cmd exec cat {*}$::env(SYNTH_NETLIST_FILES) > $::env(RESULTS_DIR)/1_1_yosys.v + log_cmd exec cat {*}$::env(SYNTH_NETLIST_FILES) > $::env(RESULTS_DIR)/1_2_yosys.v } log_cmd exec cp -p $::env(SDC_FILE) $::env(RESULTS_DIR)/1_synth.sdc if { [env_var_exists_and_non_empty CACHED_REPORTS] } { diff --git a/flow/util/genMetrics.py b/flow/util/genMetrics.py index 0b5ebee993..33261a7f8c 100755 --- a/flow/util/genMetrics.py +++ b/flow/util/genMetrics.py @@ -288,7 +288,7 @@ def extract_metrics( # Accumulate time # ========================================================================= - extractGnuTime("synth", metrics_dict, logPath + "/1_1_yosys.log") + extractGnuTime("synth", metrics_dict, logPath + "/1_2_yosys.log") extractGnuTime("floorplan", metrics_dict, logPath + "/2_1_floorplan.log") extractGnuTime("floorplan_io", metrics_dict, logPath + "/2_2_floorplan_io.log") extractGnuTime( From 22bfa724a05f4b3f1c71034761a844187e6f3993 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=98yvind=20Harboe?= Date: Mon, 7 Jul 2025 17:20:27 +0200 Subject: [PATCH 2/3] make: elapsed now looks for .v after .odb for a stage MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Øyvind Harboe --- flow/util/genElapsedTime.py | 26 ++++++++++++++------------ 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/flow/util/genElapsedTime.py b/flow/util/genElapsedTime.py index 3c9d0c7cf9..83e992c70e 100755 --- a/flow/util/genElapsedTime.py +++ b/flow/util/genElapsedTime.py @@ -62,20 +62,22 @@ def print_log_dir_times(logdir, args): int(line.split("Peak memory: ")[1].split("KB")[0]) / 1024 ) - # content hash for .odb file alongside .log file is useful to + # content hash for the result file alongside .log file is useful to # debug divergent results under what should be identical # builds(such as local and CI builds) - odb_file = pathlib.Path( - str(f).replace("logs/", "results/").replace(".log", ".odb") - ) - if odb_file.exists(): - hasher = hashlib.sha1() - with open(odb_file, "rb") as odb_f: - while chunk := odb_f.read(16 * 1024 * 1024): - hasher.update(chunk) - odb_hash = hasher.hexdigest() - else: - odb_hash = "N/A" + for ext in [".odb", ".rtlil", ".v"]: + result_file = pathlib.Path( + str(f).replace("logs/", "results/").replace(".log", ext) + ) + if result_file.exists(): + hasher = hashlib.sha1() + with open(result_file, "rb") as odb_f: + while chunk := odb_f.read(16 * 1024 * 1024): + hasher.update(chunk) + odb_hash = hasher.hexdigest() + break + else: + odb_hash = "N/A" if not found: print("No elapsed time found in", str(f), file=sys.stderr) From c537a7e91e304ba60f6e98683badd7acf241e999 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=98yvind=20Harboe?= Date: Mon, 7 Jul 2025 22:55:56 +0200 Subject: [PATCH 3/3] logs: log hashes to ORFS log files MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In the bazel-orfs use-case, the .odb files are not all present in the finish step, so log as we go along in addition to the finish step. A little bit more verbose than I could have wished for, but it does the job. Refine later, possibly. Signed-off-by: Øyvind Harboe --- flow/scripts/flow.sh | 3 +++ flow/util/genElapsedTime.py | 14 +++++++++++--- 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/flow/scripts/flow.sh b/flow/scripts/flow.sh index 2d2e037927..96ef5615e0 100755 --- a/flow/scripts/flow.sh +++ b/flow/scripts/flow.sh @@ -6,3 +6,6 @@ echo Running $2.tcl, stage $1 $OPENROAD_EXE $OPENROAD_ARGS -exit $SCRIPTS_DIR/noop.tcl 2>&1 >$LOG_DIR/$1.tmp.log; \ eval "$TIME_CMD $OPENROAD_CMD -no_splash $SCRIPTS_DIR/$2.tcl -metrics $LOG_DIR/$1.json" 2>&1 | \ tee -a $(realpath $LOG_DIR/$1.tmp.log)) +# Log the hash for this step. The summary "make elapsed" in "make finish", +# will not have all the .odb files for the bazel-orfs use-case. +$PYTHON_EXE $UTILS_DIR/genElapsedTime.py --match $1 -d $LOG_DIR | tee -a $(realpath $LOG_DIR/$1.log) diff --git a/flow/util/genElapsedTime.py b/flow/util/genElapsedTime.py index 83e992c70e..93a762afc7 100755 --- a/flow/util/genElapsedTime.py +++ b/flow/util/genElapsedTime.py @@ -18,13 +18,17 @@ def print_log_dir_times(logdir, args): first = True totalElapsed = 0 total_max_memory = 0 - print(logdir) + if not args.match: + print(logdir) # Loop on all log files in the directory for f in sorted(pathlib.Path(logdir).glob("**/*.log")): if "eqy_output" in str(f): continue # Extract Elapsed Time line from log file + stem = os.path.splitext(os.path.basename(str(f)))[0] + if args.match and args.match != stem: + continue with open(str(f)) as logfile: found = False for line in logfile: @@ -95,7 +99,7 @@ def print_log_dir_times(logdir, args): print( format_str % ( - os.path.splitext(os.path.basename(str(f)))[0], + stem, elapsedTime, peak_memory, odb_hash[0:20], @@ -104,7 +108,7 @@ def print_log_dir_times(logdir, args): totalElapsed += elapsedTime total_max_memory = max(total_max_memory, int(peak_memory)) - if totalElapsed != 0: + if totalElapsed != 0 and not args.match: print(format_str % ("Total", totalElapsed, total_max_memory, "")) @@ -112,6 +116,10 @@ def scan_logs(args): parser = argparse.ArgumentParser( description="Print elapsed time for every step in the flow" ) + parser.add_argument( + "--match", + help="Match this string in the log file names", + ) parser.add_argument( "--logDir", "-d", required=True, nargs="+", help="Log files directories" )