mirror of
https://github.com/The-OpenROAD-Project/OpenSTA.git
synced 2026-09-05 09:02:12 +02:00
Dispatch fixed-size chunks (8 vertices per task) instead of one contiguous slice per thread, so threads that finish early pick up more work. Chunk size vs. runtime is U-shaped; 8 is the smallest size at the bottom of the curve. report_checks on a 32-core machine (min of 5 runs): - gcd_sky130hd, 32 threads: 1845 us -> 1255 us (-32%) - gcd_sky130hd, 8 threads: 1254 us -> 1117 us (-11%) - aes_nangate45 (~17k inst): neutral; single-threaded path unchanged. To keep upstream merges clean, the fork logic lives in a new BfsIterator::visitLevelChunked() wrapped in "OpenROAD fork: BFS chunked dispatch" markers, called from one marked line in visitParallel's existing else branch. All other upstream lines are byte-identical. This is a stop-gap until the upstream BFS rework lands; on merge conflict take upstream and drop it. Signed-off-by: Drew <[email protected]>
185 lines
6.0 KiB
C++
185 lines
6.0 KiB
C++
// OpenSTA, Static Timing Analyzer
|
|
// Copyright (c) 2026, Parallax Software, Inc.
|
|
//
|
|
// This program is free software: you can redistribute it and/or modify
|
|
// it under the terms of the GNU General Public License as published by
|
|
// the Free Software Foundation, either version 3 of the License, or
|
|
// (at your option) any later version.
|
|
//
|
|
// This program is distributed in the hope that it will be useful,
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
// GNU General Public License for more details.
|
|
//
|
|
// You should have received a copy of the GNU General Public License
|
|
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
//
|
|
// The origin of this software must not be misrepresented; you must not
|
|
// claim that you wrote the original software.
|
|
//
|
|
// Altered source versions must be plainly marked as such, and must not be
|
|
// misrepresented as being the original software.
|
|
//
|
|
// This notice may not be removed or altered from any source distribution.
|
|
|
|
#pragma once
|
|
|
|
#include <functional>
|
|
#include <mutex>
|
|
#include <vector>
|
|
|
|
#include "GraphClass.hh"
|
|
#include "Iterator.hh"
|
|
#include "StaState.hh"
|
|
#include "VertexVisitor.hh"
|
|
|
|
namespace sta {
|
|
|
|
class SearchPred;
|
|
class BfsFwdIterator;
|
|
class BfsBkwdIterator;
|
|
|
|
using VertexFn = std::function<void(Vertex*)>;
|
|
|
|
// LevelQueue is a vector of vertex vectors indexed by logic level.
|
|
using LevelQueue = std::vector<VertexSeq>;
|
|
|
|
// Abstract base class for forward and backward breadth first search iterators.
|
|
// Visit all of the vertices at a level before moving to the next.
|
|
// Use enqueue to seed the search.
|
|
// Use enqueueAdjacentVertices as a vertex is visited to queue the
|
|
// fanout vertices filtered by the search predicate.
|
|
//
|
|
// Vertices are marked as being in the queue by using a flag on
|
|
// the vertex indexed by bfs_index. A unique flag is only needed
|
|
// if the BFS in in use when other BFS's are simultaneously in use.
|
|
class BfsIterator : public StaState
|
|
{
|
|
public:
|
|
// Make sure that the BFS queue is deep enough for the max logic level.
|
|
void ensureSize();
|
|
// Reset to virgin state.
|
|
void clear();
|
|
// Apply fn to each vertex and clear.
|
|
void clear(const VertexFn &fn);
|
|
[[nodiscard]] bool empty() const;
|
|
// Enqueue a vertex to search from.
|
|
void enqueue(Vertex *vertex);
|
|
// Enqueue vertices adjacent to a vertex.
|
|
virtual void enqueueAdjacentVertices(Vertex *vertex) = 0;
|
|
virtual void enqueueAdjacentVertices(Vertex *vertex,
|
|
const Mode *mode) = 0;
|
|
|
|
[[nodiscard]] bool inQueue(Vertex *vertex);
|
|
void checkInQueue(Vertex *vertex);
|
|
// Notify iterator that vertex will be deleted.
|
|
void deleteVertexBefore(Vertex *vertex);
|
|
void remove(Vertex *vertex);
|
|
void reportEntries() const;
|
|
|
|
// Apply visitor to all vertices in the queue in level order.
|
|
// Returns the number of vertices that are visited.
|
|
virtual int visit(Level to_level,
|
|
VertexVisitor *visitor);
|
|
// Apply visitor to all vertices in the queue in level order,
|
|
// using threads to parallelize the visits. visitor must be thread safe.
|
|
// Returns the number of vertices that are visited.
|
|
int visitParallel(Level to_level,
|
|
VertexVisitor *visitor);
|
|
|
|
bool hasNext();
|
|
bool hasNext(Level to_level);
|
|
Vertex *next();
|
|
|
|
protected:
|
|
BfsIterator(BfsIndex bfs_index,
|
|
Level level_min,
|
|
Level level_max,
|
|
SearchPred *search_pred,
|
|
StaState *sta);
|
|
void init();
|
|
void deleteEntries(Level level);
|
|
virtual bool levelLess(Level level1,
|
|
Level level2) const = 0;
|
|
virtual bool levelLessOrEqual(Level level1,
|
|
Level level2) const = 0;
|
|
virtual void incrLevel(Level &level) const = 0;
|
|
void deleteEntries();
|
|
void checkLevel(Vertex *vertex,
|
|
Level level);
|
|
void findNext(Level to_level);
|
|
|
|
// ---- OpenROAD fork: BFS chunked dispatch (begin) ----
|
|
// Dispatch level_vertices to the worker pool in fixed-size chunks so
|
|
// idle threads pick up remaining work. Stop-gap until upstream BFS
|
|
// rework lands; on merge conflict take upstream and drop this.
|
|
void visitLevelChunked(VertexSeq &level_vertices,
|
|
Level level,
|
|
std::vector<VertexVisitor *> &visitors);
|
|
// ---- OpenROAD fork: BFS chunked dispatch (end) ----
|
|
|
|
BfsIndex bfs_index_;
|
|
Level level_min_;
|
|
Level level_max_;
|
|
SearchPred *search_pred_;
|
|
LevelQueue queue_;
|
|
std::mutex queue_lock_;
|
|
// Min (max) level of queued vertices.
|
|
Level first_level_;
|
|
// Max (min) level of queued vertices.
|
|
Level last_level_;
|
|
|
|
friend class BfsFwdIterator;
|
|
friend class BfsBkwdIterator;
|
|
};
|
|
|
|
class BfsFwdIterator : public BfsIterator
|
|
{
|
|
public:
|
|
BfsFwdIterator(BfsIndex bfs_index,
|
|
SearchPred *search_pred,
|
|
StaState *sta);
|
|
~BfsFwdIterator() override;
|
|
void enqueueAdjacentVertices(Vertex *vertex) override;
|
|
void enqueueAdjacentVertices(Vertex *vertex,
|
|
const Mode *mode) override;
|
|
using BfsIterator::enqueueAdjacentVertices;
|
|
void enqueueFanout(Vertex *vertex);
|
|
void enqueueFanout(Vertex *vertex,
|
|
const Mode *mode);
|
|
|
|
protected:
|
|
bool levelLessOrEqual(Level level1,
|
|
Level level2) const override;
|
|
bool levelLess(Level level1,
|
|
Level level2) const override;
|
|
void incrLevel(Level &level) const override;
|
|
};
|
|
|
|
class BfsBkwdIterator : public BfsIterator
|
|
{
|
|
public:
|
|
BfsBkwdIterator(BfsIndex bfs_index,
|
|
SearchPred *search_pred,
|
|
StaState *sta);
|
|
~BfsBkwdIterator() override;
|
|
void enqueueAdjacentVertices(Vertex *vertex) override;
|
|
void enqueueAdjacentVertices(Vertex *vertex,
|
|
const Mode *mode) override;
|
|
using BfsIterator::enqueueAdjacentVertices;
|
|
void enqueueFanin(Vertex *vertex);
|
|
void enqueueFanin(Vertex *vertex,
|
|
const Mode *mode);
|
|
|
|
protected:
|
|
void enqueueFanin(Vertex *vertex,
|
|
SearchPred *search_pred);
|
|
bool levelLessOrEqual(Level level1,
|
|
Level level2) const override;
|
|
bool levelLess(Level level1,
|
|
Level level2) const override;
|
|
void incrLevel(Level &level) const override;
|
|
};
|
|
|
|
} // namespace sta
|