Merge pull request #327 from The-OpenROAD-Project/driver-vertex-level-cache

added driver vertex levelization
This commit is contained in:
Matt Liberty 2026-04-02 21:22:03 +00:00 committed by GitHub
commit 94bb37bb4a
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
9 changed files with 4686 additions and 2 deletions

View File

@ -28,6 +28,7 @@
#include "Graph.hh"
#include "FuncExpr.hh"
#include "TimingRole.hh"
#include "search/Levelize.hh"
#include "Liberty.hh"
#include "Network.hh"
#include "Clock.hh"
@ -118,6 +119,32 @@ remove_delay_slew_annotations()
Sta::sta()->removeDelaySlewAnnotations();
}
void
report_levelized_drvr_vertices(int max_count)
{
Sta *sta = Sta::sta();
sta->ensureGraph();
const VertexSeq &drvrs = sta->levelizedDrvrVertices();
Report *report = sta->report();
const Network *network = sta->network();
report->report("driver vertex count {}", drvrs.size());
Level prev_level = -1;
int n = 0;
for (Vertex *vertex : drvrs) {
Level level = vertex->level();
if (level < prev_level)
report->report("level order violated {} {} < {}",
network->pathName(vertex->pin()),
level, prev_level);
if (n < max_count)
report->report("{} level={}",
network->pathName(vertex->pin()),
level);
prev_level = level;
n++;
}
}
%} // inline
////////////////////////////////////////////////////////////////

View File

@ -1325,6 +1325,7 @@ public:
// Ensure that the timing graph has been built.
Graph *ensureGraph();
void ensureClkArrivals();
const VertexSeq& levelizedDrvrVertices();
// Find all arc delays and vertex slews with delay calculator.
virtual void findDelays();

View File

@ -53,7 +53,8 @@ Levelize::Levelize(StaState *sta) :
level_space_(10),
roots_(makeVertexSet(sta)),
relevelize_from_(makeVertexSet(sta)),
observer_(nullptr)
observer_(nullptr),
drvr_vertices_level_valid_(false)
{
}
@ -90,6 +91,8 @@ Levelize::clear()
loops_.clear();
loop_edges_.clear();
max_level_ = 0;
drvr_vertices_level_valid_ = false;
levelized_drvr_vertices_.clear();
}
void
@ -546,6 +549,7 @@ Levelize::setLevel(Vertex *vertex,
void
Levelize::invalid()
{
drvr_vertices_level_valid_ = false;
if (levelized_) {
debugPrint(debug_, "levelize", 1, "levels invalid");
levelized_ = false;
@ -559,6 +563,8 @@ Levelize::deleteVertexBefore(Vertex *vertex)
if (levelized_) {
roots_.erase(vertex);
relevelize_from_.erase(vertex);
drvr_vertices_level_valid_ = false;
levelized_drvr_vertices_.clear();
}
}
@ -570,6 +576,7 @@ Levelize::relevelizeFrom(Vertex *vertex)
vertex->to_string(this));
relevelize_from_.insert(vertex);
levels_valid_ = false;
drvr_vertices_level_valid_ = false;
}
}
@ -584,6 +591,7 @@ Levelize::deleteEdgeBefore(Edge *edge)
// fails because the DFS path will be missing.
levelized_ = false;
levels_valid_ = false;
drvr_vertices_level_valid_ = false;
}
}
@ -710,6 +718,36 @@ Levelize::checkLevels()
}
}
void
Levelize::levelizeDrvrVertices()
{
levelized_drvr_vertices_.clear();
// Rough estimate: ~half of vertices are drivers
levelized_drvr_vertices_.reserve(graph_->vertexCount() / 2);
VertexIterator vertex_iter(graph_);
while (vertex_iter.hasNext()) {
Vertex *vertex = vertex_iter.next();
if (vertex->isDriver(network_))
levelized_drvr_vertices_.emplace_back(vertex);
}
sort(levelized_drvr_vertices_,
[this](const Vertex *a, const Vertex *b) {
if (a->level() != b->level())
return a->level() < b->level();
return VertexNameLess(network_)(a, b);
});
drvr_vertices_level_valid_ = true;
}
const VertexSeq &
Levelize::levelizedDrvrVertices()
{
ensureLevelized();
if (!drvr_vertices_level_valid_)
levelizeDrvrVertices();
return levelized_drvr_vertices_;
}
////////////////////////////////////////////////////////////////
GraphLoop::GraphLoop(EdgeSeq *edges) :

