Parallel `findClkSkew`

Signed-off-by: Krzysztof Bieganski <kbieganski@antmicro.com>
This commit is contained in:
Krzysztof Bieganski 2024-04-04 10:20:37 +02:00
parent abacd6c89c
commit 18b94651bb
1 changed files with 76 additions and 24 deletions

View File

@ -18,9 +18,11 @@
#include <cmath> // abs #include <cmath> // abs
#include <algorithm> #include <algorithm>
#include <stack>
#include "Report.hh" #include "Report.hh"
#include "Debug.hh" #include "Debug.hh"
#include "DispatchQueue.hh"
#include "Units.hh" #include "Units.hh"
#include "TimingArc.hh" #include "TimingArc.hh"
#include "Liberty.hh" #include "Liberty.hh"
@ -278,25 +280,46 @@ ClkSkews::findClkSkew(ConstClockSeq &clks,
ConstClockSet clk_set; ConstClockSet clk_set;
for (const Clock *clk : clks) for (const Clock *clk : clks)
clk_set.insert(clk); clk_set.insert(clk);
const auto findClkSkew = [this, corner, setup_hold, include_internal_latency, &clk_set](Vertex *src_vertex, ClkSkewMap &skews) {
VertexOutEdgeIterator edge_iter(src_vertex, graph_);
while (edge_iter.hasNext()) {
Edge *edge = edge_iter.next();
if (edge->role()->genericRole() != TimingRole::regClkToQ()) continue;
Vertex *q_vertex = edge->to(graph_);
RiseFall *rf = edge->timingArcSet()->isRisingFallingEdge();
RiseFallBoth *src_rf = rf
? rf->asRiseFallBoth()
: RiseFallBoth::riseFall();
findClkSkewFrom(src_vertex, q_vertex, src_rf, clk_set, corner, setup_hold, include_internal_latency, skews);
}
};
for (Vertex *src_vertex : *graph_->regClkVertices()) { if (threadCount() > 1) {
if (hasClkPaths(src_vertex, clk_set)) { std::vector<ClkSkewMap> partial_skews(thread_count_, skews);
VertexOutEdgeIterator edge_iter(src_vertex, graph_); for (Vertex *src_vertex : *graph_->regClkVertices()) {
while (edge_iter.hasNext()) { if (!hasClkPaths(src_vertex, clk_set)) continue;
Edge *edge = edge_iter.next(); dispatch_queue_->dispatch([findClkSkew, src_vertex, &partial_skews](int i) {
if (edge->role()->genericRole() == TimingRole::regClkToQ()) { findClkSkew(src_vertex, partial_skews[i]);
Vertex *q_vertex = edge->to(graph_); });
const RiseFall *rf = edge->timingArcSet()->isRisingFallingEdge(); }
const RiseFallBoth *src_rf = rf dispatch_queue_->finishTasks();
? rf->asRiseFallBoth() for (size_t i = 0; i < partial_skews.size(); i++) {
: RiseFallBoth::riseFall(); for (auto [clk, partial_skew] : partial_skews[i]) {
findClkSkewFrom(src_vertex, q_vertex, src_rf, clk_set, auto ins = skews.insert(std::make_pair(clk, partial_skew));
corner, setup_hold, include_internal_latency, if (ins.second) continue;
skews); ClkSkew &final_skew = ins.first->second;
} if (abs(partial_skew.skew()) > abs(final_skew.skew())) {
final_skew = partial_skew;
}
} }
} }
} }
else {
for (Vertex *src_vertex : *graph_->regClkVertices()) {
if (!hasClkPaths(src_vertex, clk_set)) continue;
findClkSkew(src_vertex, skews);
}
}
return skews; return skews;
} }
@ -432,16 +455,45 @@ ClkSkews::findFanout(Vertex *from)
from->name(sdc_network_)); from->name(sdc_network_));
VertexSet endpoints(graph_); VertexSet endpoints(graph_);
FanOutSrchPred pred(this); FanOutSrchPred pred(this);
BfsFwdIterator fanout_iter(BfsIndex::other, &pred, this); if (threadCount() > 1) {
fanout_iter.enqueue(from); // This is called from multiple threads, so BfsVisitor cannot be used, as it modifies vertex state.
while (fanout_iter.hasNext()) { // Uses depth-first search; breadth-first would work too, but a stack is slightly faster than a queue.
Vertex *fanout = fanout_iter.next(); thread_local static std::unordered_set<Vertex *> visited;
if (fanout->hasChecks()) { thread_local static std::stack<Vertex *, std::vector<Vertex *>> stack;
debugPrint(debug_, "fanout", 1, " endpoint %s", visited.clear();
fanout->name(sdc_network_)); stack.push(from);
endpoints.insert(fanout); visited.insert(from);
while (!stack.empty()) {
Vertex *fanout = stack.top();
stack.pop();
if (fanout->hasChecks()) {
debugPrint(debug_, "fanout", 1, " endpoint %s",
fanout->name(sdc_network_));
endpoints.insert(fanout);
}
if (!pred.searchFrom(fanout)) continue;
VertexOutEdgeIterator edge_iter(fanout, graph_);
while (edge_iter.hasNext()) {
Edge *edge = edge_iter.next();
Vertex *to = edge->to(graph_);
if (pred.searchThru(edge) && pred.searchTo(to) && visited.insert(to).second) {
stack.push(to);
}
}
}
}
else {
BfsFwdIterator fanout_iter(BfsIndex::other, &pred, this);
fanout_iter.enqueue(from);
while (fanout_iter.hasNext()) {
Vertex *fanout = fanout_iter.next();
if (fanout->hasChecks()) {
debugPrint(debug_, "fanout", 1, " endpoint %s",
fanout->name(sdc_network_));
endpoints.insert(fanout);
}
fanout_iter.enqueueAdjacentVertices(fanout);
} }
fanout_iter.enqueueAdjacentVertices(fanout);
} }
return endpoints; return endpoints;
} }