drt: FlexGC detailed-route performance (bit-identical)#10847
drt: FlexGC detailed-route performance (bit-identical)#10847saurav-fermions wants to merge 2 commits into
Conversation
…% GC init) The dominant FlexGC boost::polygon cost is not the per-pair spacing-check set intersections but fixed-polygon corner materialization during GC worker init. isPolygonCorner() ran poly_set.get() (a full boost::polygon scanline reconstruction of the net polygon set) once per corner, giving O(corners * fixed_poly_size) per net. perf on aes shows initNet_pins_polygonCorners_helper at ~20.7% cumulative. Materialize each net's fixed-polygon vertex set once per layer into a hash set (collectPolygonCorners) and test corner membership with an O(1) lookup. The predicate is identical (a point is a corner iff it equals a boundary/hole vertex), the fixed set is immutable during init, so DRC decisions, markers and geometry are unchanged. Measured (aes, interleaved median, quiet box): - initNet_pins_polygonCorners_helper cumulative: 20.7% -> 2.5% - detailed_route wall-clock: -18.5% @ 1 thread, -15.2% @ 8 threads - routed DEF byte-identical (MD5) vs baseline on gcd + aes at 1 and 8 threads - drt ctest: 27/27 pass (incl. golden log_compare) Transparent change, no flag, thread-count invariant. See GC_POLYGON_REPORT.md. Signed-off-by: Saurav Singh <saurav.singh@fermions.co>
Replace per-call heap-allocated scratch vectors in the FlexGC route-time DRC checker with per-thread (thread_local) reusable buffers (clear() + reuse capacity). Sites: checkMetalSpacing_main region-query results, checkMetalSpacing_prl_hasPolyEdge, checkMetalSpacing_short_skipSameNet, checkMetalCornerSpacing_main, bg2gtl, and isPolygonCorner. DRT parallelism is across FlexDRWorkers (one worker per OMP thread), so thread_local keeps each worker's buffers private. boost::polygon get() and the region queries append via back_inserter and return deterministic order, so clearing before each use reproduces identical contents. Bit-identical: gcd_nangate45 and aes_nangate45 routed DEFs MD5-identical to baseline at 1 and 8 threads. drt ctest 27/27. Allocations: aes -2.40% (2.970B -> 2.899B), gcd -3.25%. aes DR wall-clock -0.54% (median). The maze A* priority queue was already reused upstream (cleanup() keeps capacity, per-worker member), so no maze churn remained to remove; the remaining churn is largely boost::polygon-internal and not safely poolable. See DRT_ALLOC_REPORT.md. Signed-off-by: Saurav Singh <saurav.singh@fermions.co>
There was a problem hiding this comment.
Code Review
This pull request optimizes the GC initialization and checking phases by utilizing thread_local scratch buffers to avoid frequent vector allocations, and caching polygon corners in a hash set to enable O(1) lookups instead of repeated scanline reconstructions. The feedback suggests further optimizing the polygon corner cache by making it thread_local and persisting it across pins of the same net, clearing it only when the net changes.
| std::map<frLayerNum, | ||
| std::unordered_set<std::pair<frCoord, frCoord>, | ||
| boost::hash<std::pair<frCoord, frCoord>>>> | ||
| fixedCornerCache; |
There was a problem hiding this comment.
Currently, fixedCornerCache is local to initNet_pins_polygonCorners_helper, which is called once per pin. This means the cache is cleared and re-materialized for every single pin, even if multiple pins belong to the same net and share the same layer. Since the net's fixed polygon set (net->getPolygons(true)[layerNum]) is identical across all pins of the same net, we can optimize this further by making the cache thread_local and persisting it across pins of the same net, clearing it only when the net changes.
thread_local gcNet* cachedNet = nullptr;
thread_local std::map<frLayerNum,
std::unordered_set<std::pair<frCoord, frCoord>,
boost::hash<std::pair<frCoord, frCoord>>>>
fixedCornerCache;
if (cachedNet != net) {
fixedCornerCache.clear();
cachedNet = net;
}18e09fd to
6078642
Compare
|
Thanks for the review.
|
Summary
Two constant-factor optimizations to FlexGC, the dominant detailed-route DRC cost. Routing output is byte-for-byte identical (DEF MD5 unchanged at 1 and 8 threads).
collectPolygonCorners) and test corner membership with an O(1) lookup, instead of a fullboost::polygonscanline reconstruction per corner. Predicate is identical (a point is a corner iff it equals a boundary/hole vertex). On aes,initNet_pins_polygonCorners_helpercumulative time ~20.7% -> ~2.5%.thread_localreusable buffers (clear()+ reuse capacity), acrosscheckMetalSpacing_*,checkMetalCornerSpacing_main,bg2gtl, and the corner-collection path.Testing
Built
openroad; full drt regression suite passes (19/19, incl. goldenlog_compare). Routed DEF is bit-identical to baseline.Notes
src/stachange; no cross-repo dependency.