forked from OSchip/llvm-project
[llvm-mca][NFC] Refactor handling of views that examine individual instructions,
including printing them. Reviewers: andreadb, lebedev.ri Differential Review: https://reviews.llvm.org/D86390 Introduces a new base class "InstructionView" that such views derive from. Other views still use the "View" base class.
This commit is contained in:
parent
4d69bcb12f
commit
e02920fe55
|
@ -16,7 +16,6 @@
|
|||
#include "llvm/MC/MCInst.h"
|
||||
#include "llvm/MCA/Support.h"
|
||||
#include "llvm/Support/Format.h"
|
||||
#include "llvm/Support/FormattedStream.h"
|
||||
|
||||
namespace llvm {
|
||||
namespace mca {
|
||||
|
@ -284,21 +283,14 @@ void DependencyGraph::getCriticalSequence(
|
|||
}
|
||||
}
|
||||
|
||||
static void printInstruction(formatted_raw_ostream &FOS,
|
||||
const MCSubtargetInfo &STI, MCInstPrinter &MCIP,
|
||||
const MCInst &MCI,
|
||||
bool UseDifferentColor = false) {
|
||||
std::string Instruction;
|
||||
raw_string_ostream InstrStream(Instruction);
|
||||
|
||||
void BottleneckAnalysis::printInstruction(formatted_raw_ostream &FOS,
|
||||
const MCInst &MCI,
|
||||
bool UseDifferentColor) const {
|
||||
FOS.PadToColumn(14);
|
||||
|
||||
MCIP.printInst(&MCI, 0, "", STI, InstrStream);
|
||||
InstrStream.flush();
|
||||
|
||||
if (UseDifferentColor)
|
||||
FOS.changeColor(raw_ostream::CYAN, true, false);
|
||||
FOS << StringRef(Instruction).ltrim();
|
||||
FOS << printInstructionString(MCI);
|
||||
if (UseDifferentColor)
|
||||
FOS.resetColor();
|
||||
}
|
||||
|
@ -316,6 +308,7 @@ void BottleneckAnalysis::printCriticalSequence(raw_ostream &OS) const {
|
|||
OS << "\nCritical sequence based on the simulation:\n\n";
|
||||
|
||||
const DependencyEdge &FirstEdge = *Seq[0];
|
||||
ArrayRef<llvm::MCInst> Source = getSource();
|
||||
unsigned FromIID = FirstEdge.FromIID % Source.size();
|
||||
unsigned ToIID = FirstEdge.ToIID % Source.size();
|
||||
bool IsLoopCarried = FromIID >= ToIID;
|
||||
|
@ -331,17 +324,17 @@ void BottleneckAnalysis::printCriticalSequence(raw_ostream &OS) const {
|
|||
unsigned CurrentIID = 0;
|
||||
if (IsLoopCarried) {
|
||||
FOS << "\n +----< " << FromIID << ".";
|
||||
printInstruction(FOS, STI, MCIP, Source[FromIID], HasColors);
|
||||
printInstruction(FOS, Source[FromIID], HasColors);
|
||||
FOS << "\n |\n | < loop carried > \n |";
|
||||
} else {
|
||||
while (CurrentIID < FromIID) {
|
||||
FOS << "\n " << CurrentIID << ".";
|
||||
printInstruction(FOS, STI, MCIP, Source[CurrentIID]);
|
||||
printInstruction(FOS, Source[CurrentIID]);
|
||||
CurrentIID++;
|
||||
}
|
||||
|
||||
FOS << "\n +----< " << CurrentIID << ".";
|
||||
printInstruction(FOS, STI, MCIP, Source[CurrentIID], HasColors);
|
||||
printInstruction(FOS, Source[CurrentIID], HasColors);
|
||||
CurrentIID++;
|
||||
}
|
||||
|
||||
|
@ -351,17 +344,17 @@ void BottleneckAnalysis::printCriticalSequence(raw_ostream &OS) const {
|
|||
|
||||
while (CurrentIID < LastIID) {
|
||||
FOS << "\n | " << CurrentIID << ".";
|
||||
printInstruction(FOS, STI, MCIP, Source[CurrentIID]);
|
||||
printInstruction(FOS, Source[CurrentIID]);
|
||||
CurrentIID++;
|
||||
}
|
||||
|
||||
if (CurrentIID == ToIID) {
|
||||
FOS << "\n +----> " << ToIID << ".";
|
||||
printInstruction(FOS, STI, MCIP, Source[CurrentIID], HasColors);
|
||||
printInstruction(FOS, Source[CurrentIID], HasColors);
|
||||
} else {
|
||||
FOS << "\n |\n | < loop carried > \n |"
|
||||
<< "\n +----> " << ToIID << ".";
|
||||
printInstruction(FOS, STI, MCIP, Source[ToIID], HasColors);
|
||||
printInstruction(FOS, Source[ToIID], HasColors);
|
||||
}
|
||||
FOS.PadToColumn(58);
|
||||
|
||||
|
@ -373,7 +366,7 @@ void BottleneckAnalysis::printCriticalSequence(raw_ostream &OS) const {
|
|||
FOS << "## REGISTER dependency: ";
|
||||
if (HasColors)
|
||||
FOS.changeColor(raw_ostream::MAGENTA, true, false);
|
||||
MCIP.printRegName(FOS, Dep.ResourceOrRegID);
|
||||
getInstPrinter().printRegName(FOS, Dep.ResourceOrRegID);
|
||||
} else if (Dep.Type == DependencyEdge::DT_MEMORY) {
|
||||
FOS << "## MEMORY dependency.";
|
||||
} else {
|
||||
|
@ -397,7 +390,7 @@ void BottleneckAnalysis::printCriticalSequence(raw_ostream &OS) const {
|
|||
|
||||
while (CurrentIID < Source.size()) {
|
||||
FOS << "\n " << CurrentIID << ".";
|
||||
printInstruction(FOS, STI, MCIP, Source[CurrentIID]);
|
||||
printInstruction(FOS, Source[CurrentIID]);
|
||||
CurrentIID++;
|
||||
}
|
||||
|
||||
|
@ -451,8 +444,8 @@ void DependencyGraph::addDependency(unsigned From, unsigned To,
|
|||
BottleneckAnalysis::BottleneckAnalysis(const MCSubtargetInfo &sti,
|
||||
MCInstPrinter &Printer,
|
||||
ArrayRef<MCInst> S, unsigned NumIter)
|
||||
: STI(sti), MCIP(Printer), Tracker(STI.getSchedModel()), DG(S.size() * 3),
|
||||
Source(S), Iterations(NumIter), TotalCycles(0),
|
||||
: InstructionView(sti, Printer, S), Tracker(sti.getSchedModel()),
|
||||
DG(S.size() * 3), Iterations(NumIter), TotalCycles(0),
|
||||
PressureIncreasedBecauseOfResources(false),
|
||||
PressureIncreasedBecauseOfRegisterDependencies(false),
|
||||
PressureIncreasedBecauseOfMemoryDependencies(false),
|
||||
|
@ -461,7 +454,7 @@ BottleneckAnalysis::BottleneckAnalysis(const MCSubtargetInfo &sti,
|
|||
void BottleneckAnalysis::addRegisterDep(unsigned From, unsigned To,
|
||||
unsigned RegID, unsigned Cost) {
|
||||
bool IsLoopCarried = From >= To;
|
||||
unsigned SourceSize = Source.size();
|
||||
unsigned SourceSize = getSource().size();
|
||||
if (IsLoopCarried) {
|
||||
DG.addRegisterDep(From, To + SourceSize, RegID, Cost);
|
||||
DG.addRegisterDep(From + SourceSize, To + (SourceSize * 2), RegID, Cost);
|
||||
|
@ -473,7 +466,7 @@ void BottleneckAnalysis::addRegisterDep(unsigned From, unsigned To,
|
|||
void BottleneckAnalysis::addMemoryDep(unsigned From, unsigned To,
|
||||
unsigned Cost) {
|
||||
bool IsLoopCarried = From >= To;
|
||||
unsigned SourceSize = Source.size();
|
||||
unsigned SourceSize = getSource().size();
|
||||
if (IsLoopCarried) {
|
||||
DG.addMemoryDep(From, To + SourceSize, Cost);
|
||||
DG.addMemoryDep(From + SourceSize, To + (SourceSize * 2), Cost);
|
||||
|
@ -485,7 +478,7 @@ void BottleneckAnalysis::addMemoryDep(unsigned From, unsigned To,
|
|||
void BottleneckAnalysis::addResourceDep(unsigned From, unsigned To,
|
||||
uint64_t Mask, unsigned Cost) {
|
||||
bool IsLoopCarried = From >= To;
|
||||
unsigned SourceSize = Source.size();
|
||||
unsigned SourceSize = getSource().size();
|
||||
if (IsLoopCarried) {
|
||||
DG.addResourceDep(From, To + SourceSize, Mask, Cost);
|
||||
DG.addResourceDep(From + SourceSize, To + (SourceSize * 2), Mask, Cost);
|
||||
|
@ -508,6 +501,7 @@ void BottleneckAnalysis::onEvent(const HWInstructionEvent &Event) {
|
|||
if (Event.Type != HWInstructionEvent::Issued)
|
||||
return;
|
||||
|
||||
ArrayRef<llvm::MCInst> Source = getSource();
|
||||
const Instruction &IS = *Event.IR.getInstruction();
|
||||
unsigned To = IID % Source.size();
|
||||
|
||||
|
@ -617,7 +611,7 @@ void BottleneckAnalysis::printBottleneckHints(raw_ostream &OS) const {
|
|||
|
||||
if (BPI.PressureIncreaseCycles) {
|
||||
ArrayRef<unsigned> Distribution = Tracker.getResourcePressureDistribution();
|
||||
const MCSchedModel &SM = STI.getSchedModel();
|
||||
const MCSchedModel &SM = getSubTargetInfo().getSchedModel();
|
||||
for (unsigned I = 0, E = Distribution.size(); I < E; ++I) {
|
||||
unsigned ResourceCycles = Distribution[I];
|
||||
if (ResourceCycles) {
|
||||
|
|
|
@ -87,6 +87,7 @@
|
|||
#include "llvm/MC/MCSchedule.h"
|
||||
#include "llvm/MC/MCSubtargetInfo.h"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
#include "llvm/Support/FormattedStream.h"
|
||||
|
||||
namespace llvm {
|
||||
namespace mca {
|
||||
|
@ -282,13 +283,10 @@ public:
|
|||
};
|
||||
|
||||
/// A view that collects and prints a few performance numbers.
|
||||
class BottleneckAnalysis : public View {
|
||||
const MCSubtargetInfo &STI;
|
||||
MCInstPrinter &MCIP;
|
||||
class BottleneckAnalysis : public InstructionView {
|
||||
PressureTracker Tracker;
|
||||
DependencyGraph DG;
|
||||
|
||||
ArrayRef<MCInst> Source;
|
||||
unsigned Iterations;
|
||||
unsigned TotalCycles;
|
||||
|
||||
|
@ -317,6 +315,9 @@ class BottleneckAnalysis : public View {
|
|||
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;
|
||||
|
||||
// Prints a bottleneck message to OS.
|
||||
void printBottleneckHints(raw_ostream &OS) const;
|
||||
void printCriticalSequence(raw_ostream &OS) const;
|
||||
|
|
|
@ -20,9 +20,8 @@ namespace mca {
|
|||
void InstructionInfoView::printView(raw_ostream &OS) const {
|
||||
std::string Buffer;
|
||||
raw_string_ostream TempStream(Buffer);
|
||||
std::string Instruction;
|
||||
raw_string_ostream InstrStream(Instruction);
|
||||
|
||||
ArrayRef<llvm::MCInst> Source = getSource();
|
||||
if (!Source.size())
|
||||
return;
|
||||
|
||||
|
@ -82,14 +81,7 @@ void InstructionInfoView::printView(raw_ostream &OS) const {
|
|||
}
|
||||
|
||||
const MCInst &Inst = std::get<1>(I.value());
|
||||
MCIP.printInst(&Inst, 0, "", STI, InstrStream);
|
||||
InstrStream.flush();
|
||||
|
||||
// Consume any tabs or spaces at the beginning of the string.
|
||||
StringRef Str(Instruction);
|
||||
Str = Str.ltrim();
|
||||
TempStream << Str << '\n';
|
||||
Instruction = "";
|
||||
TempStream << printInstructionString(Inst) << '\n';
|
||||
}
|
||||
|
||||
TempStream.flush();
|
||||
|
@ -98,8 +90,9 @@ void InstructionInfoView::printView(raw_ostream &OS) const {
|
|||
|
||||
void InstructionInfoView::collectData(
|
||||
MutableArrayRef<InstructionInfoViewData> IIVD) const {
|
||||
const llvm::MCSubtargetInfo &STI = getSubTargetInfo();
|
||||
const MCSchedModel &SM = STI.getSchedModel();
|
||||
for (auto I : zip(Source, IIVD)) {
|
||||
for (auto I : zip(getSource(), IIVD)) {
|
||||
const MCInst &Inst = std::get<0>(I);
|
||||
InstructionInfoViewData &IIVDEntry = std::get<1>(I);
|
||||
const MCInstrDesc &MCDesc = MCII.get(Inst.getOpcode());
|
||||
|
|
|
@ -50,13 +50,10 @@ namespace llvm {
|
|||
namespace mca {
|
||||
|
||||
/// A view that prints out generic instruction information.
|
||||
class InstructionInfoView : public View {
|
||||
const llvm::MCSubtargetInfo &STI;
|
||||
class InstructionInfoView : public InstructionView {
|
||||
const llvm::MCInstrInfo &MCII;
|
||||
CodeEmitter &CE;
|
||||
bool PrintEncodings;
|
||||
llvm::ArrayRef<llvm::MCInst> Source;
|
||||
llvm::MCInstPrinter &MCIP;
|
||||
|
||||
struct InstructionInfoViewData {
|
||||
unsigned NumMicroOpcodes = 0;
|
||||
|
@ -76,8 +73,8 @@ public:
|
|||
const llvm::MCInstrInfo &II, CodeEmitter &C,
|
||||
bool ShouldPrintEncodings, llvm::ArrayRef<llvm::MCInst> S,
|
||||
llvm::MCInstPrinter &IP)
|
||||
: STI(ST), MCII(II), CE(C), PrintEncodings(ShouldPrintEncodings),
|
||||
Source(S), MCIP(IP) {}
|
||||
: InstructionView(ST, IP, S), MCII(II), CE(C),
|
||||
PrintEncodings(ShouldPrintEncodings) {}
|
||||
|
||||
void printView(llvm::raw_ostream &OS) const override;
|
||||
};
|
||||
|
|
|
@ -21,10 +21,10 @@ namespace mca {
|
|||
ResourcePressureView::ResourcePressureView(const llvm::MCSubtargetInfo &sti,
|
||||
MCInstPrinter &Printer,
|
||||
ArrayRef<MCInst> S)
|
||||
: STI(sti), MCIP(Printer), Source(S), LastInstructionIdx(0) {
|
||||
: InstructionView(sti, Printer, S), LastInstructionIdx(0) {
|
||||
// Populate the map of resource descriptors.
|
||||
unsigned R2VIndex = 0;
|
||||
const MCSchedModel &SM = STI.getSchedModel();
|
||||
const MCSchedModel &SM = getSubTargetInfo().getSchedModel();
|
||||
for (unsigned I = 0, E = SM.getNumProcResourceKinds(); I < E; ++I) {
|
||||
const MCProcResourceDesc &ProcResource = *SM.getProcResource(I);
|
||||
unsigned NumUnits = ProcResource.NumUnits;
|
||||
|
@ -37,7 +37,7 @@ ResourcePressureView::ResourcePressureView(const llvm::MCSubtargetInfo &sti,
|
|||
}
|
||||
|
||||
NumResourceUnits = R2VIndex;
|
||||
ResourceUsage.resize(NumResourceUnits * (Source.size() + 1));
|
||||
ResourceUsage.resize(NumResourceUnits * (getSource().size() + 1));
|
||||
std::fill(ResourceUsage.begin(), ResourceUsage.end(), 0.0);
|
||||
}
|
||||
|
||||
|
@ -52,6 +52,7 @@ void ResourcePressureView::onEvent(const HWInstructionEvent &Event) {
|
|||
return;
|
||||
|
||||
const auto &IssueEvent = static_cast<const HWInstructionIssuedEvent &>(Event);
|
||||
ArrayRef<llvm::MCInst> Source = getSource();
|
||||
const unsigned SourceIdx = Event.IR.getSourceIndex() % Source.size();
|
||||
for (const std::pair<ResourceRef, ResourceCycles> &Use :
|
||||
IssueEvent.UsedResources) {
|
||||
|
@ -105,7 +106,7 @@ void ResourcePressureView::printResourcePressurePerIter(raw_ostream &OS) const {
|
|||
formatted_raw_ostream FOS(TempStream);
|
||||
|
||||
FOS << "\n\nResources:\n";
|
||||
const MCSchedModel &SM = STI.getSchedModel();
|
||||
const MCSchedModel &SM = getSubTargetInfo().getSchedModel();
|
||||
for (unsigned I = 1, ResourceIndex = 0, E = SM.getNumProcResourceKinds();
|
||||
I < E; ++I) {
|
||||
const MCProcResourceDesc &ProcResource = *SM.getProcResource(I);
|
||||
|
@ -132,6 +133,7 @@ void ResourcePressureView::printResourcePressurePerIter(raw_ostream &OS) const {
|
|||
FOS << '\n';
|
||||
FOS.flush();
|
||||
|
||||
ArrayRef<llvm::MCInst> Source = getSource();
|
||||
const unsigned Executions = LastInstructionIdx / Source.size() + 1;
|
||||
for (unsigned I = 0, E = NumResourceUnits; I < E; ++I) {
|
||||
double Usage = ResourceUsage[I + Source.size() * E];
|
||||
|
@ -148,13 +150,11 @@ void ResourcePressureView::printResourcePressurePerInst(raw_ostream &OS) const {
|
|||
formatted_raw_ostream FOS(TempStream);
|
||||
|
||||
FOS << "\n\nResource pressure by instruction:\n";
|
||||
printColumnNames(FOS, STI.getSchedModel());
|
||||
printColumnNames(FOS, getSubTargetInfo().getSchedModel());
|
||||
FOS << "Instructions:\n";
|
||||
|
||||
std::string Instruction;
|
||||
raw_string_ostream InstrStream(Instruction);
|
||||
|
||||
unsigned InstrIndex = 0;
|
||||
ArrayRef<llvm::MCInst> Source = getSource();
|
||||
const unsigned Executions = LastInstructionIdx / Source.size() + 1;
|
||||
for (const MCInst &MCI : Source) {
|
||||
unsigned BaseEltIdx = InstrIndex * NumResourceUnits;
|
||||
|
@ -163,16 +163,7 @@ void ResourcePressureView::printResourcePressurePerInst(raw_ostream &OS) const {
|
|||
printResourcePressure(FOS, Usage / Executions, (J + 1) * 7);
|
||||
}
|
||||
|
||||
MCIP.printInst(&MCI, 0, "", STI, InstrStream);
|
||||
InstrStream.flush();
|
||||
StringRef Str(Instruction);
|
||||
|
||||
// Remove any tabs or spaces at the beginning of the instruction.
|
||||
Str = Str.ltrim();
|
||||
|
||||
FOS << Str << '\n';
|
||||
Instruction = "";
|
||||
|
||||
FOS << printInstructionString(MCI) << '\n';
|
||||
FOS.flush();
|
||||
OS << Buffer;
|
||||
Buffer = "";
|
||||
|
|
|
@ -69,10 +69,7 @@ namespace mca {
|
|||
|
||||
/// This class collects resource pressure statistics and it is able to print
|
||||
/// out all the collected information as a table to an output stream.
|
||||
class ResourcePressureView : public View {
|
||||
const llvm::MCSubtargetInfo &STI;
|
||||
llvm::MCInstPrinter &MCIP;
|
||||
llvm::ArrayRef<llvm::MCInst> Source;
|
||||
class ResourcePressureView : public InstructionView {
|
||||
unsigned LastInstructionIdx;
|
||||
|
||||
// Map to quickly obtain the ResourceUsage column index from a processor
|
||||
|
|
|
@ -20,10 +20,10 @@ namespace mca {
|
|||
TimelineView::TimelineView(const MCSubtargetInfo &sti, MCInstPrinter &Printer,
|
||||
llvm::ArrayRef<llvm::MCInst> S, unsigned Iterations,
|
||||
unsigned Cycles)
|
||||
: STI(sti), MCIP(Printer), Source(S), CurrentCycle(0),
|
||||
: InstructionView(sti, Printer, S), CurrentCycle(0),
|
||||
MaxCycle(Cycles == 0 ? 80 : Cycles), LastCycle(0), WaitTime(S.size()),
|
||||
UsedBuffer(S.size()) {
|
||||
unsigned NumInstructions = Source.size();
|
||||
unsigned NumInstructions = getSource().size();
|
||||
assert(Iterations && "Invalid number of iterations specified!");
|
||||
NumInstructions *= Iterations;
|
||||
Timeline.resize(NumInstructions);
|
||||
|
@ -40,10 +40,10 @@ TimelineView::TimelineView(const MCSubtargetInfo &sti, MCInstPrinter &Printer,
|
|||
|
||||
void TimelineView::onReservedBuffers(const InstRef &IR,
|
||||
ArrayRef<unsigned> Buffers) {
|
||||
if (IR.getSourceIndex() >= Source.size())
|
||||
if (IR.getSourceIndex() >= getSource().size())
|
||||
return;
|
||||
|
||||
const MCSchedModel &SM = STI.getSchedModel();
|
||||
const MCSchedModel &SM = getSubTargetInfo().getSchedModel();
|
||||
std::pair<unsigned, int> BufferInfo = {0, -1};
|
||||
for (const unsigned Buffer : Buffers) {
|
||||
const MCProcResourceDesc &MCDesc = *SM.getProcResource(Buffer);
|
||||
|
@ -70,7 +70,7 @@ void TimelineView::onEvent(const HWInstructionEvent &Event) {
|
|||
// Update the WaitTime entry which corresponds to this Index.
|
||||
assert(TVEntry.CycleDispatched >= 0 && "Invalid TVEntry found!");
|
||||
unsigned CycleDispatched = static_cast<unsigned>(TVEntry.CycleDispatched);
|
||||
WaitTimeEntry &WTEntry = WaitTime[Index % Source.size()];
|
||||
WaitTimeEntry &WTEntry = WaitTime[Index % getSource().size()];
|
||||
WTEntry.CyclesSpentInSchedulerQueue +=
|
||||
TVEntry.CycleIssued - CycleDispatched;
|
||||
assert(CycleDispatched <= TVEntry.CycleReady &&
|
||||
|
@ -133,7 +133,7 @@ void TimelineView::printWaitTimeEntry(formatted_raw_ostream &OS,
|
|||
const WaitTimeEntry &Entry,
|
||||
unsigned SourceIndex,
|
||||
unsigned Executions) const {
|
||||
bool PrintingTotals = SourceIndex == Source.size();
|
||||
bool PrintingTotals = SourceIndex == getSource().size();
|
||||
unsigned CumulativeExecutions = PrintingTotals ? Timeline.size() : Executions;
|
||||
|
||||
if (!PrintingTotals)
|
||||
|
@ -164,7 +164,8 @@ void TimelineView::printWaitTimeEntry(formatted_raw_ostream &OS,
|
|||
OS.PadToColumn(27);
|
||||
if (!PrintingTotals)
|
||||
tryChangeColor(OS, Entry.CyclesSpentAfterWBAndBeforeRetire,
|
||||
CumulativeExecutions, STI.getSchedModel().MicroOpBufferSize);
|
||||
CumulativeExecutions,
|
||||
getSubTargetInfo().getSchedModel().MicroOpBufferSize);
|
||||
OS << format("%.1f", floor((AverageTime3 * 10) + 0.5) / 10);
|
||||
|
||||
if (OS.has_colors())
|
||||
|
@ -181,33 +182,19 @@ void TimelineView::printAverageWaitTimes(raw_ostream &OS) const {
|
|||
"[3]: Average time elapsed from WB until retire stage\n\n"
|
||||
" [0] [1] [2] [3]\n";
|
||||
OS << Header;
|
||||
|
||||
// Use a different string stream for printing instructions.
|
||||
std::string Instruction;
|
||||
raw_string_ostream InstrStream(Instruction);
|
||||
|
||||
formatted_raw_ostream FOS(OS);
|
||||
unsigned Executions = Timeline.size() / Source.size();
|
||||
unsigned Executions = Timeline.size() / getSource().size();
|
||||
unsigned IID = 0;
|
||||
for (const MCInst &Inst : Source) {
|
||||
for (const MCInst &Inst : getSource()) {
|
||||
printWaitTimeEntry(FOS, WaitTime[IID], IID, Executions);
|
||||
// Append the instruction info at the end of the line.
|
||||
MCIP.printInst(&Inst, 0, "", STI, InstrStream);
|
||||
InstrStream.flush();
|
||||
|
||||
// Consume any tabs or spaces at the beginning of the string.
|
||||
StringRef Str(Instruction);
|
||||
Str = Str.ltrim();
|
||||
FOS << " " << Str << '\n';
|
||||
FOS << " " << printInstructionString(Inst) << '\n';
|
||||
FOS.flush();
|
||||
Instruction = "";
|
||||
|
||||
++IID;
|
||||
}
|
||||
|
||||
// If the timeline contains more than one instruction,
|
||||
// let's also print global averages.
|
||||
if (Source.size() != 1) {
|
||||
if (getSource().size() != 1) {
|
||||
WaitTimeEntry TotalWaitTime = std::accumulate(
|
||||
WaitTime.begin(), WaitTime.end(), WaitTimeEntry{0, 0, 0},
|
||||
[](const WaitTimeEntry &A, const WaitTimeEntry &B) {
|
||||
|
@ -220,7 +207,7 @@ void TimelineView::printAverageWaitTimes(raw_ostream &OS) const {
|
|||
printWaitTimeEntry(FOS, TotalWaitTime, IID, Executions);
|
||||
FOS << " "
|
||||
<< "<total>" << '\n';
|
||||
InstrStream.flush();
|
||||
FOS.flush();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -292,11 +279,8 @@ void TimelineView::printTimeline(raw_ostream &OS) const {
|
|||
printTimelineHeader(FOS, LastCycle);
|
||||
FOS.flush();
|
||||
|
||||
// Use a different string stream for the instruction.
|
||||
std::string Instruction;
|
||||
raw_string_ostream InstrStream(Instruction);
|
||||
|
||||
unsigned IID = 0;
|
||||
ArrayRef<llvm::MCInst> Source = getSource();
|
||||
const unsigned Iterations = Timeline.size() / Source.size();
|
||||
for (unsigned Iteration = 0; Iteration < Iterations; ++Iteration) {
|
||||
for (const MCInst &Inst : Source) {
|
||||
|
@ -306,16 +290,8 @@ void TimelineView::printTimeline(raw_ostream &OS) const {
|
|||
|
||||
unsigned SourceIndex = IID % Source.size();
|
||||
printTimelineViewEntry(FOS, Entry, Iteration, SourceIndex);
|
||||
// Append the instruction info at the end of the line.
|
||||
MCIP.printInst(&Inst, 0, "", STI, InstrStream);
|
||||
InstrStream.flush();
|
||||
|
||||
// Consume any tabs or spaces at the beginning of the string.
|
||||
StringRef Str(Instruction);
|
||||
Str = Str.ltrim();
|
||||
FOS << " " << Str << '\n';
|
||||
FOS << " " << printInstructionString(Inst) << '\n';
|
||||
FOS.flush();
|
||||
Instruction = "";
|
||||
|
||||
++IID;
|
||||
}
|
||||
|
|
|
@ -118,11 +118,7 @@ namespace mca {
|
|||
/// a TimelineViewEntry object. TimelineViewEntry objects are then used
|
||||
/// to print the timeline information, as well as the "average wait times"
|
||||
/// for every instruction in the input assembly sequence.
|
||||
class TimelineView : public View {
|
||||
const llvm::MCSubtargetInfo &STI;
|
||||
llvm::MCInstPrinter &MCIP;
|
||||
llvm::ArrayRef<llvm::MCInst> Source;
|
||||
|
||||
class TimelineView : public InstructionView {
|
||||
unsigned CurrentCycle;
|
||||
unsigned MaxCycle;
|
||||
unsigned LastCycle;
|
||||
|
|
|
@ -17,5 +17,13 @@ namespace llvm {
|
|||
namespace mca {
|
||||
|
||||
void View::anchor() {}
|
||||
|
||||
StringRef InstructionView::printInstructionString(const llvm::MCInst &MCI) const {
|
||||
InstructionString = "";
|
||||
MCIP.printInst(&MCI, 0, "", STI, InstrStream);
|
||||
InstrStream.flush();
|
||||
// Remove any tabs or spaces at the beginning of the instruction.
|
||||
return StringRef(InstructionString).ltrim();
|
||||
}
|
||||
} // namespace mca
|
||||
} // namespace llvm
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
#ifndef LLVM_TOOLS_LLVM_MCA_VIEW_H
|
||||
#define LLVM_TOOLS_LLVM_MCA_VIEW_H
|
||||
|
||||
#include "llvm/MC/MCInstPrinter.h"
|
||||
#include "llvm/MCA/HWEventListener.h"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
|
||||
|
@ -27,6 +28,33 @@ public:
|
|||
virtual ~View() = default;
|
||||
void anchor() override;
|
||||
};
|
||||
|
||||
// The base class for views that deal with individual machine instructions.
|
||||
class InstructionView : public View {
|
||||
const llvm::MCSubtargetInfo &STI;
|
||||
llvm::MCInstPrinter &MCIP;
|
||||
llvm::ArrayRef<llvm::MCInst> Source;
|
||||
|
||||
mutable std::string InstructionString;
|
||||
mutable raw_string_ostream InstrStream;
|
||||
|
||||
protected:
|
||||
InstructionView(const llvm::MCSubtargetInfo &STI,
|
||||
llvm::MCInstPrinter &Printer,
|
||||
llvm::ArrayRef<llvm::MCInst> S)
|
||||
: STI(STI), MCIP(Printer), Source(S), InstrStream(InstructionString) {}
|
||||
|
||||
virtual ~InstructionView() = default;
|
||||
|
||||
// Return a reference to a string representing a given machine instruction.
|
||||
// The result should be used or copied before the next call to
|
||||
// printInstructionString() as it will overwrite the previous result.
|
||||
StringRef printInstructionString(const llvm::MCInst &MCI) const;
|
||||
|
||||
const llvm::MCSubtargetInfo &getSubTargetInfo() const { return STI; }
|
||||
llvm::MCInstPrinter &getInstPrinter() const { return MCIP; }
|
||||
llvm::ArrayRef<llvm::MCInst> getSource() const { return Source; }
|
||||
};
|
||||
} // namespace mca
|
||||
} // namespace llvm
|
||||
|
||||
|
|
Loading…
Reference in New Issue