grt: FastRoute maze-routing performance (bit-identical)#10848
grt: FastRoute maze-routing performance (bit-identical)#10848saurav-fermions wants to merge 2 commits into
Conversation
addNeighborPoints allocated two local vectors (heapVisited, heapQueue) sized to the net node count on every call. On medium03 (98.6K cells) that is ~175K calls and ~125M node-slots of alloc+init churn per global_route, and the function is ~9% of the GRT profile. Reuse two member scratch buffers instead, clearing/resizing the used region each call rather than reallocating. This mirrors the existing maze2D visited_2D_/queue_2D_ reuse pattern. heapVisited is reset with assign(numNodes,false); heapQueue is write-before-read so only its size matters. Pure constant-factor change, no algorithmic difference: the global_route guide output is byte-identical (same MD5) before and after, and the grt regression suite stays 131/131. ~4.6% median global_route speedup on medium03 (10385ms -> 9910ms, median of 3 runs each). Signed-off-by: Saurav Singh <saurav.singh@fermions.co>
…bit-identical routing)
The 3D maze Dijkstra inner loop in mazeRouteMSMDOrder3D re-read the popped
("current") cell's distance, path length, and direction from the boost
multi_array 3D distance grids once per direction block -- up to six times per
popped node. These values are loop-invariant during a node's relaxation: only
the neighbor cells (tmpX/tmpY/tmpL) are written, never [curL][curY][curX]
itself. Each read pays a full boost::multi_array 3D index computation.
Hoist d1_3D_, path_len_3D_, and directions_3D_ for the current cell into locals
(cur_d1, cur_path_len, cur_dir) immediately after removeMin3D, and use them in
the six direction blocks. This removes ~5 redundant 3D index computations per
popped node. On aes_nangate45 the 3D maze pops ~22.4M nodes per global_route,
so the saved indexing is substantial.
Pure constant-factor change, no algorithmic difference. cur_d1 is int and is
promoted to float in `cur_d1 + cost + penalty` exactly as the original
multi_array read was, so arithmetic is identical.
Bit-identity proof (write_guides MD5, baseline bc114e8639 vs this change):
gcd_nangate45 : da0e9f94e649c9f65443ce70d79ec7a9 (identical)
aes_nangate45 : ccd6428a729cfea6c7228ac4d341c892 (identical, 156K cells)
Timing (global_route only, interleaved base vs opt, median of 6, aes 156K cells):
base 4790 ms -> opt 4469 ms (~6.7% faster, -321 ms)
grt regression: 131/131 pass (suite includes guideok comparisons across many
designs, an additional bit-identity check).
Signed-off-by: Saurav Singh <saurav.singh@fermions.co>
There was a problem hiding this comment.
Code Review
This pull request optimizes 3D maze routing performance by reusing member scratch buffers (visited_3D_ and queue_3D_) to avoid per-call allocations, and caching current cell states to eliminate redundant 3D index computations. The reviewer suggests replacing std::vector<bool> with std::vector<char> for the scratch buffer to avoid bit-packing overhead and further improve performance.
| // Reusable BFS scratch for addNeighborPoints (3D). Mirrors the maze2D | ||
| // visited_2D_/queue_2D_ reuse pattern: allocate once, reset the used region | ||
| // each call instead of reallocating per call. | ||
| std::vector<bool> visited_3D_; |
There was a problem hiding this comment.
Using std::vector<bool> can be slower due to the overhead of bit-packing and bit-manipulation operations. Since this PR focuses on performance optimizations, using std::vector<char> (or std::vector<uint8_t>) instead of std::vector<bool> is a great opportunity to improve performance by allowing direct byte access.
| std::vector<bool> visited_3D_; | |
| std::vector<char> visited_3D_; |
| visited_3D_.assign(numNodes, false); | ||
| queue_3D_.resize(numNodes); | ||
| std::vector<bool>& heapVisited = visited_3D_; | ||
| std::vector<int>& heapQueue = queue_3D_; |
There was a problem hiding this comment.
Update the type of heapVisited to std::vector<char>& to match the change of visited_3D_ from std::vector<bool> to std::vector<char> for better performance.
| visited_3D_.assign(numNodes, false); | |
| queue_3D_.resize(numNodes); | |
| std::vector<bool>& heapVisited = visited_3D_; | |
| std::vector<int>& heapQueue = queue_3D_; | |
| visited_3D_.assign(numNodes, 0); | |
| queue_3D_.resize(numNodes); | |
| std::vector<char>& heapVisited = visited_3D_; | |
| std::vector<int>& heapQueue = queue_3D_; |
osamahammad21
left a comment
There was a problem hiding this comment.
revert the STA commit change. I assume this was accidental
48a25fd to
e317fc0
Compare
|
@osamahammad21 good catch — the On the gemini suggestion to switch |
Summary
Two constant-factor optimizations to the FastRoute global router. Global-route guide output is byte-for-byte identical before and after.
heapVisited,heapQueue) inaddNeighborPointsinstead of allocating net-node-sized local vectors on every call. Mirrors the existingmaze2Dvisited_2D_/queue_2D_reuse pattern.mazeRouteMSMDOrder3D— hoist the popped cell's distance / path-length / direction out of the boostmulti_array3D grids into locals, removing ~5 redundant 3D index computations per popped node.Testing
Built
openroad; full grt regression suite passes (140/140, incl. goldenlog_compare). Guide output bit-identical to baseline.Notes
src/stachange; no cross-repo dependency.