diff --git a/src/rsz/README.md b/src/rsz/README.md index b0d62e4a589..596edcff7ec 100644 --- a/src/rsz/README.md +++ b/src/rsz/README.md @@ -289,6 +289,7 @@ repair_timing [-skip_last_gasp] [-repair_tns tns_end_percent] [-max_passes passes] + [-max_passes_per_iter passes] [-max_utilization util] [-max_buffer_percent buffer_percent] [-match_cell_footprint] @@ -311,6 +312,7 @@ repair_timing | `-skip_buffer_removal` | Flag to skip buffer removal. The default is to perform buffer removal transform during setup fixing. | | `-skip_last_gasp` | Flag to skip final ("last gasp") optimizations. The default is to perform greedy sizing at the end of optimization. | | `-repair_tns` | Percentage of violating endpoints to repair (0-100). When `tns_end_percent` is zero, only the worst endpoint is repaired. When `tns_end_percent` is 100 (default), all violating endpoints are repaired. | +| `-max_passes_per_iter` | Max number of repairs per iteration for `rsz::repairSetup`. | | `-max_utilization` | Defines the percentage of core area used. | | `-max_buffer_percent` | Specify a maximum number of buffers to insert to repair hold violations as a percentage of the number of instances in the design. The default value is `20`, and the allowed values are integers `[0, 100]`. | | `-match_cell_footprint` | Obey the Liberty cell footprint when swapping gates. | diff --git a/src/rsz/src/RepairSetup.cc b/src/rsz/src/RepairSetup.cc index 4ea5affd15a..56a95e1635f 100644 --- a/src/rsz/src/RepairSetup.cc +++ b/src/rsz/src/RepairSetup.cc @@ -60,6 +60,7 @@ namespace rsz { using std::max; using std::pair; +using std::set; using std::string; using std::vector; using utl::RSZ; @@ -87,9 +88,21 @@ void RepairSetup::init() db_network_ = resizer_->db_network_; } +struct SlackVertexPairComp +{ + bool operator()(const pair& end_slack1, + const pair& end_slack2) const + { + return end_slack1.second < end_slack2.second + || (end_slack1.second == end_slack2.second + && end_slack1.first->objectIdx() + < end_slack2.first->objectIdx()); + } +}; + bool RepairSetup::repairSetup(const float setup_slack_margin, const double repair_tns_end_percent, - const int max_passes, + const int max_passes_per_iter, const bool verbose, const bool skip_pin_swap, const bool skip_gate_cloning, @@ -110,7 +123,7 @@ bool RepairSetup::repairSetup(const float setup_slack_margin, // Sort failing endpoints by slack. const VertexSet* endpoints = sta_->endpoints(); - vector> violating_ends; + set, SlackVertexPairComp> violating_ends; // logger_->setDebugLevel(RSZ, "repair_setup", 2); // Should check here whether we can figure out the clock domain for each // vertex. This may be the place where we can do some round robin fun to @@ -119,14 +132,9 @@ bool RepairSetup::repairSetup(const float setup_slack_margin, for (Vertex* end : *endpoints) { const Slack end_slack = sta_->vertexSlack(end, max_); if (end_slack < setup_slack_margin) { - violating_ends.emplace_back(end, end_slack); + violating_ends.emplace(end, end_slack); } } - std::stable_sort(violating_ends.begin(), - violating_ends.end(), - [](const auto& end_slack1, const auto& end_slack2) { - return end_slack1.second < end_slack2.second; - }); debugPrint(logger_, RSZ, "repair_setup", @@ -174,8 +182,9 @@ bool RepairSetup::repairSetup(const float setup_slack_margin, printProgress(opto_iteration, false, false, false, num_viols); } float fix_rate_threshold = inc_fix_rate_threshold_; - for (const auto& end_original_slack : violating_ends) { - Vertex* end = end_original_slack.first; + while (num_viols > 0 && !violating_ends.empty()) { + Vertex* end = violating_ends.begin()->first; + violating_ends.erase(violating_ends.begin()); Slack end_slack = sta_->vertexSlack(end, max_); Slack worst_slack; Vertex* worst_vertex; @@ -202,14 +211,14 @@ bool RepairSetup::repairSetup(const float setup_slack_margin, " max_end_count {}", end->name(network_), end_index, max_end_count); // clang-format on - break; + continue; } Slack prev_end_slack = end_slack; Slack prev_worst_slack = worst_slack; int pass = 1; int decreasing_slack_passes = 0; resizer_->journalBegin(); - while (pass <= max_passes) { + while (pass <= max_passes_per_iter) { opto_iteration++; if (verbose) { printProgress(opto_iteration, false, false, false, num_viols); @@ -328,7 +337,8 @@ bool RepairSetup::repairSetup(const float setup_slack_margin, // Allow slack to increase to get out of local minima. // Do not update prev_end_slack so it saves the high water mark. decreasing_slack_passes++; - if (decreasing_slack_passes > decreasing_slack_max_passes_) { + if (decreasing_slack_passes > decreasing_slack_max_passes_ + || pass == max_passes_per_iter) { // Undo changes that reduced slack. debugPrint(logger_, RSZ, @@ -350,8 +360,8 @@ bool RepairSetup::repairSetup(const float setup_slack_margin, removed_buffer_count_); // clang-format off debugPrint(logger_, RSZ, "repair_setup", 1, "bailing out {} decreasing" - " passes {} > decreasig pass limit {}", end->name(network_), - decreasing_slack_passes, decreasing_slack_max_passes_); + " passes {} > decreasig pass limit {} or pass {} > max passes per iteration {}", end->name(network_), + decreasing_slack_passes, decreasing_slack_max_passes_, pass, max_passes_per_iter); // clang-format on break; } @@ -370,6 +380,10 @@ bool RepairSetup::repairSetup(const float setup_slack_margin, } pass++; } // while pass <= max_passes + if (pass == max_passes_per_iter + 1) { + // If violation was not fixed, placed it back to the queue + violating_ends.emplace(end, worst_slack); + } if (verbose) { printProgress(opto_iteration, true, false, false, num_viols); } diff --git a/src/rsz/src/RepairSetup.hh b/src/rsz/src/RepairSetup.hh index 1ea63d83fc0..a5fed741093 100644 --- a/src/rsz/src/RepairSetup.hh +++ b/src/rsz/src/RepairSetup.hh @@ -128,7 +128,7 @@ class RepairSetup : public sta::dbStaState // Percent of violating ends to repair to // reduce tns (0.0-1.0). double repair_tns_end_percent, - int max_passes, + int max_passes_per_iter, bool verbose, bool skip_pin_swap, bool skip_gate_cloning, diff --git a/src/rsz/src/Resizer.i b/src/rsz/src/Resizer.i index ec2d22f1dcf..506a845016c 100644 --- a/src/rsz/src/Resizer.i +++ b/src/rsz/src/Resizer.i @@ -595,7 +595,7 @@ repair_net_cmd(Net *net, bool repair_setup(double setup_margin, double repair_tns_end_percent, - int max_passes, + int max_passes_per_iter, bool match_cell_footprint, bool verbose, bool skip_pin_swap, bool skip_gate_cloning, bool skip_buffering, bool skip_buffer_removal, @@ -604,7 +604,7 @@ repair_setup(double setup_margin, ensureLinked(); Resizer *resizer = getResizer(); return resizer->repairSetup(setup_margin, repair_tns_end_percent, - max_passes, match_cell_footprint, verbose, + max_passes_per_iter, match_cell_footprint, verbose, skip_pin_swap, skip_gate_cloning, skip_buffering, skip_buffer_removal, skip_last_gasp); diff --git a/src/rsz/src/Resizer.tcl b/src/rsz/src/Resizer.tcl index 6e87d31cc05..d1eaab903ad 100644 --- a/src/rsz/src/Resizer.tcl +++ b/src/rsz/src/Resizer.tcl @@ -537,6 +537,7 @@ sta::define_cmd_args "repair_timing" {[-setup] [-hold]\ [-skip_last_gasp]\ [-repair_tns tns_end_percent]\ [-max_passes passes]\ + [-max_passes_per_iter passes_per_iter]\ [-max_buffer_percent buffer_percent]\ [-max_utilization util] \ [-match_cell_footprint] \ @@ -546,7 +547,7 @@ proc repair_timing { args } { sta::parse_key_args "repair_timing" args \ keys {-setup_margin -hold_margin -slack_margin \ -libraries -max_utilization -max_buffer_percent \ - -recover_power -repair_tns -max_passes} \ + -recover_power -repair_tns -max_passes -max_passes_per_iter} \ flags {-setup -hold -allow_setup_violations -skip_pin_swap -skip_gate_cloning \ -skip_buffering -skip_buffer_removal -skip_last_gasp -match_cell_footprint \ -verbose} @@ -612,6 +613,11 @@ proc repair_timing { args } { set max_passes $keys(-max_passes) } + set max_passes_per_iter 20 + if { [info exists keys(-max_passes_per_iter)] } { + set max_passes_per_iter $keys(-max_passes_per_iter) + } + set match_cell_footprint [info exists flags(-match_cell_footprint)] if { [design_is_routed] } { rsz::set_parasitics_src "detailed_routing" @@ -627,8 +633,8 @@ proc repair_timing { args } { set recovered_power [rsz::recover_power $recover_power_percent $match_cell_footprint] } else { if { $setup } { - set repaired_setup [rsz::repair_setup $setup_margin $repair_tns_end_percent $max_passes \ - $match_cell_footprint $verbose \ + set repaired_setup [rsz::repair_setup $setup_margin $repair_tns_end_percent \ + $max_passes_per_iter $match_cell_footprint $verbose \ $skip_pin_swap $skip_gate_cloning $skip_buffering \ $skip_buffer_removal $skip_last_gasp] }