8#ifndef AIE_DIALECT_AIE_TRANSFORMS_AIESTREAMDEPENDENCYANALYSIS_H
9#define AIE_DIALECT_AIE_TRANSFORMS_AIESTREAMDEPENDENCYANALYSIS_H
13#include "llvm/ADT/DenseMap.h"
14#include "llvm/ADT/DenseSet.h"
15#include "llvm/ADT/SmallVector.h"
57 llvm::SmallVector<mlir::Block *>
bds{};
58 llvm::SmallVector<mlir::Region *>
regions{};
85 llvm::SmallVector<StreamHop, 8>
hops{};
91 bool carries(std::optional<PacketInfoAttr> packet)
const {
167 llvm::ArrayRef<RoutedStream> streams)
const;
178 std::optional<uint64_t>
180 llvm::function_ref<uint64_t(DMABDOp)> bytesOf)
const;
184 llvm::function_ref<
void(DMABDOp)> visit)
const;
187 std::optional<uint64_t> tokensFromOthers(LockOp lock,
192 mutable DeviceOp device;
193 llvm::ArrayRef<RoutedStream> streams;
194 std::map<TileDMAChannel, llvm::SmallVector<DmaChannelProgram, 1>> programs;
196 std::map<TileDMAChannel, llvm::SmallVector<mlir::Operation *>> memcpys;
198 llvm::DenseMap<mlir::Operation *, const DmaChannelProgram *> lockUseProgram;
199 mutable llvm::DenseSet<const DmaChannelProgram *> visiting;
226 return {{tile, DMAChannelDir::S2MM, 0},
Kind::Core};
250 llvm::SmallVector<unsigned>
drainersOf(
unsigned agent)
const;
254 llvm::SmallVector<unsigned>
waitChain(llvm::ArrayRef<unsigned> from,
255 llvm::ArrayRef<unsigned> targets,
256 llvm::ArrayRef<unsigned> avoid)
const;
260 bool isModeled(
unsigned id)
const {
return modeled.contains(
id); }
263 std::string
describe(
unsigned id)
const;
266 enum class EdgeKind { Lock, Stream, Host };
273 bool receives =
false;
276 unsigned getOrCreate(
const Agent &agent);
277 std::optional<unsigned> lookup(
const Agent &agent)
const;
278 void addEdge(
unsigned from,
unsigned to, EdgeKind kind,
bool sends =
false,
279 bool receives =
false);
281 std::vector<Agent> agents;
282 std::vector<llvm::SmallVector<Edge, 4>> edges;
283 std::map<std::pair<Agent::Kind, TileDMAChannel>,
unsigned> agentIDs;
284 llvm::DenseSet<unsigned> modeled;
298 bool canBlock(
size_t f,
size_t g)
const;
301 bool silent(
size_t f)
const;
310 llvm::SmallVector<std::string>
assumptions(
size_t f,
size_t g)
const;
313 bool canStall(
size_t f)
const;
314 llvm::SmallVector<unsigned> blockingChain(
size_t f,
size_t g)
const;
316 llvm::ArrayRef<RoutedStream> streams;
320 mutable std::vector<std::optional<bool>> stalls, silence;
321 mutable llvm::DenseMap<std::pair<size_t, size_t>,
bool> blocks;
332 llvm::ArrayRef<RoutedStream>
getStreams()
const {
return streams; }
336 return llvm::ArrayRef(streams).take_front(numRequested);
344 bool conflict(
size_t s,
size_t t)
const;
353 std::string
explain(
size_t s,
size_t t)
const;
361 llvm::SmallVector<std::pair<size_t, size_t>>
unavoidable()
const;
369 std::optional<HoldCycle>
370 holdCycle(llvm::ArrayRef<llvm::SmallVector<StreamHop, 8>> routes,
371 bool forcedWaits =
false,
bool definite =
false)
const;
377 bool blocks(
size_t s,
size_t t)
const;
378 bool related(
size_t s,
size_t t)
const;
381 using TreeKey = std::tuple<TileID, Port, int, bool>;
383 std::optional<TreeKey> treeKey(
size_t s)
const;
387 const llvm::DenseMap<size_t, std::pair<size_t, size_t>> &
388 waitsFrom(
size_t a)
const;
392 std::vector<RoutedStream> streams;
395 std::vector<llvm::SmallVector<size_t, 2>> treeMembers;
396 std::vector<size_t> treeOf;
398 std::optional<llvm::DenseMap<size_t, std::pair<size_t, size_t>>>>
400 mutable std::optional<StreamDeadlockAnalysis> analysis;
llvm::ArrayRef< RoutedStream > getRequestedStreams() const
The streams the flow ops ask for, which come first in getStreams().
StreamConflicts & operator=(const StreamConflicts &)=delete
llvm::SmallVector< std::pair< size_t, size_t > > unavoidable() const
The requested streams where the first can hold up the second however they are routed,...
StreamConflicts(DeviceOp device)
bool mustSeparate(size_t s, size_t t) const
Whether a routing that puts packet streams s and t on one arbiter anywhere has a hold cycle: they con...
StreamConflicts(const StreamConflicts &)=delete
llvm::ArrayRef< RoutedStream > getStreams() const
bool conflict(size_t s, size_t t) const
Whether s and t can deadlock if they share an arbiter or a link.
std::optional< HoldCycle > holdCycle(llvm::ArrayRef< llvm::SmallVector< StreamHop, 8 > > routes, bool forcedWaits=false, bool definite=false) const
A cycle of waits the packet streams can deadlock in when routed along routes, indexed like getStreams...
std::string explain(size_t s, size_t t) const
Why s and t conflict.
Which streams can deadlock against each other if they share an arbiter or a link.
bool canBlock(size_t f, size_t g) const
Whether stream f, stalled at its receiver, can keep stream g from ever arriving: f carries more than ...
std::string explainBlock(size_t f, size_t g) const
Why f can block g: the chain of waits from f's receiver to g, and which links of it are assumed for l...
bool silent(size_t f) const
Whether stream f carries nothing, so it neither holds nor waits.
llvm::SmallVector< std::string > assumptions(size_t f, size_t g) const
What explainBlock(f, g) takes on trust rather than reads off the design, one sentence each.
StreamDeadlockAnalysis(DeviceOp device, llvm::ArrayRef< RoutedStream > streams)
streams must outlive the analysis.
How much data a stream carries over a run and how much a receiver takes in before it has to wait on a...
StreamVolumeAnalysis(DeviceOp device, llvm::ArrayRef< RoutedStream > streams)
std::optional< uint64_t > sendVolume(const RoutedStream &stream) const
Bytes the stream's source sends with the stream's packet id, headers included where the receiver keep...
StreamVolumeAnalysis & operator=(const StreamVolumeAnalysis &)=delete
std::optional< uint64_t > receiveCapacity(const StreamEndpoint &endpoint) const
Bytes the receiver at endpoint accepts before it waits on another agent, or nullopt when it never doe...
StreamVolumeAnalysis(const StreamVolumeAnalysis &)=delete
bool canFill(const StreamEndpoint &endpoint, llvm::ArrayRef< RoutedStream > streams) const
Whether streams can send the receiver at endpoint more than it takes in before it waits on another ag...
std::optional< bool > maySendAfter(const RoutedStream &first, const RoutedStream &then) const
Whether the source both streams come from can send a packet of then after one of first; nullopt if it...
Which agent waits on which.
std::optional< unsigned > agentAt(const StreamEndpoint &endpoint, bool sending) const
The agent pushing data into (sending) or pulling data out of the fabric at endpoint,...
std::string describe(unsigned id) const
llvm::SmallVector< unsigned > waitChain(llvm::ArrayRef< unsigned > from, llvm::ArrayRef< unsigned > targets, llvm::ArrayRef< unsigned > avoid) const
A shortest chain of waits from an agent in from to one in targets that avoids avoid,...
llvm::SmallVector< unsigned > drainersOf(unsigned agent) const
Agents whose progress frees room in agent for more incoming data: a core frees itself,...
const Agent & getAgent(unsigned id) const
bool isModeled(unsigned id) const
Whether the design programs this agent, so its waits are known rather than assumed.
StreamWaitGraph(DeviceOp device, llvm::ArrayRef< RoutedStream > streams, const StreamVolumeAnalysis &volumes)
struct TileID { friend std::ostream &operator<<(std::ostream &os, const TileID &s) { os<< "TileID("<< s.col<< ", "<< s.row<< ")"; return os; } friend std::string to_string(const TileID &s) { std::ostringstream ss; ss<< s; return ss.str(); } friend llvm::raw_ostream &operator<<(llvm::raw_ostream &os, const TileID &s) { os<< to_string(s); return os; } inline bool operator<(const TileID &rhs) const { return std::tie(col, row)< std::tie(rhs.col, rhs.row); } bool operator==(const TileID &rhs) const { return std::tie(col, row)==std::tie(rhs.col, rhs.row); } bool operator!=(const TileID &rhs) const { return !(*this==rhs);} int col, row;} TileID
std::string describeStream(const RoutedStream &stream)
Names the stream by its endpoints and packet id, e.g.
std::vector< RoutedStream > requestedStreams(DeviceOp device)
The streams the aie.flow and aie.packet_flow ops ask for, one per source, destination and packet id,...
std::vector< RoutedStream > traceRoutedStreams(DeviceOp device)
Follows every stream from its source tile port through the configured switchboxes,...
struct Port { WireBundle bundle; int channel; bool operator==(const Port &rhs) const { return std::tie(bundle, channel)==std::tie(rhs.bundle, rhs.channel); } bool operator!=(const Port &rhs) const { return !(*this==rhs);} bool operator<(const Port &rhs) const { return std::tie(bundle, channel)< std::tie(rhs.bundle, rhs.channel); } friend std::ostream &operator<<(std::ostream &os, const Port &port) { os<< "("; os<< stringifyWireBundle(port.bundle).str(); os<< ": "<< std::to_string(port.channel)<< ")"; return os; } friend llvm::raw_ostream &operator<<(llvm::raw_ostream &os, const Port &port) { os<< to_string(port); return os; } } Port
The BD chain a DMA channel runs, as one aie.dma_start, aie.dma or runtime task programs it.
llvm::SmallVector< mlir::Region * > regions
uint64_t passes
Times one start of the channel runs the chain: its repeat count plus one.
bool loops
Whether the BD chain runs forever.
size_t loopStart
The first of bds a looping chain returns to once it has run them all.
llvm::SmallVector< mlir::Block * > bds
bool forced
The wait holds however the arbiters are planned, as sharer and holding go into a receiver they share ...
A cycle of waits packet streams can deadlock in, given their routes.
llvm::SmallVector< Step, 4 > steps
@ Drain
waiting fills its receiver, and draining that waits on holding.
@ Link
waiting queues behind holding on the port both enter tile by.
@ Arbiter
waiting, or sharer it queues behind, needs the arbiter holding holds at tile; sharer enters by sharer...
One stream from a source tile port to a destination tile port, recovered from the physical switchbox ...
llvm::SmallVector< StreamHop, 8 > hops
The switchboxes the stream passes, source first, where it is routed.
bool carries(std::optional< PacketInfoAttr > packet) const
Whether what a BD sends with header packet, or with none, goes on this stream.
int packetMask
The stream carries every id that agrees with packetID on these bits.
bool keepsPktHeader
The destination stores each packet's header along with its payload.
std::optional< int > packetID
The packet id carried, if any.
A tile port at the edge of the stream fabric.
bool operator==(const StreamEndpoint &rhs) const
bool operator!=(const StreamEndpoint &rhs) const
A switchbox a stream passes: the port it enters by and, where it is packet switched there,...
std::optional< int > arbiter
A core, a DMA channel, or a tile's controller.
static Agent core(TileID tile)
static std::optional< Agent > at(const StreamEndpoint &endpoint, bool sending)
Each agent at a stream endpoint: the core, DMA channel or controller pushing data into (sending) or p...
static Agent channel(const TileDMAChannel &dma)
static Agent controller(TileID tile)
One DMA channel of one tile.
bool operator==(const TileDMAChannel &rhs) const
bool operator<(const TileDMAChannel &rhs) const