View File

@ -74,7 +74,8 @@ public:
void checkLevels();
// Public for regression testing.
void levelize();
const VertexSeq &levelizedDrvrVertices();
protected:
void findRoots();
VertexSeq sortedRootsWithFanout();
@ -104,6 +105,7 @@ protected:
void clearLoopEdges();
void deleteLoops();
void reportPath(EdgeSeq &path) const;
void levelizeDrvrVertices();
bool levelized_;
bool levels_valid_;
@ -116,6 +118,8 @@ protected:
EdgeSet disabled_loop_edges_;
EdgeSet latch_d_to_q_edges_;
LevelizeObserver *observer_;
VertexSeq levelized_drvr_vertices_;
bool drvr_vertices_level_valid_;
};
// Loops broken by levelization may not necessarily be combinational.

View File

@ -2900,6 +2900,12 @@ Sta::ensureClkArrivals()
search_->findClkArrivals();
}
const VertexSeq&
Sta::levelizedDrvrVertices()
{
return levelize_->levelizedDrvrVertices();
}
////////////////////////////////////////////////////////////////
VertexSet &

4466
test/gcd_asap7.v Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,127 @@
OpenSTA 3.1.0 211aea7497 Copyright (c) 2026, Parallax Software, Inc.
License GPLv3: GNU GPL version 3 <http://gnu.org/licenses/gpl.html>
This is free software, and you are free to change and redistribute it
under certain conditions; type `show_copying' for details.
This program comes with ABSOLUTELY NO WARRANTY; for details type `show_warranty'.
Warning 198: gcd_asap7.v line 844, module FAx1_ASAP7_75t_R not found. Creating black box for _106_.
Warning 198: gcd_asap7.v line 925, module HAxp5_ASAP7_75t_R not found. Creating black box for _115_.
Warning 198: gcd_asap7.v line 1079, module XOR2x2_ASAP7_75t_R not found. Creating black box for _140_.
Warning 198: gcd_asap7.v line 1159, module OR2x2_ASAP7_75t_R not found. Creating black box for _156_.
Warning 198: gcd_asap7.v line 1164, module OA21x2_ASAP7_75t_R not found. Creating black box for _157_.
Warning 198: gcd_asap7.v line 1170, module OAI21x1_ASAP7_75t_R not found. Creating black box for _158_.
Warning 198: gcd_asap7.v line 1210, module NOR2x1_ASAP7_75t_R not found. Creating black box for _165_.
Warning 198: gcd_asap7.v line 1219, module OR4x1_ASAP7_75t_R not found. Creating black box for _167_.
Warning 198: gcd_asap7.v line 1232, module AO21x1_ASAP7_75t_R not found. Creating black box for _169_.
Warning 198: gcd_asap7.v line 1265, module NAND2x1_ASAP7_75t_R not found. Creating black box for _175_.
Warning 198: gcd_asap7.v line 1313, module AO221x1_ASAP7_75t_R not found. Creating black box for _184_.
Warning 198: gcd_asap7.v line 3244, module TIEHIx1_ASAP7_75t_R not found. Creating black box for _216_.
Warning 198: gcd_asap7.v line 3251, module AOI211x1_ASAP7_75t_R not found. Creating black box for _218_.
Warning 198: gcd_asap7.v line 3258, module AND3x1_ASAP7_75t_R not found. Creating black box for _219_.
Warning 198: gcd_asap7.v line 3269, module OA211x2_ASAP7_75t_R not found. Creating black box for _221_.
Warning 198: gcd_asap7.v line 3735, module OAI22x1_ASAP7_75t_R not found. Creating black box for _305_.
Warning 198: gcd_asap7.v line 4197, module AND4x1_ASAP7_75t_R not found. Creating black box for _386_.
Warning 198: gcd_asap7.v line 4204, module AND5x1_ASAP7_75t_R not found. Creating black box for _387_.
Warning 198: gcd_asap7.v line 4259, module DFFHQNx1_ASAP7_75t_R not found. Creating black box for \ctrl.state.out[0]$_DFF_P_ .
driver vertex count 106
clk level=0
req_msg[0] level=0
req_msg[10] level=0
req_msg[11] level=0
req_msg[12] level=0
req_msg[13] level=0
req_msg[14] level=0
req_msg[15] level=0
req_msg[16] level=0
req_msg[17] level=0
req_msg[18] level=0
req_msg[19] level=0
req_msg[1] level=0
req_msg[20] level=0
req_msg[21] level=0
req_msg[22] level=0
req_msg[23] level=0
req_msg[24] level=0
req_msg[25] level=0
req_msg[26] level=0
req_msg[27] level=0
req_msg[28] level=0
req_msg[29] level=0
req_msg[2] level=0
req_msg[30] level=0
req_msg[31] level=0
req_msg[3] level=0
req_msg[4] level=0
req_msg[5] level=0
req_msg[6] level=0
req_msg[7] level=0
req_msg[8] level=0
req_msg[9] level=0
req_val level=0
reset level=0
resp_rdy level=0
_215_/_129_/Y level=10
_215_/_130_/Y level=10
_215_/_131_/Y level=10
_215_/_132_/Y level=10
_215_/_133_/Y level=10
_215_/_134_/Y level=10
_215_/_135_/Y level=10
_215_/_136_/Y level=10
_215_/_137_/Y level=10
_215_/_138_/Y level=10
_215_/_139_/Y level=10
_215_/_166_/Y level=10
_215_/_174_/Y level=10
_215_/_180_/Y level=10
_215_/_182_/Y level=10
_215_/_186_/Y level=10
_215_/_193_/Y level=10
_217_/Y level=10
_222_/Y level=10
_224_/Y level=10
_227_/Y level=10
_228_/Y level=10
_229_/Y level=10
_230_/Y level=10
_231_/Y level=10
_232_/Y level=10
_233_/Y level=10
_234_/Y level=10
_235_/Y level=10
_236_/Y level=10
_237_/Y level=10
_238_/Y level=10
_239_/Y level=10
_240_/Y level=10
_241_/Y level=10
_242_/Y level=10
_243_/Y level=10
_244_/Y level=10
_245_/Y level=10
_354_/Y level=10
_357_/Y level=10
_361_/Y level=10
_365_/Y level=10
_368_/Y level=10
_373_/Y level=10
_376_/Y level=10
_380_/Y level=10
_384_/Y level=10
_388_/Y level=10
_393_/Y level=10
_395_/Y level=10
_396_/Y level=10
_278_/Y level=20
_282_/Y level=20
_286_/Y level=20
_291_/Y level=20
_296_/Y level=20
_301_/Y level=20
_304_/Y level=20
_308_/Y level=20
_312_/Y level=20
_315_/Y level=20
_320_/Y level=20
_323_/Y level=20
%

View File

@ -0,0 +1,14 @@
# Test for Levelize::levelizedDrvrVertices() API.
# Verifies:
# 1. Returns driver vertices in non-decreasing level order
# 2. All returned vertices are drivers
source helpers.tcl
read_liberty asap7/asap7sc7p5t_INVBUF_RVT_TT_nldm_220122.lib.gz
read_liberty asap7/asap7sc7p5t_INVBUF_LVT_TT_nldm_220122.lib.gz
read_liberty asap7/asap7sc7p5t_INVBUF_SLVT_TT_nldm_220122.lib.gz
read_verilog gcd_asap7.v
link_design gcd
create_clock -name clk -period 500 {clk}
# Report first 100 driver vertices in level order and total count
sta::report_levelized_drvr_vertices 100

View File

@ -148,6 +148,7 @@ record_public_tests {
get_lib_pins_of_objects
get_noargs
get_objrefs
levelized_drvr_vertices1
liberty_arcs_one2one_1
liberty_arcs_one2one_2
liberty_backslash_eol