aboutsummaryrefslogtreecommitdiff
path: root/llvm/tools/llvm-mca/Views
diff options
context:
space:
mode:
Diffstat (limited to 'llvm/tools/llvm-mca/Views')
-rw-r--r--llvm/tools/llvm-mca/Views/BottleneckAnalysis.cpp15
-rw-r--r--llvm/tools/llvm-mca/Views/BottleneckAnalysis.h30
-rw-r--r--llvm/tools/llvm-mca/Views/DispatchStatistics.cpp16
-rw-r--r--llvm/tools/llvm-mca/Views/DispatchStatistics.h1
-rw-r--r--llvm/tools/llvm-mca/Views/InstructionInfoView.cpp4
-rw-r--r--llvm/tools/llvm-mca/Views/InstructionView.cpp33
-rw-r--r--llvm/tools/llvm-mca/Views/InstructionView.h26
-rw-r--r--llvm/tools/llvm-mca/Views/RegisterFileStatistics.cpp27
-rw-r--r--llvm/tools/llvm-mca/Views/RegisterFileStatistics.h1
-rw-r--r--llvm/tools/llvm-mca/Views/RetireControlUnitStatistics.cpp3
-rw-r--r--llvm/tools/llvm-mca/Views/RetireControlUnitStatistics.h1
-rw-r--r--llvm/tools/llvm-mca/Views/SchedulerStatistics.h1
-rw-r--r--llvm/tools/llvm-mca/Views/SummaryView.cpp7
-rw-r--r--llvm/tools/llvm-mca/Views/SummaryView.h2
-rw-r--r--llvm/tools/llvm-mca/Views/TimelineView.cpp22
-rw-r--r--llvm/tools/llvm-mca/Views/TimelineView.h2
-rw-r--r--llvm/tools/llvm-mca/Views/View.h20
17 files changed, 103 insertions, 108 deletions
diff --git a/llvm/tools/llvm-mca/Views/BottleneckAnalysis.cpp b/llvm/tools/llvm-mca/Views/BottleneckAnalysis.cpp
index 38a8e2ef9c53..5b110d6602df 100644
--- a/llvm/tools/llvm-mca/Views/BottleneckAnalysis.cpp
+++ b/llvm/tools/llvm-mca/Views/BottleneckAnalysis.cpp
@@ -66,8 +66,6 @@ void PressureTracker::onInstructionExecuted(unsigned IID) { IPI.erase(IID); }
void PressureTracker::handleInstructionIssuedEvent(
const HWInstructionIssuedEvent &Event) {
unsigned IID = Event.IR.getSourceIndex();
- using ResourceRef = HWInstructionIssuedEvent::ResourceRef;
- using ResourceUse = std::pair<ResourceRef, ResourceCycles>;
for (const ResourceUse &Use : Event.UsedResources) {
const ResourceRef &RR = Use.first;
unsigned Index = ProcResID2ResourceUsersIndex[RR.first];
@@ -200,8 +198,8 @@ void DependencyGraph::initializeRootSet(
}
}
-void DependencyGraph::propagateThroughEdges(
- SmallVectorImpl<unsigned> &RootSet, unsigned Iterations) {
+void DependencyGraph::propagateThroughEdges(SmallVectorImpl<unsigned> &RootSet,
+ unsigned Iterations) {
SmallVector<unsigned, 8> ToVisit;
// A critical sequence is computed as the longest path from a node of the
@@ -223,14 +221,14 @@ void DependencyGraph::propagateThroughEdges(
// The `unvisited nodes` set initially contains all the nodes from the
// RootSet. A node N is added to the `unvisited nodes` if all its
// predecessors have been visited already.
- //
+ //
// For simplicity, every node tracks the number of unvisited incoming edges in
// field `NumVisitedPredecessors`. When the value of that field drops to
// zero, then the corresponding node is added to a `ToVisit` set.
//
// At the end of every iteration of the outer loop, set `ToVisit` becomes our
// new `unvisited nodes` set.
- //
+ //
// The algorithm terminates when the set of unvisited nodes (i.e. our RootSet)
// is empty. This algorithm works under the assumption that the graph is
// acyclic.
@@ -269,8 +267,9 @@ void DependencyGraph::getCriticalSequence(
// that node is the last instruction of our critical sequence.
// Field N.Depth would tell us the total length of the sequence.
//
- // To obtain the sequence of critical edges, we simply follow the chain of critical
- // predecessors starting from node N (field DGNode::CriticalPredecessor).
+ // To obtain the sequence of critical edges, we simply follow the chain of
+ // critical predecessors starting from node N (field
+ // DGNode::CriticalPredecessor).
const auto It = std::max_element(
Nodes.begin(), Nodes.end(),
[](const DGNode &Lhs, const DGNode &Rhs) { return Lhs.Cost < Rhs.Cost; });
diff --git a/llvm/tools/llvm-mca/Views/BottleneckAnalysis.h b/llvm/tools/llvm-mca/Views/BottleneckAnalysis.h
index 427937d9e3d7..cd5af0afcf5b 100644
--- a/llvm/tools/llvm-mca/Views/BottleneckAnalysis.h
+++ b/llvm/tools/llvm-mca/Views/BottleneckAnalysis.h
@@ -33,9 +33,9 @@
/// In particular, this occurs when there is a delta between the number of uOps
/// dispatched and the number of uOps issued to the underlying pipelines.
///
-/// The bottleneck analysis view is also responsible for identifying and printing
-/// the most "critical" sequence of dependent instructions according to the
-/// simulated run.
+/// The bottleneck analysis view is also responsible for identifying and
+/// printing the most "critical" sequence of dependent instructions according to
+/// the simulated run.
///
/// Below is the critical sequence computed for the dot-product example on
/// btver2:
@@ -62,13 +62,14 @@
/// and edges of the graph represent data dependencies or processor resource
/// interferences.
///
-/// Edges are dynamically 'discovered' by observing instruction state transitions
-/// and backend pressure increase events. Edges are internally ranked based on
-/// their "criticality". A dependency is considered to be critical if it takes a
-/// long time to execute, and if it contributes to backend pressure increases.
-/// Criticality is internally measured in terms of cycles; it is computed for
-/// every edge in the graph as a function of the edge latency and the number of
-/// backend pressure increase cycles contributed by that edge.
+/// Edges are dynamically 'discovered' by observing instruction state
+/// transitions and backend pressure increase events. Edges are internally
+/// ranked based on their "criticality". A dependency is considered to be
+/// critical if it takes a long time to execute, and if it contributes to
+/// backend pressure increases. Criticality is internally measured in terms of
+/// cycles; it is computed for every edge in the graph as a function of the edge
+/// latency and the number of backend pressure increase cycles contributed by
+/// that edge.
///
/// At the end of simulation, costs are propagated to nodes through the edges of
/// the graph, and the most expensive path connecting the root-set (a
@@ -217,8 +218,8 @@ struct DependencyEdge {
// Loop carried dependencies are carefully expanded by the bottleneck analysis
// to guarantee that the graph stays acyclic. To this end, extra nodes are
// pre-allocated at construction time to describe instructions from "past and
-// future" iterations. The graph is kept acyclic mainly because it simplifies the
-// complexity of the algorithm that computes the critical sequence.
+// future" iterations. The graph is kept acyclic mainly because it simplifies
+// the complexity of the algorithm that computes the critical sequence.
class DependencyGraph {
struct DGNode {
unsigned NumPredecessors;
@@ -239,7 +240,8 @@ class DependencyGraph {
void pruneEdges(unsigned Iterations);
void initializeRootSet(SmallVectorImpl<unsigned> &RootSet) const;
- void propagateThroughEdges(SmallVectorImpl<unsigned> &RootSet, unsigned Iterations);
+ void propagateThroughEdges(SmallVectorImpl<unsigned> &RootSet,
+ unsigned Iterations);
#ifndef NDEBUG
void dumpDependencyEdge(raw_ostream &OS, const DependencyEdge &DE,
@@ -333,7 +335,7 @@ public:
void printView(raw_ostream &OS) const override;
StringRef getNameAsString() const override { return "BottleneckAnalysis"; }
- json::Value toJSON() const override { return "not implemented"; }
+ bool isSerializable() const override { return false; }
#ifndef NDEBUG
void dump(raw_ostream &OS, MCInstPrinter &MCIP) const { DG.dump(OS, MCIP); }
diff --git a/llvm/tools/llvm-mca/Views/DispatchStatistics.cpp b/llvm/tools/llvm-mca/Views/DispatchStatistics.cpp
index a1c0cf208d35..3dc17c8754d8 100644
--- a/llvm/tools/llvm-mca/Views/DispatchStatistics.cpp
+++ b/llvm/tools/llvm-mca/Views/DispatchStatistics.cpp
@@ -1,5 +1,4 @@
-//===--------------------- DispatchStatistics.cpp ---------------------*- C++
-//-*-===//
+//===--------------------- DispatchStatistics.cpp ---------------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
@@ -77,10 +76,23 @@ void DispatchStatistics::printDispatchStalls(raw_ostream &OS) const {
printStalls(SS, HWStalls[HWStallEvent::StoreQueueFull], NumCycles);
SS << "\nGROUP - Static restrictions on the dispatch group: ";
printStalls(SS, HWStalls[HWStallEvent::DispatchGroupStall], NumCycles);
+ SS << "\nUSH - Uncategorised Structural Hazard: ";
+ printStalls(SS, HWStalls[HWStallEvent::CustomBehaviourStall], NumCycles);
SS << '\n';
SS.flush();
OS << Buffer;
}
+json::Value DispatchStatistics::toJSON() const {
+ json::Object JO({{"RAT", HWStalls[HWStallEvent::RegisterFileStall]},
+ {"RCU", HWStalls[HWStallEvent::RetireControlUnitStall]},
+ {"SCHEDQ", HWStalls[HWStallEvent::SchedulerQueueFull]},
+ {"LQ", HWStalls[HWStallEvent::LoadQueueFull]},
+ {"SQ", HWStalls[HWStallEvent::StoreQueueFull]},
+ {"GROUP", HWStalls[HWStallEvent::DispatchGroupStall]},
+ {"USH", HWStalls[HWStallEvent::CustomBehaviourStall]}});
+ return JO;
+}
+
} // namespace mca
} // namespace llvm
diff --git a/llvm/tools/llvm-mca/Views/DispatchStatistics.h b/llvm/tools/llvm-mca/Views/DispatchStatistics.h
index 8d999fb0acfe..81b582f74a6b 100644
--- a/llvm/tools/llvm-mca/Views/DispatchStatistics.h
+++ b/llvm/tools/llvm-mca/Views/DispatchStatistics.h
@@ -79,6 +79,7 @@ public:
printDispatchHistogram(OS);
}
StringRef getNameAsString() const override { return "DispatchStatistics"; }
+ json::Value toJSON() const override;
};
} // namespace mca
} // namespace llvm
diff --git a/llvm/tools/llvm-mca/Views/InstructionInfoView.cpp b/llvm/tools/llvm-mca/Views/InstructionInfoView.cpp
index 2248f63fe7e9..3f6abf4af2cf 100644
--- a/llvm/tools/llvm-mca/Views/InstructionInfoView.cpp
+++ b/llvm/tools/llvm-mca/Views/InstructionInfoView.cpp
@@ -93,7 +93,7 @@ void InstructionInfoView::collectData(
MutableArrayRef<InstructionInfoViewData> IIVD) const {
const llvm::MCSubtargetInfo &STI = getSubTargetInfo();
const MCSchedModel &SM = STI.getSchedModel();
- for (const auto &I : zip(getSource(), IIVD)) {
+ for (const 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());
@@ -147,7 +147,7 @@ json::Value InstructionInfoView::toJSON() const {
JO.try_emplace("Instruction", (unsigned)I.index());
InstInfo.push_back(std::move(JO));
}
- return json::Value(std::move(InstInfo));
+ return json::Object({{"InstructionList", json::Value(std::move(InstInfo))}});
}
} // namespace mca.
} // namespace llvm
diff --git a/llvm/tools/llvm-mca/Views/InstructionView.cpp b/llvm/tools/llvm-mca/Views/InstructionView.cpp
index 7f7a5b7cdbbb..3b174a064985 100644
--- a/llvm/tools/llvm-mca/Views/InstructionView.cpp
+++ b/llvm/tools/llvm-mca/Views/InstructionView.cpp
@@ -1,4 +1,4 @@
-//===----------------------- View.cpp ---------------------------*- C++ -*-===//
+//===----------------------- InstructionView.cpp ----------------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
@@ -11,15 +11,18 @@
///
//===----------------------------------------------------------------------===//
-#include <sstream>
#include "Views/InstructionView.h"
#include "llvm/MC/MCInst.h"
+#include "llvm/MC/MCInstPrinter.h"
#include "llvm/MC/MCSubtargetInfo.h"
namespace llvm {
namespace mca {
-StringRef InstructionView::printInstructionString(const llvm::MCInst &MCI) const {
+InstructionView::~InstructionView() = default;
+
+StringRef
+InstructionView::printInstructionString(const llvm::MCInst &MCI) const {
InstructionString = "";
MCIP.printInst(&MCI, 0, "", STI, InstrStream);
InstrStream.flush();
@@ -28,33 +31,13 @@ StringRef InstructionView::printInstructionString(const llvm::MCInst &MCI) const
}
json::Value InstructionView::toJSON() const {
- json::Object JO;
json::Array SourceInfo;
for (const auto &MCI : getSource()) {
StringRef Instruction = printInstructionString(MCI);
SourceInfo.push_back(Instruction.str());
}
- JO.try_emplace("Instructions", std::move(SourceInfo));
-
- json::Array Resources;
- const MCSchedModel &SM = STI.getSchedModel();
- for (unsigned I = 1, E = SM.getNumProcResourceKinds(); I < E; ++I) {
- const MCProcResourceDesc &ProcResource = *SM.getProcResource(I);
- unsigned NumUnits = ProcResource.NumUnits;
- // Skip groups and invalid resources with zero units.
- if (ProcResource.SubUnitsIdxBegin || !NumUnits)
- continue;
- for (unsigned J = 0; J < NumUnits; ++J) {
- std::stringstream ResNameStream;
- ResNameStream << ProcResource.Name;
- if (NumUnits > 1)
- ResNameStream << "." << J;
- Resources.push_back(ResNameStream.str());
- }
- }
- JO.try_emplace("Resources", json::Object({{"CPUName", MCPU}, {"Resources", std::move(Resources)}}));
-
- return JO;
+ return SourceInfo;
}
+
} // namespace mca
} // namespace llvm
diff --git a/llvm/tools/llvm-mca/Views/InstructionView.h b/llvm/tools/llvm-mca/Views/InstructionView.h
index 2a260b97d8fb..1843b0513dfc 100644
--- a/llvm/tools/llvm-mca/Views/InstructionView.h
+++ b/llvm/tools/llvm-mca/Views/InstructionView.h
@@ -1,4 +1,4 @@
-//===----------------------- InstrucionView.h -----------------------------*- C++ -*-===//
+//===----------------------- InstructionView.h ------------------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
@@ -16,9 +16,8 @@
#define LLVM_TOOLS_LLVM_MCA_INSTRUCTIONVIEW_H
#include "Views/View.h"
-#include "llvm/MC/MCInstPrinter.h"
-#include "llvm/Support/raw_ostream.h"
#include "llvm/Support/JSON.h"
+#include "llvm/Support/raw_ostream.h"
namespace llvm {
namespace mca {
@@ -28,7 +27,6 @@ class InstructionView : public View {
const llvm::MCSubtargetInfo &STI;
llvm::MCInstPrinter &MCIP;
llvm::ArrayRef<llvm::MCInst> Source;
- StringRef MCPU;
mutable std::string InstructionString;
mutable raw_string_ostream InstrStream;
@@ -36,17 +34,13 @@ class InstructionView : public View {
public:
void printView(llvm::raw_ostream &) const override {}
InstructionView(const llvm::MCSubtargetInfo &STI,
- llvm::MCInstPrinter &Printer,
- llvm::ArrayRef<llvm::MCInst> S,
- StringRef MCPU = StringRef())
- : STI(STI), MCIP(Printer), Source(S), MCPU(MCPU),
- InstrStream(InstructionString) {}
+ llvm::MCInstPrinter &Printer, llvm::ArrayRef<llvm::MCInst> S)
+ : STI(STI), MCIP(Printer), Source(S), InstrStream(InstructionString) {}
+
+ virtual ~InstructionView();
- virtual ~InstructionView() = default;
+ StringRef getNameAsString() const override { return "Instructions"; }
- StringRef getNameAsString() const override {
- return "Instructions and CPU resources";
- }
// 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.
@@ -55,12 +49,10 @@ public:
llvm::MCInstPrinter &getInstPrinter() const { return MCIP; }
llvm::ArrayRef<llvm::MCInst> getSource() const { return Source; }
+
json::Value toJSON() const override;
- virtual void printViewJSON(llvm::raw_ostream &OS) override {
- json::Value JV = toJSON();
- OS << formatv("{0:2}", JV) << "\n";
- }
};
+
} // namespace mca
} // namespace llvm
diff --git a/llvm/tools/llvm-mca/Views/RegisterFileStatistics.cpp b/llvm/tools/llvm-mca/Views/RegisterFileStatistics.cpp
index 58736ee0d18c..4ef8053bff41 100644
--- a/llvm/tools/llvm-mca/Views/RegisterFileStatistics.cpp
+++ b/llvm/tools/llvm-mca/Views/RegisterFileStatistics.cpp
@@ -60,18 +60,21 @@ void RegisterFileStatistics::updateMoveElimInfo(const Instruction &Inst) {
if (!Inst.isOptimizableMove())
return;
- assert(Inst.getDefs().size() == 1 && "Expected a single definition!");
- assert(Inst.getUses().size() == 1 && "Expected a single register use!");
- const WriteState &WS = Inst.getDefs()[0];
- const ReadState &RS = Inst.getUses()[0];
-
- MoveEliminationInfo &Info =
- MoveElimInfo[Inst.getDefs()[0].getRegisterFileID()];
- Info.TotalMoveEliminationCandidates++;
- if (WS.isEliminated())
- Info.CurrentMovesEliminated++;
- if (WS.isWriteZero() && RS.isReadZero())
- Info.TotalMovesThatPropagateZero++;
+ if (Inst.getDefs().size() != Inst.getUses().size())
+ return;
+
+ for (size_t I = 0, E = Inst.getDefs().size(); I < E; ++I) {
+ const WriteState &WS = Inst.getDefs()[I];
+ const ReadState &RS = Inst.getUses()[E - (I + 1)];
+
+ MoveEliminationInfo &Info =
+ MoveElimInfo[Inst.getDefs()[0].getRegisterFileID()];
+ Info.TotalMoveEliminationCandidates++;
+ if (WS.isEliminated())
+ Info.CurrentMovesEliminated++;
+ if (WS.isWriteZero() && RS.isReadZero())
+ Info.TotalMovesThatPropagateZero++;
+ }
}
void RegisterFileStatistics::onEvent(const HWInstructionEvent &Event) {
diff --git a/llvm/tools/llvm-mca/Views/RegisterFileStatistics.h b/llvm/tools/llvm-mca/Views/RegisterFileStatistics.h
index cf384dbfe337..ec5c5f431e12 100644
--- a/llvm/tools/llvm-mca/Views/RegisterFileStatistics.h
+++ b/llvm/tools/llvm-mca/Views/RegisterFileStatistics.h
@@ -76,6 +76,7 @@ public:
StringRef getNameAsString() const override {
return "RegisterFileStatistics";
}
+ bool isSerializable() const override { return false; }
};
} // namespace mca
} // namespace llvm
diff --git a/llvm/tools/llvm-mca/Views/RetireControlUnitStatistics.cpp b/llvm/tools/llvm-mca/Views/RetireControlUnitStatistics.cpp
index 61c115b27be1..1c40428fb018 100644
--- a/llvm/tools/llvm-mca/Views/RetireControlUnitStatistics.cpp
+++ b/llvm/tools/llvm-mca/Views/RetireControlUnitStatistics.cpp
@@ -71,7 +71,8 @@ void RetireControlUnitStatistics::printView(raw_ostream &OS) const {
}
unsigned AvgUsage = (double)SumOfUsedEntries / NumCycles;
- double MaxUsagePercentage = ((double)MaxUsedEntries / TotalROBEntries) * 100.0;
+ double MaxUsagePercentage =
+ ((double)MaxUsedEntries / TotalROBEntries) * 100.0;
double NormalizedMaxPercentage = floor((MaxUsagePercentage * 10) + 0.5) / 10;
double AvgUsagePercentage = ((double)AvgUsage / TotalROBEntries) * 100.0;
double NormalizedAvgPercentage = floor((AvgUsagePercentage * 10) + 0.5) / 10;
diff --git a/llvm/tools/llvm-mca/Views/RetireControlUnitStatistics.h b/llvm/tools/llvm-mca/Views/RetireControlUnitStatistics.h
index 662a223662e6..86b46e93aa7c 100644
--- a/llvm/tools/llvm-mca/Views/RetireControlUnitStatistics.h
+++ b/llvm/tools/llvm-mca/Views/RetireControlUnitStatistics.h
@@ -55,6 +55,7 @@ public:
StringRef getNameAsString() const override {
return "RetireControlUnitStatistics";
}
+ bool isSerializable() const override { return false; }
};
} // namespace mca
diff --git a/llvm/tools/llvm-mca/Views/SchedulerStatistics.h b/llvm/tools/llvm-mca/Views/SchedulerStatistics.h
index 734046c3112f..66f4b0011866 100644
--- a/llvm/tools/llvm-mca/Views/SchedulerStatistics.h
+++ b/llvm/tools/llvm-mca/Views/SchedulerStatistics.h
@@ -89,6 +89,7 @@ public:
void printView(llvm::raw_ostream &OS) const override;
StringRef getNameAsString() const override { return "SchedulerStatistics"; }
+ bool isSerializable() const override { return false; }
};
} // namespace mca
} // namespace llvm
diff --git a/llvm/tools/llvm-mca/Views/SummaryView.cpp b/llvm/tools/llvm-mca/Views/SummaryView.cpp
index c0fe3b5193a7..bf258b4c26b1 100644
--- a/llvm/tools/llvm-mca/Views/SummaryView.cpp
+++ b/llvm/tools/llvm-mca/Views/SummaryView.cpp
@@ -1,4 +1,4 @@
-//===--------------------- SummaryView.cpp -------------------*- C++ -*-===//
+//===--------------------- SummaryView.cpp ----------------------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
@@ -24,9 +24,8 @@ namespace mca {
SummaryView::SummaryView(const MCSchedModel &Model, ArrayRef<MCInst> S,
unsigned Width)
- : SM(Model), Source(S), DispatchWidth(Width?Width: Model.IssueWidth),
- LastInstructionIdx(0),
- TotalCycles(0), NumMicroOps(0),
+ : SM(Model), Source(S), DispatchWidth(Width ? Width : Model.IssueWidth),
+ LastInstructionIdx(0), TotalCycles(0), NumMicroOps(0),
ProcResourceUsage(Model.getNumProcResourceKinds(), 0),
ProcResourceMasks(Model.getNumProcResourceKinds()),
ResIdx2ProcResID(Model.getNumProcResourceKinds(), 0) {
diff --git a/llvm/tools/llvm-mca/Views/SummaryView.h b/llvm/tools/llvm-mca/Views/SummaryView.h
index 2622e869ef23..e2c7cfd19e94 100644
--- a/llvm/tools/llvm-mca/Views/SummaryView.h
+++ b/llvm/tools/llvm-mca/Views/SummaryView.h
@@ -1,4 +1,4 @@
-//===--------------------- SummaryView.h ---------------------*- C++ -*-===//
+//===--------------------- SummaryView.h ------------------------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
diff --git a/llvm/tools/llvm-mca/Views/TimelineView.cpp b/llvm/tools/llvm-mca/Views/TimelineView.cpp
index c8b481bc7ce6..9a949761bb75 100644
--- a/llvm/tools/llvm-mca/Views/TimelineView.cpp
+++ b/llvm/tools/llvm-mca/Views/TimelineView.cpp
@@ -21,8 +21,8 @@ TimelineView::TimelineView(const MCSubtargetInfo &sti, MCInstPrinter &Printer,
llvm::ArrayRef<llvm::MCInst> S, unsigned Iterations,
unsigned Cycles)
: InstructionView(sti, Printer, S), CurrentCycle(0),
- MaxCycle(Cycles == 0 ? 80 : Cycles), LastCycle(0), WaitTime(S.size()),
- UsedBuffer(S.size()) {
+ MaxCycle(Cycles == 0 ? std::numeric_limits<unsigned>::max() : Cycles),
+ LastCycle(0), WaitTime(S.size()), UsedBuffer(S.size()) {
unsigned NumInstructions = getSource().size();
assert(Iterations && "Invalid number of iterations specified!");
NumInstructions *= Iterations;
@@ -77,8 +77,10 @@ void TimelineView::onEvent(const HWInstructionEvent &Event) {
"Instruction cannot be ready if it hasn't been dispatched yet!");
WTEntry.CyclesSpentInSQWhileReady +=
TVEntry.CycleIssued - TVEntry.CycleReady;
- WTEntry.CyclesSpentAfterWBAndBeforeRetire +=
- (CurrentCycle - 1) - TVEntry.CycleExecuted;
+ if (CurrentCycle > TVEntry.CycleExecuted) {
+ WTEntry.CyclesSpentAfterWBAndBeforeRetire +=
+ (CurrentCycle - 1) - TVEntry.CycleExecuted;
+ }
break;
}
case HWInstructionEvent::Ready:
@@ -243,7 +245,8 @@ void TimelineView::printTimelineViewEntry(formatted_raw_ostream &OS,
for (unsigned I = Entry.CycleExecuted + 1, E = Entry.CycleRetired; I < E; ++I)
OS << TimelineView::DisplayChar::RetireLag;
- OS << TimelineView::DisplayChar::Retired;
+ if (Entry.CycleExecuted < Entry.CycleRetired)
+ OS << TimelineView::DisplayChar::Retired;
// Skip other columns.
for (unsigned I = Entry.CycleRetired + 1, E = LastCycle; I <= E; ++I)
@@ -285,7 +288,14 @@ void TimelineView::printTimeline(raw_ostream &OS) const {
for (unsigned Iteration = 0; Iteration < Iterations; ++Iteration) {
for (const MCInst &Inst : Source) {
const TimelineViewEntry &Entry = Timeline[IID];
- if (Entry.CycleRetired == 0)
+ // When an instruction is retired after timeline-max-cycles,
+ // its CycleRetired is left at 0. However, it's possible for
+ // a 0 latency instruction to be retired during cycle 0 and we
+ // don't want to early exit in that case. The CycleExecuted
+ // attribute is set correctly whether or not it is greater
+ // than timeline-max-cycles so we can use that to ensure
+ // we don't early exit because of a 0 latency instruction.
+ if (Entry.CycleRetired == 0 && Entry.CycleExecuted != 0)
return;
unsigned SourceIndex = IID % Source.size();
diff --git a/llvm/tools/llvm-mca/Views/TimelineView.h b/llvm/tools/llvm-mca/Views/TimelineView.h
index 81f2b0335081..81be8244b779 100644
--- a/llvm/tools/llvm-mca/Views/TimelineView.h
+++ b/llvm/tools/llvm-mca/Views/TimelineView.h
@@ -125,7 +125,7 @@ class TimelineView : public InstructionView {
unsigned LastCycle;
struct TimelineViewEntry {
- int CycleDispatched; // A negative value is an "invalid cycle".
+ int CycleDispatched; // A negative value is an "invalid cycle".
unsigned CycleReady;
unsigned CycleIssued;
unsigned CycleExecuted;
diff --git a/llvm/tools/llvm-mca/Views/View.h b/llvm/tools/llvm-mca/Views/View.h
index 85464bfda662..c604733d4ec9 100644
--- a/llvm/tools/llvm-mca/Views/View.h
+++ b/llvm/tools/llvm-mca/Views/View.h
@@ -17,32 +17,22 @@
#include "llvm/MC/MCInstPrinter.h"
#include "llvm/MCA/HWEventListener.h"
-#include "llvm/Support/raw_ostream.h"
#include "llvm/Support/JSON.h"
+#include "llvm/Support/raw_ostream.h"
namespace llvm {
namespace mca {
class View : public HWEventListener {
public:
- enum OutputKind { OK_READABLE, OK_JSON };
-
- void printView(OutputKind OutputKind, llvm::raw_ostream &OS) {
- if (OutputKind == OK_JSON)
- printViewJSON(OS);
- else
- printView(OS);
- }
+ virtual ~View() = default;
virtual void printView(llvm::raw_ostream &OS) const = 0;
- virtual void printViewJSON(llvm::raw_ostream &OS) {
- json::Object JO;
- JO.try_emplace(getNameAsString().str(), toJSON());
- OS << formatv("{0:2}", json::Value(std::move(JO))) << "\n";
- }
- virtual ~View() = default;
virtual StringRef getNameAsString() const = 0;
+
virtual json::Value toJSON() const { return "not implemented"; }
+ virtual bool isSerializable() const { return true; }
+
void anchor() override;
};
} // namespace mca