--- /dev/null
+# RUN: llvm-mca -mtriple=x86_64-unknown-unknown -mcpu=btver2 -iterations=5 -verbose -timeline < %s | FileCheck %s
+
+vaddps %xmm0, %xmm0, %xmm0
+vmulps %xmm0, %xmm0, %xmm0
+
+# CHECK: Iterations: 5
+# CHECK-NEXT: Instructions: 10
+
+# CHECK: Dynamic Dispatch Stall Cycles:
+# CHECK-NEXT: RAT - Register unavailable: 0
+
+# CHECK: Register File statistics.
+# CHECK-NEXT: Register File #0
+# CHECK-NEXT: Total number of mappings created: 10
+# CHECK-NEXT: Max number of mappings used: 10
+
+# CHECK: Timeline view:
+# CHECK-NEXT: 0123456789
+# CHECK-NEXT: Index 0123456789 01234567
+# CHECK: [0,0] DeeeER . . . . . vaddps %xmm0, %xmm0, %xmm0
+# CHECK-NEXT: [0,1] D===eeER . . . . . vmulps %xmm0, %xmm0, %xmm0
+# CHECK: [1,0] .D====eeeER . . . . vaddps %xmm0, %xmm0, %xmm0
+# CHECK-NEXT: [1,1] .D=======eeER . . . . vmulps %xmm0, %xmm0, %xmm0
+# CHECK: [2,0] . D========eeeER . . . vaddps %xmm0, %xmm0, %xmm0
+# CHECK-NEXT: [2,1] . D===========eeER . . . vmulps %xmm0, %xmm0, %xmm0
+# CHECK: [3,0] . D============eeeER . . vaddps %xmm0, %xmm0, %xmm0
+# CHECK-NEXT: [3,1] . D===============eeER . . vmulps %xmm0, %xmm0, %xmm0
+# CHECK: [4,0] . D================eeeER . vaddps %xmm0, %xmm0, %xmm0
+# CHECK-NEXT: [4,1] . D===================eeER vmulps %xmm0, %xmm0, %xmm0
--- /dev/null
+# RUN: llvm-mca -mtriple=x86_64-unknown-unknown -mcpu=btver2 -register-file-size=5 -iterations=5 -verbose -timeline < %s | FileCheck %s
+
+vaddps %xmm0, %xmm0, %xmm0
+vmulps %xmm0, %xmm0, %xmm0
+
+# CHECK: Iterations: 5
+# CHECK-NEXT: Instructions: 10
+
+# CHECK: Dynamic Dispatch Stall Cycles:
+# CHECK-NEXT: RAT - Register unavailable: 13
+
+# CHECK: Register File statistics.
+# CHECK-NEXT: Register File #0
+# CHECK-NEXT: Total number of mappings created: 10
+# CHECK-NEXT: Max number of mappings used: 5
+
+# CHECK: Timeline view:
+# CHECK-NEXT: 0123456789
+# CHECK-NEXT: Index 0123456789 01234567
+# CHECK: [0,0] DeeeER . . . . . vaddps %xmm0, %xmm0, %xmm0
+# CHECK-NEXT: [0,1] D===eeER . . . . . vmulps %xmm0, %xmm0, %xmm0
+# CHECK: [1,0] .D====eeeER . . . . vaddps %xmm0, %xmm0, %xmm0
+# CHECK-NEXT: [1,1] .D=======eeER . . . . vmulps %xmm0, %xmm0, %xmm0
+# CHECK: [2,0] . D========eeeER . . . vaddps %xmm0, %xmm0, %xmm0
+# CHECK-NEXT: [2,1] . D========eeER . . . vmulps %xmm0, %xmm0, %xmm0
+# CHECK: [3,0] . . D========eeeER . . vaddps %xmm0, %xmm0, %xmm0
+# CHECK-NEXT: [3,1] . . D========eeER . . vmulps %xmm0, %xmm0, %xmm0
+# CHECK: [4,0] . . . D========eeeER . vaddps %xmm0, %xmm0, %xmm0
+# CHECK-NEXT: [4,1] . . . D========eeER vmulps %xmm0, %xmm0, %xmm0
return *It->second;
}
void eraseInstruction(unsigned Index) { Instructions.erase(Index); }
- unsigned getTotalRegisterMappingsCreated() const {
- return DU->getTotalRegisterMappingsCreated();
- }
- unsigned getMaxUsedRegisterMappings() const {
- return DU->getMaxUsedRegisterMappings();
- }
void addEventListener(HWEventListener *Listener);
void notifyCycleBegin(unsigned Cycle);
void BackendStatistics::onInstructionEvent(const HWInstructionEvent &Event) {
switch (Event.Type) {
- case HWInstructionEvent::Retired:
+ default:
+ break;
+ case HWInstructionEvent::Retired: {
+ const auto &RE = static_cast<const HWInstructionRetiredEvent &>(Event);
+ for (unsigned I = 0, E = RegisterFiles.size(); I < E; ++I)
+ RegisterFiles[I].CurrentlyUsedMappings -= RE.FreedPhysRegs[I];
+
++NumRetired;
break;
+ }
case HWInstructionEvent::Issued:
++NumIssued;
break;
- case HWInstructionEvent::Dispatched:
+ case HWInstructionEvent::Dispatched: {
+ const auto &DE = static_cast<const HWInstructionDispatchedEvent &>(Event);
+ for (unsigned I = 0, E = RegisterFiles.size(); I < E; ++I) {
+ RegisterFileUsage &RFU = RegisterFiles[I];
+ unsigned NumUsedPhysRegs = DE.UsedPhysRegs[I];
+ RFU.CurrentlyUsedMappings += NumUsedPhysRegs;
+ RFU.TotalMappings += NumUsedPhysRegs;
+ RFU.MaxUsedMappings =
+ std::max(RFU.MaxUsedMappings, RFU.CurrentlyUsedMappings);
+ }
+
++NumDispatched;
- break;
- default:
- break;
+ }
}
}
OS << Buffer;
}
-void BackendStatistics::printRATStatistics(raw_ostream &OS,
- unsigned TotalMappings,
- unsigned MaxUsedMappings) const {
+void BackendStatistics::printRATStatistics(raw_ostream &OS) const {
std::string Buffer;
raw_string_ostream TempStream(Buffer);
- TempStream << "\n\nRegister Alias Table:";
- TempStream << "\nTotal number of mappings created: " << TotalMappings;
- TempStream << "\nMax number of mappings used: " << MaxUsedMappings
- << '\n';
+
+ TempStream << "\n\nRegister File statistics.";
+ for (unsigned I = 0, E = RegisterFiles.size(); I < E; ++I) {
+ const RegisterFileUsage &RFU = RegisterFiles[I];
+ TempStream << "\nRegister File #" << I;
+ TempStream << "\n Total number of mappings created: " << RFU.TotalMappings;
+ TempStream << "\n Max number of mappings used: "
+ << RFU.MaxUsedMappings;
+ }
+
TempStream.flush();
OS << Buffer;
}
namespace mca {
class BackendStatistics : public View {
- // TODO: remove the dependency from Backend.
- const Backend &B;
const llvm::MCSubtargetInfo &STI;
using Histogram = std::map<unsigned, unsigned>;
NumRetired = 0;
}
+ // Used to track the number of physical registers used in a register file.
+ struct RegisterFileUsage {
+ unsigned TotalMappings;
+ unsigned MaxUsedMappings;
+ unsigned CurrentlyUsedMappings;
+ };
+
+ // There is one entry for each register file implemented by the processor.
+ llvm::SmallVector<RegisterFileUsage, 4> RegisterFiles;
+
void printRetireUnitStatistics(llvm::raw_ostream &OS) const;
void printDispatchUnitStatistics(llvm::raw_ostream &OS) const;
void printSchedulerStatistics(llvm::raw_ostream &OS) const;
void printDispatchStalls(llvm::raw_ostream &OS) const;
- void printRATStatistics(llvm::raw_ostream &OS, unsigned Mappings,
- unsigned MaxUsedMappings) const;
+ void printRATStatistics(llvm::raw_ostream &OS) const;
void printRCUStatistics(llvm::raw_ostream &OS, const Histogram &Histogram,
unsigned Cycles) const;
void printDispatchUnitUsage(llvm::raw_ostream &OS, const Histogram &Stats,
const llvm::MCSchedModel &SM) const;
public:
- BackendStatistics(const Backend &backend, const llvm::MCSubtargetInfo &sti)
- : B(backend), STI(sti), NumDispatched(0), NumIssued(0), NumRetired(0),
- NumCycles(0), HWStalls(HWStallEvent::LastGenericEvent) {}
+ BackendStatistics(const llvm::MCSubtargetInfo &sti)
+ : STI(sti), NumDispatched(0), NumIssued(0), NumRetired(0),
+ NumCycles(0), HWStalls(HWStallEvent::LastGenericEvent),
+ // TODO: The view currently assumes a single register file. This will
+ // change in future.
+ RegisterFiles(1) {}
void onInstructionEvent(const HWInstructionEvent &Event) override;
void printView(llvm::raw_ostream &OS) const override {
printDispatchStalls(OS);
- printRATStatistics(OS, B.getTotalRegisterMappingsCreated(),
- B.getMaxUsedRegisterMappings());
+ printRATStatistics(OS);
printDispatchUnitStatistics(OS);
printSchedulerStatistics(OS);
printRetireUnitStatistics(OS);
-
printSchedulerUsage(OS, STI.getSchedModel());
}
};
}
}
-void RegisterFile::createNewMappings(unsigned RegisterFileMask) {
+void RegisterFile::createNewMappings(unsigned RegisterFileMask,
+ MutableArrayRef<unsigned> UsedPhysRegs) {
assert(RegisterFileMask && "RegisterFileMask cannot be zero!");
// Notify each register file that contains RegID.
do {
unsigned RegisterFileIndex = llvm::countTrailingZeros(NextRegisterFile);
RegisterMappingTracker &RMT = RegisterFiles[RegisterFileIndex];
RMT.NumUsedMappings++;
- RMT.MaxUsedMappings = std::max(RMT.MaxUsedMappings, RMT.NumUsedMappings);
- RMT.TotalMappingsCreated++;
+ UsedPhysRegs[RegisterFileIndex]++;
RegisterFileMask ^= NextRegisterFile;
} while (RegisterFileMask);
}
-void RegisterFile::removeMappings(unsigned RegisterFileMask) {
+void RegisterFile::removeMappings(unsigned RegisterFileMask,
+ MutableArrayRef<unsigned> FreedPhysRegs) {
assert(RegisterFileMask && "RegisterFileMask cannot be zero!");
// Notify each register file that contains RegID.
do {
RegisterMappingTracker &RMT = RegisterFiles[RegisterFileIndex];
assert(RMT.NumUsedMappings);
RMT.NumUsedMappings--;
+ FreedPhysRegs[RegisterFileIndex]++;
RegisterFileMask ^= NextRegisterFile;
} while (RegisterFileMask);
}
-void RegisterFile::addRegisterMapping(WriteState &WS) {
+void RegisterFile::addRegisterMapping(WriteState &WS,
+ MutableArrayRef<unsigned> UsedPhysRegs) {
unsigned RegID = WS.getRegisterID();
assert(RegID && "Adding an invalid register definition?");
for (MCSubRegIterator I(RegID, &MRI); I.isValid(); ++I)
RegisterMappings[*I].first = &WS;
- createNewMappings(Mapping.second);
+ createNewMappings(Mapping.second, UsedPhysRegs);
+
// If this is a partial update, then we are done.
if (!WS.fullyUpdatesSuperRegs())
return;
RegisterMappings[*I].first = &WS;
}
-void RegisterFile::invalidateRegisterMapping(const WriteState &WS) {
+void RegisterFile::invalidateRegisterMapping(
+ const WriteState &WS, MutableArrayRef<unsigned> FreedPhysRegs) {
unsigned RegID = WS.getRegisterID();
bool ShouldInvalidateSuperRegs = WS.fullyUpdatesSuperRegs();
if (!Mapping.first)
return;
- removeMappings(Mapping.second);
+ removeMappings(Mapping.second, FreedPhysRegs);
if (Mapping.first == &WS)
Mapping.first = nullptr;
dbgs() << "Register File #" << I;
const RegisterMappingTracker &RMT = RegisterFiles[I];
dbgs() << "\n TotalMappings: " << RMT.TotalMappings
- << "\n TotalMappingsCreated: " << RMT.TotalMappingsCreated
- << "\n MaxUsedMappings: " << RMT.MaxUsedMappings
<< "\n NumUsedMappings: " << RMT.NumUsedMappings << '\n';
}
}
return TokenID;
}
-void DispatchUnit::notifyInstructionDispatched(unsigned Index) {
+void DispatchUnit::notifyInstructionDispatched(
+ unsigned Index, ArrayRef<unsigned> UsedRegs) {
DEBUG(dbgs() << "[E] Instruction Dispatched: " << Index << '\n');
- Owner->notifyInstructionEvent(
- HWInstructionEvent(HWInstructionEvent::Dispatched, Index));
+ Owner->notifyInstructionEvent(HWInstructionDispatchedEvent(Index, UsedRegs));
}
void DispatchUnit::notifyInstructionRetired(unsigned Index) {
DEBUG(dbgs() << "[E] Instruction Retired: " << Index << '\n');
- Owner->notifyInstructionEvent(
- HWInstructionEvent(HWInstructionEvent::Retired, Index));
-
const Instruction &IS = Owner->getInstruction(Index);
+ SmallVector<unsigned, 4> FreedRegs(RAT->getNumRegisterFiles());
for (const std::unique_ptr<WriteState> &WS : IS.getDefs())
- RAT->invalidateRegisterMapping(*WS.get());
+ RAT->invalidateRegisterMapping(*WS.get(), FreedRegs);
+ Owner->notifyInstructionEvent(HWInstructionRetiredEvent(Index, FreedRegs));
Owner->eraseInstruction(Index);
}
updateRAWDependencies(*RS, STI);
// Allocate new mappings.
+ SmallVector<unsigned, 4> RegisterFiles(RAT->getNumRegisterFiles());
for (std::unique_ptr<WriteState> &WS : NewInst->getDefs())
- RAT->addRegisterMapping(*WS);
+ RAT->addRegisterMapping(*WS, RegisterFiles);
// Set the cycles left before the write-back stage.
const InstrDesc &D = NewInst->getDesc();
// Reserve slots in the RCU.
unsigned RCUTokenID = RCU->reserveSlot(IID, NumMicroOps);
NewInst->setRCUTokenID(RCUTokenID);
- notifyInstructionDispatched(IID);
+ notifyInstructionDispatched(IID, RegisterFiles);
SC->scheduleInstruction(IID, *NewInst);
return RCUTokenID;
const unsigned TotalMappings;
// Number of mappings that are currently in use.
unsigned NumUsedMappings;
- // Maximum number of register mappings used.
- unsigned MaxUsedMappings;
- // Total number of mappings allocated during the entire execution.
- unsigned TotalMappingsCreated;
RegisterMappingTracker(unsigned NumMappings)
- : TotalMappings(NumMappings), NumUsedMappings(0), MaxUsedMappings(0),
- TotalMappingsCreated(0) {}
+ : TotalMappings(NumMappings), NumUsedMappings(0) {}
};
// This is where information related to the various register files is kept.
// Allocates a new register mapping in every register file specified by the
// register file mask. This method is called from addRegisterMapping.
- void createNewMappings(unsigned RegisterFileMask);
+ void createNewMappings(unsigned RegisterFileMask,
+ llvm::MutableArrayRef<unsigned> UsedPhysRegs);
// Removes a previously allocated mapping from each register file in the
// RegisterFileMask set. This method is called from invalidateRegisterMapping.
- void removeMappings(unsigned RegisterFileMask);
+ void removeMappings(unsigned RegisterFileMask,
+ llvm::MutableArrayRef<unsigned> FreedPhysRegs);
public:
RegisterFile(const llvm::MCRegisterInfo &mri, unsigned TempRegs = 0)
// Creates a new register mapping for RegID.
// This reserves a microarchitectural register in every register file that
// contains RegID.
- void addRegisterMapping(WriteState &WS);
+ void addRegisterMapping(WriteState &WS,
+ llvm::MutableArrayRef<unsigned> UsedPhysRegs);
// Invalidates register mappings associated to the input WriteState object.
// This releases previously allocated mappings for the physical register
// associated to the WriteState.
- void invalidateRegisterMapping(const WriteState &WS);
+ void invalidateRegisterMapping(const WriteState &WS,
+ llvm::MutableArrayRef<unsigned> FreedPhysRegs);
// Checks if there are enough microarchitectural registers in the register
// files. Returns a "response mask" where each bit is the response from a
void collectWrites(llvm::SmallVectorImpl<WriteState *> &Writes,
unsigned RegID) const;
void updateOnRead(ReadState &RS, unsigned RegID);
- unsigned getMaxUsedRegisterMappings(unsigned RegisterFileIndex) const {
- assert(RegisterFileIndex < getNumRegisterFiles() &&
- "Invalid register file index!");
- return RegisterFiles[RegisterFileIndex].MaxUsedMappings;
- }
- unsigned getTotalRegisterMappingsCreated(unsigned RegisterFileIndex) const {
- assert(RegisterFileIndex < getNumRegisterFiles() &&
- "Invalid register file index!");
- return RegisterFiles[RegisterFileIndex].TotalMappingsCreated;
- }
+
unsigned getNumRegisterFiles() const { return RegisterFiles.size(); }
#ifndef NDEBUG
bool checkScheduler(unsigned Index, const InstrDesc &Desc);
void updateRAWDependencies(ReadState &RS, const llvm::MCSubtargetInfo &STI);
- void notifyInstructionDispatched(unsigned IID);
+ void notifyInstructionDispatched(unsigned IID, llvm::ArrayRef<unsigned> UsedPhysRegs);
public:
DispatchUnit(Backend *B, const llvm::MCRegisterInfo &MRI,
unsigned RegID) const {
return RAT->collectWrites(Vec, RegID);
}
- unsigned getMaxUsedRegisterMappings(unsigned RegFileIndex = 0) const {
- return RAT->getMaxUsedRegisterMappings(RegFileIndex);
- }
- unsigned getTotalRegisterMappingsCreated(unsigned RegFileIndex = 0) const {
- return RAT->getTotalRegisterMappingsCreated(RegFileIndex);
- }
void cycleEvent(unsigned Cycle) {
RCU->cycleEvent();
llvm::ArrayRef<std::pair<ResourceRef, unsigned>> UsedResources;
};
+class HWInstructionDispatchedEvent : public HWInstructionEvent {
+public:
+ HWInstructionDispatchedEvent(unsigned Index, llvm::ArrayRef<unsigned> Regs)
+ : HWInstructionEvent(HWInstructionEvent::Dispatched, Index),
+ UsedPhysRegs(Regs) {}
+ // Number of physical register allocated for this instruction. There is one
+ // entry per register file.
+ llvm::ArrayRef<unsigned> UsedPhysRegs;
+};
+
+class HWInstructionRetiredEvent : public HWInstructionEvent {
+public:
+ HWInstructionRetiredEvent(unsigned Index, llvm::ArrayRef<unsigned> Regs)
+ : HWInstructionEvent(HWInstructionEvent::Retired, Index),
+ FreedPhysRegs(Regs) {}
+ // Number of register writes that have been architecturally committed. There
+ // is one entry per register file.
+ llvm::ArrayRef<unsigned> FreedPhysRegs;
+};
+
// A HWStallEvent represents a pipeline stall caused by the lack of hardware
// resources.
class HWStallEvent {
if (PrintModeVerbose) {
std::unique_ptr<mca::BackendStatistics> BS =
- llvm::make_unique<mca::BackendStatistics>(*B, *STI);
+ llvm::make_unique<mca::BackendStatistics>(*STI);
Printer->addView(std::move(BS));
}