From be8731274b08c87cfa139b5fc2588213af9bc40f Mon Sep 17 00:00:00 2001 From: Natalia Date: Mon, 24 Nov 2025 02:16:29 -0800 Subject: [PATCH 1/5] Deduplicate by word in report paths --- include/sta/Sta.hh | 9 ++--- search/ReportPath.cc | 76 +++++++++++++++++++++++++++++++++------ search/ReportPath.hh | 12 ++++--- search/Search.i | 12 +++++-- search/Search.tcl | 7 +++- search/Sta.cc | 11 ++++-- test/path_dedup_worst.ok | 3 ++ test/path_dedup_worst.tcl | 40 +++++++++++++++++++++ test/regression_vars.tcl | 1 + 9 files changed, 145 insertions(+), 26 deletions(-) create mode 100644 test/path_dedup_worst.ok create mode 100644 test/path_dedup_worst.tcl diff --git a/include/sta/Sta.hh b/include/sta/Sta.hh index cdf67203c..bfd2ad96e 100644 --- a/include/sta/Sta.hh +++ b/include/sta/Sta.hh @@ -857,16 +857,17 @@ public: void setReportPathDigits(int digits); void setReportPathNoSplit(bool no_split); void setReportPathSigmas(bool report_sigmas); + void setReportDedupByWord(bool dedup_by_word); // Header above reportPathEnd results. void reportPathEndHeader(); // Footer below reportPathEnd results. void reportPathEndFooter(); // Format report_path_endpoint only: - // Previous path end is used to detect path group changes - // so headers are reported by group. + // Previous path end is used to: + // - detect path group changes so headers are reported by group. + // - JSON format: if not first, add a comma before appending new path void reportPathEnd(PathEnd *end, - PathEnd *prev_end, - bool last); + PathEnd *prev_end); void reportPathEnd(PathEnd *end); void reportPathEnds(PathEndSeq *ends); ReportPath *reportPath() { return report_path_; } diff --git a/search/ReportPath.cc b/search/ReportPath.cc index 6b991557d..dd58cc009 100644 --- a/search/ReportPath.cc +++ b/search/ReportPath.cc @@ -48,6 +48,7 @@ #include "GraphDelayCalc.hh" #include "ClkInfo.hh" #include "Tag.hh" +#include "ParseBus.hh" #include "PathAnalysisPt.hh" #include "PathGroup.hh" #include "CheckMinPulseWidths.hh" @@ -61,6 +62,8 @@ #include "Genclks.hh" #include "Variables.hh" +#include + namespace sta { using std::string; @@ -140,6 +143,7 @@ const float ReportPath::field_blank_ = -1.0; ReportPath::ReportPath(StaState *sta) : StaState(sta), format_(ReportPathFormat::full), + dedup_by_word_(false), no_split_(false), report_sigmas_(false), start_end_pt_width_(80), @@ -290,18 +294,23 @@ ReportPath::setReportSigmas(bool report) report_sigmas_ = report; } +void +ReportPath::setReportDedupByWord(bool dedup_by_word) +{ + dedup_by_word_ = dedup_by_word; +} + //////////////////////////////////////////////////////////////// void ReportPath::reportPathEnd(const PathEnd *end) const { - reportPathEnd(end, nullptr, true); + reportPathEnd(end, nullptr); } void ReportPath::reportPathEnd(const PathEnd *end, - const PathEnd *prev_end, - bool last) const + const PathEnd *prev_end) const { switch (format_) { case ReportPathFormat::full: @@ -327,11 +336,34 @@ ReportPath::reportPathEnd(const PathEnd *end, reportSlackOnly(end); break; case ReportPathFormat::json: - reportJson(end, last); + reportJson(end, prev_end); break; } } +inline std::string getBusName(const StaState *state, + const sta::Network *sdc_network, + PathEnd *end) { + char escape = sdc_network->pathEscape(); + PathExpanded expanded(end->path(), state); + const Pin *end_pin = expanded.endPath()->vertex(state)->pin(); + const char *endpoint_name = sdc_network->pathName(end_pin); + bool is_bus; + std::string bus_name; + int index; + parseBusName(endpoint_name, + '[', + ']', + escape, + is_bus, + bus_name, + index); + if (is_bus) { + return bus_name; + } + return ""; +} + void ReportPath::reportPathEnds(const PathEndSeq *ends) const { @@ -339,11 +371,34 @@ ReportPath::reportPathEnds(const PathEndSeq *ends) const if (ends && !ends->empty()) { PathEnd *prev_end = nullptr; PathEndSeq::ConstIterator end_iter(ends); + Set qualified_ends; + + if (dedup_by_word_) { + Map worst_slack_by_bus; + while (end_iter.hasNext()) { + PathEnd *end = end_iter.next(); + auto bus_name = getBusName(this, sdc_network_, end); + if (bus_name.length()) { + if (worst_slack_by_bus.count(bus_name) == 0 || + worst_slack_by_bus[bus_name]->slack(this) > end->slack(this)) + worst_slack_by_bus[bus_name] = end; + } + else + qualified_ends.insert(end); + } + + for (auto &[_, end]: worst_slack_by_bus) + qualified_ends.insert(end); + } + + end_iter = ends; while (end_iter.hasNext()) { PathEnd *end = end_iter.next(); - reportPathEnd(end, prev_end, !end_iter.hasNext()); - prev_end = end; - } + if (!dedup_by_word_ || qualified_ends.count(end)) { + reportPathEnd(end, prev_end); + prev_end = end; + } + } } else { if (format_ != ReportPathFormat::json) @@ -1080,9 +1135,12 @@ ReportPath::reportJsonFooter() const void ReportPath::reportJson(const PathEnd *end, - bool last) const + const PathEnd *prev_end) const { string result; + if (prev_end) { + result += ", "; + } result += "{\n"; stringAppend(result, " \"type\": \"%s\",\n", end->typeName()); stringAppend(result, " \"path_group\": \"%s\",\n", @@ -1145,8 +1203,6 @@ ReportPath::reportJson(const PathEnd *end, delayAsFloat(end->slack(this))); } result += "}"; - if (!last) - result += ","; report_->reportLineString(result); } diff --git a/search/ReportPath.hh b/search/ReportPath.hh index b9f4364b2..1fa520cd4 100644 --- a/search/ReportPath.hh +++ b/search/ReportPath.hh @@ -59,6 +59,7 @@ public: void setNoSplit(bool no_split); bool reportSigmas() const { return report_sigmas_; } void setReportSigmas(bool report); + void setReportDedupByWord(bool dedup_by_word); ReportField *findField(const char *name) const; // Header above reportPathEnd results. @@ -67,11 +68,11 @@ public: void reportPathEndFooter() const; void reportPathEnd(const PathEnd *end) const; // Format report_path_endpoint only: - // Previous path end is used to detect path group changes - // so headers are reported by group. + // Previous path end is used to: + // - detect path group changes so headers are reported by group. + // - JSON format: if not first, add a comma before appending new path void reportPathEnd(const PathEnd *end, - const PathEnd *prev_end, - bool last) const; + const PathEnd *prev_end) const; void reportPathEnds(const PathEndSeq *ends) const; void reportPath(const Path *path) const; @@ -94,7 +95,7 @@ public: void reportJsonHeader() const; void reportJsonFooter() const; void reportJson(const PathEnd *end, - bool last) const; + const PathEnd *prev_end) const; void reportJson(const Path *path) const; void reportJson(const Path *path, const char *path_name, @@ -472,6 +473,7 @@ protected: bool report_input_pin_; bool report_hier_pins_; bool report_net_; + bool dedup_by_word_; bool no_split_; int digits_; bool report_sigmas_; diff --git a/search/Search.i b/search/Search.i index 3e2e761aa..09869f255 100644 --- a/search/Search.i +++ b/search/Search.i @@ -389,6 +389,7 @@ find_path_ends(ExceptionFrom *from, corner, delay_min_max, group_path_count, endpoint_path_count, unique_pins, unique_edges, + unique_pins, slack_min, slack_max, sort_by_slack, groups->size() ? groups : nullptr, @@ -421,10 +422,9 @@ report_path_end(PathEnd *end) void report_path_end2(PathEnd *end, - PathEnd *prev_end, - bool last) + PathEnd *prev_end) { - Sta::sta()->reportPathEnd(end, prev_end, last); + Sta::sta()->reportPathEnd(end, prev_end); } void @@ -496,6 +496,12 @@ set_report_path_no_split(bool no_split) Sta::sta()->setReportPathNoSplit(no_split); } +void +set_report_path_dedup_by_word(bool dedup_by_word) +{ + Sta::sta()->setReportDedupByWord(dedup_by_word); +} + void set_report_path_sigmas(bool report_sigmas) { diff --git a/search/Search.tcl b/search/Search.tcl index ba5acba48..df7d3bc88 100644 --- a/search/Search.tcl +++ b/search/Search.tcl @@ -429,6 +429,7 @@ define_cmd_args "report_checks" \ [-fields capacitance|slew|fanout|input_pin|net|src_attr]\ [-digits digits]\ [-no_line_splits]\ + [-dedup_by_word]\ [> filename] [>> filename]} proc_redirect report_checks { @@ -887,7 +888,7 @@ proc parse_report_path_options { cmd args_var default_format unset path_options } parse_key_args $cmd args path_options {-format -digits -fields} \ - path_options {-no_line_splits -report_sigmas} $unknown_key_is_error + path_options {-no_line_splits -report_sigmas -dedup_by_word} $unknown_key_is_error set format $default_format if [info exists path_options(-format)] { @@ -959,6 +960,10 @@ proc parse_report_path_options { cmd args_var default_format $report_cap $report_slew $report_fanout $report_src_attr set_report_path_no_split [info exists path_options(-no_line_splits)] + + if { [info exists path_options(-dedup_by_word)] } { + set_report_path_dedup_by_word 1 + } } ################################################################ diff --git a/search/Sta.cc b/search/Sta.cc index 51158cf87..6129f64bc 100644 --- a/search/Sta.cc +++ b/search/Sta.cc @@ -2567,6 +2567,12 @@ Sta::setReportPathSigmas(bool report_sigmas) report_path_->setReportSigmas(report_sigmas); } +void +Sta::setReportDedupByWord(bool dedup_by_word) +{ + report_path_->setReportDedupByWord(dedup_by_word); +} + void Sta::reportPathEndHeader() { @@ -2587,10 +2593,9 @@ Sta::reportPathEnd(PathEnd *end) void Sta::reportPathEnd(PathEnd *end, - PathEnd *prev_end, - bool last) + PathEnd *prev_end) { - report_path_->reportPathEnd(end, prev_end, last); + report_path_->reportPathEnd(end, prev_end); } void diff --git a/test/path_dedup_worst.ok b/test/path_dedup_worst.ok new file mode 100644 index 000000000..e57c758a7 --- /dev/null +++ b/test/path_dedup_worst.ok @@ -0,0 +1,3 @@ +Warning: ../examples/gcd_sky130hd.v line 527, module sky130_fd_sc_hd__tapvpwrvgnd_1 not found. Creating black box for TAP_11. +resp_msg count: 1 +resp_msg[15] count: 1 diff --git a/test/path_dedup_worst.tcl b/test/path_dedup_worst.tcl new file mode 100644 index 000000000..87e4e6027 --- /dev/null +++ b/test/path_dedup_worst.tcl @@ -0,0 +1,40 @@ +read_liberty ../examples/sky130hd_tt.lib.gz +read_verilog ../examples/gcd_sky130hd.v +link_design gcd +read_sdc ../examples/gcd_sky130hd.sdc + +proc count_pattern {pattern filename} { + set count 0 + set fh [open $filename r] + while {[gets $fh line] >= 0} { + if {[regexp $pattern $line]} { + incr count + } + } + close $fh + return $count +} + +proc make_checks_rpt {args} { + set temp_file_id [file tempfile temp_filename] + close $temp_file_id + + report_checks\ + -format end\ + {*}$args > $temp_filename + + return $temp_filename +} + +set checks_rpt [make_checks_rpt\ + -group_path_count 999\ + -fields {input_pins slew}\ + -dedup_by_word] + +puts "resp_msg count: [count_pattern "resp_msg" $checks_rpt]" +puts "resp_msg[15] count: [count_pattern "resp_msg\\\[15\\\]" $checks_rpt]" + -deduplication_mode keep_worst] + +puts "resp_msg count: [count_pattern "resp_msg" $checks_rpt]\nresp_msg[15] count: [count_pattern "resp_msg\\\[15\\\]" $checks_rpt]" + +file delete -force $checks_rpt diff --git a/test/regression_vars.tcl b/test/regression_vars.tcl index acf6906bc..194b0a5a8 100644 --- a/test/regression_vars.tcl +++ b/test/regression_vars.tcl @@ -159,6 +159,7 @@ record_public_tests { liberty_latch3 package_require path_group_names + path_dedup_worst power_json prima3 report_checks_sorted From be806fa2c75bb4089036a6a37f4283877ecdc02d Mon Sep 17 00:00:00 2001 From: nataliakokoromyti <126305457+nataliakokoromyti@users.noreply.github.com> Date: Tue, 30 Dec 2025 06:13:44 -0800 Subject: [PATCH 2/5] rm duplicate puts line --- test/path_dedup_worst.tcl | 3 --- 1 file changed, 3 deletions(-) diff --git a/test/path_dedup_worst.tcl b/test/path_dedup_worst.tcl index 87e4e6027..50c68ef8a 100644 --- a/test/path_dedup_worst.tcl +++ b/test/path_dedup_worst.tcl @@ -32,9 +32,6 @@ set checks_rpt [make_checks_rpt\ -dedup_by_word] puts "resp_msg count: [count_pattern "resp_msg" $checks_rpt]" -puts "resp_msg[15] count: [count_pattern "resp_msg\\\[15\\\]" $checks_rpt]" - -deduplication_mode keep_worst] - puts "resp_msg count: [count_pattern "resp_msg" $checks_rpt]\nresp_msg[15] count: [count_pattern "resp_msg\\\[15\\\]" $checks_rpt]" file delete -force $checks_rpt From 153c485e264ae092ea69a41e8d7f09582f2eb514 Mon Sep 17 00:00:00 2001 From: nataliakokoromyti <126305457+nataliakokoromyti@users.noreply.github.com> Date: Tue, 30 Dec 2025 06:21:27 -0800 Subject: [PATCH 3/5] rm duplicate puts line --- test/path_dedup_worst.tcl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/path_dedup_worst.tcl b/test/path_dedup_worst.tcl index 50c68ef8a..5f9299bee 100644 --- a/test/path_dedup_worst.tcl +++ b/test/path_dedup_worst.tcl @@ -32,6 +32,6 @@ set checks_rpt [make_checks_rpt\ -dedup_by_word] puts "resp_msg count: [count_pattern "resp_msg" $checks_rpt]" -puts "resp_msg count: [count_pattern "resp_msg" $checks_rpt]\nresp_msg[15] count: [count_pattern "resp_msg\\\[15\\\]" $checks_rpt]" +puts "resp_msg[15] count: [count_pattern "resp_msg\\\[15\\\]" $checks_rpt]" file delete -force $checks_rpt From 2d2f5faf9e820a8572e8dd9c9cd09ec953875f55 Mon Sep 17 00:00:00 2001 From: nataliakokoromyti <126305457+nataliakokoromyti@users.noreply.github.com> Date: Tue, 30 Dec 2025 06:27:36 -0800 Subject: [PATCH 4/5] rm extra unique_pins --- search/Search.i | 1 - 1 file changed, 1 deletion(-) diff --git a/search/Search.i b/search/Search.i index 09869f255..15625d367 100644 --- a/search/Search.i +++ b/search/Search.i @@ -389,7 +389,6 @@ find_path_ends(ExceptionFrom *from, corner, delay_min_max, group_path_count, endpoint_path_count, unique_pins, unique_edges, - unique_pins, slack_min, slack_max, sort_by_slack, groups->size() ? groups : nullptr, From 2ae73695878d9f99204f2cc5b1e13620a414b8cb Mon Sep 17 00:00:00 2001 From: nataliakokoromyti <126305457+nataliakokoromyti@users.noreply.github.com> Date: Tue, 30 Dec 2025 06:33:58 -0800 Subject: [PATCH 5/5] update ReportPath.cc --- search/ReportPath.cc | 2 -- 1 file changed, 2 deletions(-) diff --git a/search/ReportPath.cc b/search/ReportPath.cc index dd58cc009..777048280 100644 --- a/search/ReportPath.cc +++ b/search/ReportPath.cc @@ -62,8 +62,6 @@ #include "Genclks.hh" #include "Variables.hh" -#include - namespace sta { using std::string;