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 <algorithm>
#include <stack>
#include "Report.hh"
#include "Debug.hh"
#include "DispatchQueue.hh"
#include "Units.hh"
#include "TimingArc.hh"
#include "Liberty.hh"
@ -278,25 +280,46 @@ ClkSkews::findClkSkew(ConstClockSeq &clks,
ConstClockSet clk_set;
for (const Clock *clk : clks)
clk_set.insert(clk);
for (Vertex *src_vertex : *graph_->regClkVertices()) {
if (hasClkPaths(src_vertex, clk_set)) {
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()) {
if (edge->role()->genericRole() != TimingRole::regClkToQ()) continue;
Vertex *q_vertex = edge->to(graph_);
const RiseFall *rf = edge->timingArcSet()->isRisingFallingEdge();
const RiseFallBoth *src_rf = rf
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);
findClkSkewFrom(src_vertex, q_vertex, src_rf, clk_set, corner, setup_hold, include_internal_latency, skews);
}
};
if (threadCount() > 1) {
std::vector<ClkSkewMap> partial_skews(thread_count_, skews);
for (Vertex *src_vertex : *graph_->regClkVertices()) {
if (!hasClkPaths(src_vertex, clk_set)) continue;
dispatch_queue_->dispatch([findClkSkew, src_vertex, &partial_skews](int i) {
findClkSkew(src_vertex, partial_skews[i]);
});
}
dispatch_queue_->finishTasks();
for (size_t i = 0; i < partial_skews.size(); i++) {
for (auto [clk, partial_skew] : partial_skews[i]) {
auto ins = skews.insert(std::make_pair(clk, partial_skew));
if (ins.second) continue;
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;
}
@ -432,6 +455,34 @@ ClkSkews::findFanout(Vertex *from)
from->name(sdc_network_));
VertexSet endpoints(graph_);
FanOutSrchPred pred(this);
if (threadCount() > 1) {
// This is called from multiple threads, so BfsVisitor cannot be used, as it modifies vertex state.
// Uses depth-first search; breadth-first would work too, but a stack is slightly faster than a queue.
thread_local static std::unordered_set<Vertex *> visited;
thread_local static std::stack<Vertex *, std::vector<Vertex *>> stack;
visited.clear();
stack.push(from);
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()) {
@ -443,6 +494,7 @@ ClkSkews::findFanout(Vertex *from)
}
fanout_iter.enqueueAdjacentVertices(fanout);
}
}
return endpoints;
}