report_clock_skews cache results resolves #113

Signed-off-by: James Cherry <cherry@parallaxsw.com>
This commit is contained in:
James Cherry 2025-12-12 15:37:30 -07:00
parent 0dd7d1bbdc
commit 3bda441305
4 changed files with 115 additions and 77 deletions

View File

@ -1365,6 +1365,7 @@ protected:
virtual void makeCheckMaxSkews(); virtual void makeCheckMaxSkews();
virtual void makeReportPath(); virtual void makeReportPath();
virtual void makePower(); virtual void makePower();
virtual void makeClkSkews();
virtual void makeObservers(); virtual void makeObservers();
NetworkEdit *networkCmdEdit(); NetworkEdit *networkCmdEdit();

View File

@ -50,40 +50,6 @@ namespace sta {
using std::abs; using std::abs;
// Source/target clock skew.
class ClkSkew
{
public:
ClkSkew();
ClkSkew(Path *src_path,
Path *tgt_path,
bool include_internal_latency,
StaState *sta);
ClkSkew(const ClkSkew &clk_skew);
void operator=(const ClkSkew &clk_skew);
Path *srcPath() { return src_path_; }
Path *tgtPath() { return tgt_path_; }
float srcLatency(const StaState *sta);
float tgtLatency(const StaState *sta);
float srcInternalClkLatency(const StaState *sta);
float tgtInternalClkLatency(const StaState *sta);
Crpr crpr(const StaState *sta);
float uncertainty(const StaState *sta);
float skew() const { return skew_; }
static bool srcTgtPathNameLess(ClkSkew &clk_skew1,
ClkSkew &clk_skew2,
const StaState *sta);
private:
float clkTreeDelay(Path *clk_path,
const StaState *sta);
Path *src_path_;
Path *tgt_path_;
bool include_internal_latency_;
float skew_;
};
ClkSkew::ClkSkew() : ClkSkew::ClkSkew() :
src_path_(nullptr), src_path_(nullptr),
tgt_path_(nullptr), tgt_path_(nullptr),
@ -206,10 +172,18 @@ ClkSkew::srcTgtPathNameLess(ClkSkew &clk_skew1,
ClkSkews::ClkSkews(StaState *sta) : ClkSkews::ClkSkews(StaState *sta) :
StaState(sta), StaState(sta),
corner_(nullptr),
include_internal_latency_(true),
fanout_pred_(sta) fanout_pred_(sta)
{ {
} }
void
ClkSkews::clear()
{
skews_.clear();
}
void void
ClkSkews::reportClkSkew(ConstClockSeq &clks, ClkSkews::reportClkSkew(ConstClockSeq &clks,
const Corner *corner, const Corner *corner,
@ -217,8 +191,7 @@ ClkSkews::reportClkSkew(ConstClockSeq &clks,
bool include_internal_latency, bool include_internal_latency,
int digits) int digits)
{ {
ClkSkewMap skews = findClkSkew(clks, corner, setup_hold, findClkSkew(clks, corner, include_internal_latency);
include_internal_latency);
// Sort the clocks to report in a stable order. // Sort the clocks to report in a stable order.
ConstClockSeq sorted_clks; ConstClockSeq sorted_clks;
@ -228,9 +201,9 @@ ClkSkews::reportClkSkew(ConstClockSeq &clks,
for (const Clock *clk : sorted_clks) { for (const Clock *clk : sorted_clks) {
report_->reportLine("Clock %s", clk->name()); report_->reportLine("Clock %s", clk->name());
auto skew_itr = skews.find(clk); auto skew_itr = skews_.find(clk);
if (skew_itr != skews.end()) if (skew_itr != skews_.end())
reportClkSkew(skew_itr->second, digits); reportClkSkew(skew_itr->second[setup_hold->index()], digits);
else else
report_->reportLine("No launch/capture paths found."); report_->reportLine("No launch/capture paths found.");
report_->reportBlankLine(); report_->reportBlankLine();
@ -289,25 +262,30 @@ ClkSkews::findWorstClkSkew(const Corner *corner,
ConstClockSeq clks; ConstClockSeq clks;
for (const Clock *clk : *sdc_->clocks()) for (const Clock *clk : *sdc_->clocks())
clks.push_back(clk); clks.push_back(clk);
ClkSkewMap skews = findClkSkew(clks, corner, setup_hold, include_internal_latency); findClkSkew(clks, corner, include_internal_latency);
float worst_skew = 0.0; float worst_skew = 0.0;
for (const auto& [clk, clk_skew] : skews) { for (const auto& [clk, clk_skews] : skews_) {
float skew = clk_skew.skew(); float skew = clk_skews[setup_hold->index()].skew();
if (abs(skew) > abs(worst_skew)) if (abs(skew) > abs(worst_skew))
worst_skew = skew; worst_skew = skew;
} }
return worst_skew; return worst_skew;
} }
ClkSkewMap void
ClkSkews::findClkSkew(ConstClockSeq &clks, ClkSkews::findClkSkew(ConstClockSeq &clks,
const Corner *corner, const Corner *corner,
const SetupHold *setup_hold,
bool include_internal_latency) bool include_internal_latency)
{ {
ClkSkewMap skews; if (corner == corner_
&& include_internal_latency == include_internal_latency_
&& clks == clks_
&& !skews_.empty())
return;
skews_.clear();
clks_ = clks;
corner_ = corner; corner_ = corner;
setup_hold_ = setup_hold;
include_internal_latency_ = include_internal_latency; include_internal_latency_ = include_internal_latency;
clk_set_.clear(); clk_set_.clear();
@ -315,7 +293,7 @@ ClkSkews::findClkSkew(ConstClockSeq &clks,
clk_set_.insert(clk); clk_set_.insert(clk);
if (thread_count_ > 1) { if (thread_count_ > 1) {
std::vector<ClkSkewMap> partial_skews(thread_count_, skews); std::vector<ClkSkewMap> partial_skews(thread_count_);
for (Vertex *src_vertex : *graph_->regClkVertices()) { for (Vertex *src_vertex : *graph_->regClkVertices()) {
if (hasClkPaths(src_vertex)) { if (hasClkPaths(src_vertex)) {
dispatch_queue_->dispatch([this, src_vertex, &partial_skews](int i) { dispatch_queue_->dispatch([this, src_vertex, &partial_skews](int i) {
@ -328,14 +306,30 @@ ClkSkews::findClkSkew(ConstClockSeq &clks,
// Reduce skews from each register source. // Reduce skews from each register source.
for (size_t i = 0; i < partial_skews.size(); i++) { for (size_t i = 0; i < partial_skews.size(); i++) {
for (auto& [clk, partial_skew] : partial_skews[i]) { for (auto& [clk, partial_skew] : partial_skews[i]) {
auto ins = skews.insert(std::make_pair(clk, partial_skew)); auto itr = skews_.find(clk);
if (!ins.second) { if (itr == skews_.end()) {
ClkSkew &final_skew = ins.first->second; // Insert new entry using emplace with piecewise_construct
if (abs(partial_skew.skew()) > abs(final_skew.skew()) // This will default-construct the array, then we copy the elements
|| (fuzzyEqual(abs(partial_skew.skew()), abs(final_skew.skew())) auto result = skews_.emplace(std::piecewise_construct,
// Break ties based on source/target path names. std::forward_as_tuple(clk),
&& ClkSkew::srcTgtPathNameLess(partial_skew, final_skew, this))) std::make_tuple());
final_skew = partial_skew; itr = result.first;
// Copy array elements
for (int setup_hold_idx : SetupHold::rangeIndex())
itr->second[setup_hold_idx] = partial_skew[setup_hold_idx];
} else {
// Update existing entry
for (int setup_hold_idx : SetupHold::rangeIndex()) {
ClkSkew &final_skew = itr->second[setup_hold_idx];
ClkSkew &partial_skew_val = partial_skew[setup_hold_idx];
float partial_skew1 = partial_skew_val.skew();
float final_skew1 = final_skew.skew();
if (abs(partial_skew1) > abs(final_skew1)
|| (fuzzyEqual(abs(partial_skew1), abs(final_skew1))
// Break ties based on source/target path names.
&& ClkSkew::srcTgtPathNameLess(partial_skew_val, final_skew, this)))
final_skew = partial_skew_val;
}
} }
} }
} }
@ -343,10 +337,9 @@ ClkSkews::findClkSkew(ConstClockSeq &clks,
else { else {
for (Vertex *src_vertex : *graph_->regClkVertices()) { for (Vertex *src_vertex : *graph_->regClkVertices()) {
if (hasClkPaths(src_vertex)) if (hasClkPaths(src_vertex))
findClkSkewFrom(src_vertex, skews); findClkSkewFrom(src_vertex, skews_);
} }
} }
return skews;
} }
bool bool
@ -392,11 +385,8 @@ ClkSkews::findClkSkewFrom(Vertex *src_vertex,
while (edge_iter.hasNext()) { while (edge_iter.hasNext()) {
Edge *edge = edge_iter.next(); Edge *edge = edge_iter.next();
const TimingRole *role = edge->role(); const TimingRole *role = edge->role();
if (role->isTimingCheck() if (role->genericRole() == TimingRole::setup()
&& ((setup_hold_ == SetupHold::max() || role->genericRole() == TimingRole::hold()) {
&& role->genericRole() == TimingRole::setup())
|| ((setup_hold_ == SetupHold::min()
&& role->genericRole() == TimingRole::hold())))) {
Vertex *tgt_vertex = edge->from(graph_); Vertex *tgt_vertex = edge->from(graph_);
const RiseFall *tgt_rf1 = edge->timingArcSet()->isRisingFallingEdge(); const RiseFall *tgt_rf1 = edge->timingArcSet()->isRisingFallingEdge();
const RiseFallBoth *tgt_rf = tgt_rf1 const RiseFallBoth *tgt_rf = tgt_rf1
@ -416,16 +406,15 @@ ClkSkews::findClkSkew(Vertex *src_vertex,
ClkSkewMap &skews) ClkSkewMap &skews)
{ {
Unit *time_unit = units_->timeUnit(); Unit *time_unit = units_->timeUnit();
const SetupHold *tgt_min_max = setup_hold_->opposite();
VertexPathIterator src_iter(src_vertex, this); VertexPathIterator src_iter(src_vertex, this);
while (src_iter.hasNext()) { while (src_iter.hasNext()) {
Path *src_path = src_iter.next(); Path *src_path = src_iter.next();
const Clock *src_clk = src_path->clock(this); const Clock *src_clk = src_path->clock(this);
if (src_path->isClock(this) if (src_path->isClock(this)
&& src_rf->matches(src_path->transition(this)) && src_rf->matches(src_path->transition(this))
&& src_path->minMax(this) == setup_hold_
&& clk_set_.find(src_clk) != clk_set_.end()) { && clk_set_.find(src_clk) != clk_set_.end()) {
Corner *src_corner = src_path->pathAnalysisPt(this)->corner(); Corner *src_corner = src_path->pathAnalysisPt(this)->corner();
const MinMax *tgt_min_max = src_path->minMax(this)->opposite();
if (corner_ == nullptr if (corner_ == nullptr
|| src_corner == corner_) { || src_corner == corner_) {
VertexPathIterator tgt_iter(tgt_vertex, this); VertexPathIterator tgt_iter(tgt_vertex, this);
@ -438,7 +427,8 @@ ClkSkews::findClkSkew(Vertex *src_vertex,
&& tgt_path->minMax(this) == tgt_min_max && tgt_path->minMax(this) == tgt_min_max
&& tgt_path->pathAnalysisPt(this)->corner() == src_corner) { && tgt_path->pathAnalysisPt(this)->corner() == src_corner) {
ClkSkew probe(src_path, tgt_path, include_internal_latency_, this); ClkSkew probe(src_path, tgt_path, include_internal_latency_, this);
ClkSkew &clk_skew = skews[src_clk]; const SetupHold *setup_hold = src_path->minMax(this);
ClkSkew &clk_skew = skews[src_clk][setup_hold->index()];
debugPrint(debug_, "clk_skew", 2, debugPrint(debug_, "clk_skew", 2,
"%s %s %s -> %s %s %s crpr = %s skew = %s", "%s %s %s -> %s %s %s crpr = %s skew = %s",
network_->pathName(src_path->pin(this)), network_->pathName(src_path->pin(this)),

View File

@ -36,10 +36,43 @@
namespace sta { namespace sta {
class ClkSkew;
class SearchPred; class SearchPred;
typedef std::map<const Clock*, ClkSkew> ClkSkewMap; // Source/target clock skew.
class ClkSkew
{
public:
ClkSkew();
ClkSkew(Path *src_path,
Path *tgt_path,
bool include_internal_latency,
StaState *sta);
ClkSkew(const ClkSkew &clk_skew);
void operator=(const ClkSkew &clk_skew);
Path *srcPath() { return src_path_; }
Path *tgtPath() { return tgt_path_; }
float srcLatency(const StaState *sta);
float tgtLatency(const StaState *sta);
float srcInternalClkLatency(const StaState *sta);
float tgtInternalClkLatency(const StaState *sta);
Crpr crpr(const StaState *sta);
float uncertainty(const StaState *sta);
float skew() const { return skew_; }
static bool srcTgtPathNameLess(ClkSkew &clk_skew1,
ClkSkew &clk_skew2,
const StaState *sta);
private:
float clkTreeDelay(Path *clk_path,
const StaState *sta);
Path *src_path_;
Path *tgt_path_;
bool include_internal_latency_;
float skew_;
};
typedef std::map<const Clock*, ClkSkew[SetupHold::index_count]> ClkSkewMap;
class FanOutSrchPred : public SearchPred1 class FanOutSrchPred : public SearchPred1
{ {
@ -53,6 +86,7 @@ class ClkSkews : public StaState
{ {
public: public:
ClkSkews(StaState *sta); ClkSkews(StaState *sta);
void clear();
// Report clk skews for clks. // Report clk skews for clks.
void reportClkSkew(ConstClockSeq &clks, void reportClkSkew(ConstClockSeq &clks,
const Corner *corner, const Corner *corner,
@ -65,10 +99,9 @@ public:
bool include_internal_latency); bool include_internal_latency);
protected: protected:
ClkSkewMap findClkSkew(ConstClockSeq &clks, void findClkSkew(ConstClockSeq &clks,
const Corner *corner, const Corner *corner,
const SetupHold *setup_hold, bool include_internal_latency);
bool include_internal_latency);
bool hasClkPaths(Vertex *vertex); bool hasClkPaths(Vertex *vertex);
void findClkSkewFrom(Vertex *src_vertex, void findClkSkewFrom(Vertex *src_vertex,
ClkSkewMap &skews); ClkSkewMap &skews);
@ -88,11 +121,12 @@ protected:
void reportClkSkew(ClkSkew &clk_skew, void reportClkSkew(ClkSkew &clk_skew,
int digits); int digits);
ConstClockSeq clks_;
ConstClockSet clk_set_; ConstClockSet clk_set_;
const Corner *corner_; const Corner *corner_;
const SetupHold *setup_hold_;
bool include_internal_latency_; bool include_internal_latency_;
FanOutSrchPred fanout_pred_; FanOutSrchPred fanout_pred_;
ClkSkewMap skews_;
}; };
} // namespace } // namespace

View File

@ -310,6 +310,8 @@ Sta::makeComponents()
makeSdcNetwork(); makeSdcNetwork();
makeReportPath(); makeReportPath();
makePower(); makePower();
makeClkSkews();
setCmdNamespace1(CmdNamespace::sdc); setCmdNamespace1(CmdNamespace::sdc);
setThreadCount1(defaultThreadCount()); setThreadCount1(defaultThreadCount());
updateComponentsState(); updateComponentsState();
@ -371,8 +373,7 @@ Sta::updateComponentsState()
if (check_timing_) if (check_timing_)
check_timing_->copyState(this); check_timing_->copyState(this);
clk_network_->copyState(this); clk_network_->copyState(this);
if (clk_skews_) clk_skews_->copyState(this);
clk_skews_->copyState(this);
if (power_) if (power_)
power_->copyState(this); power_->copyState(this);
} }
@ -590,6 +591,7 @@ Sta::clear()
check_min_pulse_widths_->clear(); check_min_pulse_widths_->clear();
if (check_min_periods_) if (check_min_periods_)
check_min_periods_->clear(); check_min_periods_->clear();
clk_skews_->clear();
delete graph_; delete graph_;
graph_ = nullptr; graph_ = nullptr;
current_instance_ = nullptr; current_instance_ = nullptr;
@ -611,6 +613,7 @@ Sta::networkChanged()
check_min_pulse_widths_->clear(); check_min_pulse_widths_->clear();
if (check_min_periods_) if (check_min_periods_)
check_min_periods_->clear(); check_min_periods_->clear();
clk_skews_->clear();
delete graph_; delete graph_;
graph_ = nullptr; graph_ = nullptr;
graph_sdc_annotated_ = false; graph_sdc_annotated_ = false;
@ -2481,6 +2484,7 @@ Sta::findPathEnds(ExceptionFrom *from,
bool clk_gating_hold) bool clk_gating_hold)
{ {
searchPreamble(); searchPreamble();
clk_skews_->clear();
return search_->findPathEnds(from, thrus, to, unconstrained, return search_->findPathEnds(from, thrus, to, unconstrained,
corner, min_max, group_path_count, corner, min_max, group_path_count,
endpoint_path_count, endpoint_path_count,
@ -2628,8 +2632,9 @@ float
Sta::findWorstClkSkew(const SetupHold *setup_hold, Sta::findWorstClkSkew(const SetupHold *setup_hold,
bool include_internal_latency) bool include_internal_latency)
{ {
clkSkewPreamble(); clkSkewPreamble();
return clk_skews_->findWorstClkSkew(cmd_corner_, setup_hold, return clk_skews_->findWorstClkSkew(nullptr, setup_hold,
include_internal_latency); include_internal_latency);
} }
@ -2637,8 +2642,12 @@ void
Sta::clkSkewPreamble() Sta::clkSkewPreamble()
{ {
ensureClkArrivals(); ensureClkArrivals();
if (clk_skews_ == nullptr) }
clk_skews_ = new ClkSkews(this);
void
Sta::makeClkSkews()
{
clk_skews_ = new ClkSkews(this);
} }
//////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////
@ -4367,6 +4376,7 @@ Sta::replaceCellBefore(const Instance *inst,
} }
} }
delete pin_iter; delete pin_iter;
clk_skews_->clear();
} }
} }
@ -4431,6 +4441,7 @@ Sta::connectPinAfter(const Pin *pin)
} }
sdc_->connectPinAfter(pin); sdc_->connectPinAfter(pin);
sim_->connectPinAfter(pin); sim_->connectPinAfter(pin);
clk_skews_->clear();
} }
void void
@ -4521,6 +4532,7 @@ Sta::disconnectPinBefore(const Pin *pin)
} }
} }
} }
clk_skews_->clear();
} }
} }
@ -4671,6 +4683,7 @@ Sta::deletePinBefore(const Pin *pin)
sim_->deletePinBefore(pin); sim_->deletePinBefore(pin);
clk_network_->deletePinBefore(pin); clk_network_->deletePinBefore(pin);
power_->deletePinBefore(pin); power_->deletePinBefore(pin);
clk_skews_->clear();
} }
void void