#ifndef LLVM_TOOLS_LLVM_MCA_BOTTLENECK_ANALYSIS_H
#define LLVM_TOOLS_LLVM_MCA_BOTTLENECK_ANALYSIS_H
#include "Views/InstructionView.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/MC/MCInstPrinter.h"
#include "llvm/MC/MCSchedule.h"
#include "llvm/MC/MCSubtargetInfo.h"
#include "llvm/Support/FormattedStream.h"
#include "llvm/Support/raw_ostream.h"
namespace llvm {
namespace mca {
class PressureTracker {
const MCSchedModel &SM;
SmallVector<unsigned, 4> ResourcePressureDistribution;
SmallVector<uint64_t, 4> ProcResID2Mask;
SmallVector<unsigned, 4> ResIdx2ProcResID;
SmallVector<unsigned, 4> ProcResID2ResourceUsersIndex;
using User = std::pair<unsigned, unsigned>;
SmallVector<User, 4> ResourceUsers;
struct InstructionPressureInfo {
unsigned RegisterPressureCycles;
unsigned MemoryPressureCycles;
unsigned ResourcePressureCycles;
};
DenseMap<unsigned, InstructionPressureInfo> IPI;
void updateResourcePressureDistribution(uint64_t CumulativeMask);
User getResourceUser(unsigned ProcResID, unsigned UnitID) const {
unsigned Index = ProcResID2ResourceUsersIndex[ProcResID];
return ResourceUsers[Index + UnitID];
}
public:
PressureTracker(const MCSchedModel &Model);
ArrayRef<unsigned> getResourcePressureDistribution() const {
return ResourcePressureDistribution;
}
void getResourceUsers(uint64_t ResourceMask,
SmallVectorImpl<User> &Users) const;
unsigned getRegisterPressureCycles(unsigned IID) const {
assert(IPI.find(IID) != IPI.end() && "Instruction is not tracked!");
const InstructionPressureInfo &Info = IPI.find(IID)->second;
return Info.RegisterPressureCycles;
}
unsigned getMemoryPressureCycles(unsigned IID) const {
assert(IPI.find(IID) != IPI.end() && "Instruction is not tracked!");
const InstructionPressureInfo &Info = IPI.find(IID)->second;
return Info.MemoryPressureCycles;
}
unsigned getResourcePressureCycles(unsigned IID) const {
assert(IPI.find(IID) != IPI.end() && "Instruction is not tracked!");
const InstructionPressureInfo &Info = IPI.find(IID)->second;
return Info.ResourcePressureCycles;
}
const char *resolveResourceName(uint64_t ResourceMask) const {
unsigned Index = getResourceStateIndex(ResourceMask);
unsigned ProcResID = ResIdx2ProcResID[Index];
const MCProcResourceDesc &PRDesc = *SM.getProcResource(ProcResID);
return PRDesc.Name;
}
void onInstructionDispatched(unsigned IID);
void onInstructionExecuted(unsigned IID);
void handlePressureEvent(const HWPressureEvent &Event);
void handleInstructionIssuedEvent(const HWInstructionIssuedEvent &Event);
};
struct DependencyEdge {
enum DependencyType { DT_INVALID, DT_REGISTER, DT_MEMORY, DT_RESOURCE };
struct Dependency {
DependencyType Type;
uint64_t ResourceOrRegID;
uint64_t Cost;
};
Dependency Dep;
unsigned FromIID;
unsigned ToIID;
unsigned Frequency;
};
class DependencyGraph {
struct DGNode {
unsigned NumPredecessors;
unsigned NumVisitedPredecessors;
uint64_t Cost;
unsigned Depth;
DependencyEdge CriticalPredecessor;
SmallVector<DependencyEdge, 8> OutgoingEdges;
};
SmallVector<DGNode, 16> Nodes;
DependencyGraph(const DependencyGraph &) = delete;
DependencyGraph &operator=(const DependencyGraph &) = delete;
void addDependency(unsigned From, unsigned To,
DependencyEdge::Dependency &&DE);
void pruneEdges(unsigned Iterations);
void initializeRootSet(SmallVectorImpl<unsigned> &RootSet) const;
void propagateThroughEdges(SmallVectorImpl<unsigned> &RootSet,
unsigned Iterations);
#ifndef NDEBUG
void dumpDependencyEdge(raw_ostream &OS, const DependencyEdge &DE,
MCInstPrinter &MCIP) const;
#endif
public:
DependencyGraph(unsigned Size) : Nodes(Size) {}
void addRegisterDep(unsigned From, unsigned To, unsigned RegID,
unsigned Cost) {
addDependency(From, To, {DependencyEdge::DT_REGISTER, RegID, Cost});
}
void addMemoryDep(unsigned From, unsigned To, unsigned Cost) {
addDependency(From, To, {DependencyEdge::DT_MEMORY, 0, Cost});
}
void addResourceDep(unsigned From, unsigned To, uint64_t Mask,
unsigned Cost) {
addDependency(From, To, {DependencyEdge::DT_RESOURCE, Mask, Cost});
}
void finalizeGraph(unsigned Iterations) {
SmallVector<unsigned, 16> RootSet;
pruneEdges(Iterations);
initializeRootSet(RootSet);
propagateThroughEdges(RootSet, Iterations);
}
void getCriticalSequence(SmallVectorImpl<const DependencyEdge *> &Seq) const;
#ifndef NDEBUG
void dump(raw_ostream &OS, MCInstPrinter &MCIP) const;
#endif
};
class BottleneckAnalysis : public InstructionView {
PressureTracker Tracker;
DependencyGraph DG;
unsigned Iterations;
unsigned TotalCycles;
bool PressureIncreasedBecauseOfResources;
bool PressureIncreasedBecauseOfRegisterDependencies;
bool PressureIncreasedBecauseOfMemoryDependencies;
bool SeenStallCycles;
struct BackPressureInfo {
unsigned PressureIncreaseCycles;
unsigned ResourcePressureCycles;
unsigned DataDependencyCycles;
unsigned RegisterDependencyCycles;
unsigned MemoryDependencyCycles;
};
BackPressureInfo BPI;
void addRegisterDep(unsigned From, unsigned To, unsigned RegID, unsigned Cy);
void addMemoryDep(unsigned From, unsigned To, unsigned Cy);
void addResourceDep(unsigned From, unsigned To, uint64_t Mask, unsigned Cy);
void printInstruction(formatted_raw_ostream &FOS, const MCInst &MCI,
bool UseDifferentColor = false) const;
void printBottleneckHints(raw_ostream &OS) const;
void printCriticalSequence(raw_ostream &OS) const;
public:
BottleneckAnalysis(const MCSubtargetInfo &STI, MCInstPrinter &MCIP,
ArrayRef<MCInst> Sequence, unsigned Iterations);
void onCycleEnd() override;
void onEvent(const HWStallEvent &Event) override { SeenStallCycles = true; }
void onEvent(const HWPressureEvent &Event) override;
void onEvent(const HWInstructionEvent &Event) override;
void printView(raw_ostream &OS) const override;
StringRef getNameAsString() const override { return "BottleneckAnalysis"; }
bool isSerializable() const override { return false; }
#ifndef NDEBUG
void dump(raw_ostream &OS, MCInstPrinter &MCIP) const { DG.dump(OS, MCIP); }
#endif
};
} }
#endif