Index: llvm/tools/llvm-mca/Views/BottleneckAnalysis.h =================================================================== --- llvm/tools/llvm-mca/Views/BottleneckAnalysis.h +++ llvm/tools/llvm-mca/Views/BottleneckAnalysis.h @@ -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 @@ }; /// 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 Source; unsigned Iterations; unsigned TotalCycles; @@ -317,6 +315,9 @@ 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; Index: llvm/tools/llvm-mca/Views/BottleneckAnalysis.cpp =================================================================== --- llvm/tools/llvm-mca/Views/BottleneckAnalysis.cpp +++ llvm/tools/llvm-mca/Views/BottleneckAnalysis.cpp @@ -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 @@ } } -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 @@ OS << "\nCritical sequence based on the simulation:\n\n"; const DependencyEdge &FirstEdge = *Seq[0]; + const ArrayRef Source = getSource(); unsigned FromIID = FirstEdge.FromIID % Source.size(); unsigned ToIID = FirstEdge.ToIID % Source.size(); bool IsLoopCarried = FromIID >= ToIID; @@ -331,17 +324,17 @@ 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 @@ 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 @@ 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 @@ while (CurrentIID < Source.size()) { FOS << "\n " << CurrentIID << "."; - printInstruction(FOS, STI, MCIP, Source[CurrentIID]); + printInstruction(FOS, Source[CurrentIID]); CurrentIID++; } @@ -451,8 +444,8 @@ BottleneckAnalysis::BottleneckAnalysis(const MCSubtargetInfo &sti, MCInstPrinter &Printer, ArrayRef 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 @@ 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::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::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 @@ if (Event.Type != HWInstructionEvent::Issued) return; + const ArrayRef Source = getSource(); const Instruction &IS = *Event.IR.getInstruction(); unsigned To = IID % Source.size(); @@ -617,7 +611,7 @@ if (BPI.PressureIncreaseCycles) { ArrayRef 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) { Index: llvm/tools/llvm-mca/Views/InstructionInfoView.h =================================================================== --- llvm/tools/llvm-mca/Views/InstructionInfoView.h +++ llvm/tools/llvm-mca/Views/InstructionInfoView.h @@ -50,13 +50,10 @@ 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 Source; - llvm::MCInstPrinter &MCIP; struct InstructionInfoViewData { unsigned NumMicroOpcodes = 0; @@ -76,8 +73,8 @@ const llvm::MCInstrInfo &II, CodeEmitter &C, bool ShouldPrintEncodings, llvm::ArrayRef 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; }; Index: llvm/tools/llvm-mca/Views/InstructionInfoView.cpp =================================================================== --- llvm/tools/llvm-mca/Views/InstructionInfoView.cpp +++ llvm/tools/llvm-mca/Views/InstructionInfoView.cpp @@ -20,9 +20,8 @@ void InstructionInfoView::printView(raw_ostream &OS) const { std::string Buffer; raw_string_ostream TempStream(Buffer); - std::string Instruction; - raw_string_ostream InstrStream(Instruction); + const ArrayRef &Source = getSource(); if (!Source.size()) return; @@ -82,14 +81,7 @@ } 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::collectData( MutableArrayRef 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()); Index: llvm/tools/llvm-mca/Views/ResourcePressureView.h =================================================================== --- llvm/tools/llvm-mca/Views/ResourcePressureView.h +++ llvm/tools/llvm-mca/Views/ResourcePressureView.h @@ -69,10 +69,7 @@ /// 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 Source; +class ResourcePressureView : public InstructionView { unsigned LastInstructionIdx; // Map to quickly obtain the ResourceUsage column index from a processor Index: llvm/tools/llvm-mca/Views/ResourcePressureView.cpp =================================================================== --- llvm/tools/llvm-mca/Views/ResourcePressureView.cpp +++ llvm/tools/llvm-mca/Views/ResourcePressureView.cpp @@ -21,10 +21,10 @@ ResourcePressureView::ResourcePressureView(const llvm::MCSubtargetInfo &sti, MCInstPrinter &Printer, ArrayRef 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 @@ } 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 @@ return; const auto &IssueEvent = static_cast(Event); + const ArrayRef &Source = getSource(); const unsigned SourceIdx = Event.IR.getSourceIndex() % Source.size(); for (const std::pair &Use : IssueEvent.UsedResources) { @@ -105,7 +106,7 @@ 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 @@ FOS << '\n'; FOS.flush(); + const ArrayRef 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 @@ 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; + const ArrayRef Source = getSource(); const unsigned Executions = LastInstructionIdx / Source.size() + 1; for (const MCInst &MCI : Source) { unsigned BaseEltIdx = InstrIndex * NumResourceUnits; @@ -163,16 +163,7 @@ 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 = ""; Index: llvm/tools/llvm-mca/Views/TimelineView.h =================================================================== --- llvm/tools/llvm-mca/Views/TimelineView.h +++ llvm/tools/llvm-mca/Views/TimelineView.h @@ -118,11 +118,7 @@ /// 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 Source; - +class TimelineView : public InstructionView { unsigned CurrentCycle; unsigned MaxCycle; unsigned LastCycle; Index: llvm/tools/llvm-mca/Views/TimelineView.cpp =================================================================== --- llvm/tools/llvm-mca/Views/TimelineView.cpp +++ llvm/tools/llvm-mca/Views/TimelineView.cpp @@ -20,10 +20,10 @@ TimelineView::TimelineView(const MCSubtargetInfo &sti, MCInstPrinter &Printer, llvm::ArrayRef 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 @@ void TimelineView::onReservedBuffers(const InstRef &IR, ArrayRef Buffers) { - if (IR.getSourceIndex() >= Source.size()) + if (IR.getSourceIndex() >= getSource().size()) return; - const MCSchedModel &SM = STI.getSchedModel(); + const MCSchedModel &SM = getSubTargetInfo().getSchedModel(); std::pair BufferInfo = {0, -1}; for (const unsigned Buffer : Buffers) { const MCProcResourceDesc &MCDesc = *SM.getProcResource(Buffer); @@ -70,7 +70,7 @@ // Update the WaitTime entry which corresponds to this Index. assert(TVEntry.CycleDispatched >= 0 && "Invalid TVEntry found!"); unsigned CycleDispatched = static_cast(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 @@ 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 @@ 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 @@ "[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 @@ printWaitTimeEntry(FOS, TotalWaitTime, IID, Executions); FOS << " " << "" << '\n'; - InstrStream.flush(); + FOS.flush(); } } @@ -292,11 +279,8 @@ printTimelineHeader(FOS, LastCycle); FOS.flush(); - // Use a different string stream for the instruction. - std::string Instruction; - raw_string_ostream InstrStream(Instruction); - unsigned IID = 0; + const ArrayRef &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 @@ 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; } Index: llvm/tools/llvm-mca/Views/View.h =================================================================== --- llvm/tools/llvm-mca/Views/View.h +++ llvm/tools/llvm-mca/Views/View.h @@ -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,38 @@ 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; + const llvm::ArrayRef Source; + + // Fields that + mutable std::string InstructionString; + mutable raw_string_ostream InstrStream; + +protected: + InstructionView(const llvm::MCSubtargetInfo &STI, + llvm::MCInstPrinter &Printer, + const llvm::ArrayRef S) + : STI(STI), MCIP(Printer), Source(S), InstrStream(InstructionString) {} + + // 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 { + InstructionString = ""; + MCIP.printInst(&MCI, 0, "", STI, InstrStream); + InstrStream.flush(); + // Remove any tabs or spaces at the beginning of the instruction. + return StringRef(InstructionString).ltrim(); + } + + const llvm::MCSubtargetInfo &getSubTargetInfo() const { return STI; } + llvm::MCInstPrinter &getInstPrinter() const { return MCIP; } + const llvm::ArrayRef getSource() const { return Source; } +}; } // namespace mca } // namespace llvm