Skip to content
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions llvm/docs/CommandGuide/llvm-mca.rst
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,20 @@ option specifies "``-``", then the output will also be sent to standard output.
Enable extra scheduler statistics. This view collects and analyzes instruction
issue events. This view is disabled by default.

.. option:: -scheduling-info

Enable scheduling info view. This view reports scheduling information defined
in LLVM target description in the form:
``<uOps> <Latency> <Bypass Latency> <Throughput> <LLVM Opcode Name> <Resources
units> <instruction and comment (// or /* */) if defined>``
It allows to compare scheduling info with architecture documents and fix them
in target description by fixing InstrRW for the reported LLVM opcode.
Scheduling information can be defined in the same order in each instruction
comments to check easily reported and reference scheduling information.
Suggested information in comment:
``// <architecture instruction form> \\ <scheduling documentation title> \\
<uOps>, <Latency>, <Bypass Latency>, <Throughput>, <Resources units>``

.. option:: -retire-stats

Enable extra retire control unit statistics. This view is disabled by default.
Expand Down
4 changes: 4 additions & 0 deletions llvm/include/llvm/MC/MCSchedule.h
Original file line number Diff line number Diff line change
Expand Up @@ -402,6 +402,10 @@ struct MCSchedModel {
static unsigned getForwardingDelayCycles(ArrayRef<MCReadAdvanceEntry> Entries,
unsigned WriteResourceIdx = 0);

/// Returns the bypass delay cycle for the maximum latency write cycle
static unsigned getBypassDelayCycles(const MCSubtargetInfo &STI,
const MCSchedClassDesc &SCDesc);

/// Returns the default initialized model.
static const MCSchedModel Default;
};
Expand Down
36 changes: 36 additions & 0 deletions llvm/lib/MC/MCSchedule.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -174,3 +174,39 @@ MCSchedModel::getForwardingDelayCycles(ArrayRef<MCReadAdvanceEntry> Entries,

return std::abs(DelayCycles);
}

unsigned MCSchedModel::getBypassDelayCycles(const MCSubtargetInfo &STI,
const MCSchedClassDesc &SCDesc) {

ArrayRef<MCReadAdvanceEntry> Entries = STI.getReadAdvanceEntries(SCDesc);
if (Entries.empty())
return 0;

unsigned Latency = 0;
unsigned MaxLatency = 0;
unsigned WriteResourceID = 0;
unsigned DefEnd = SCDesc.NumWriteLatencyEntries;

for (unsigned DefIdx = 0; DefIdx != DefEnd; ++DefIdx) {
// Lookup the definition's write latency in SubtargetInfo.
const MCWriteLatencyEntry *WLEntry =
STI.getWriteLatencyEntry(&SCDesc, DefIdx);
unsigned Cycles = (unsigned)WLEntry->Cycles;
// Invalid latency. Consider 0 cycle latency
if (WLEntry->Cycles < 0)
Cycles = 0;
if (Cycles > Latency) {
MaxLatency = Cycles;
WriteResourceID = WLEntry->WriteResourceID;
}
Latency = MaxLatency;
}

for (const MCReadAdvanceEntry &E : Entries) {
if (E.WriteResourceID == WriteResourceID)
return E.Cycles;
}

// Unable to find WriteResourceID in MCReadAdvanceEntry Entries
return 0;
}
7,748 changes: 3,889 additions & 3,859 deletions llvm/test/tools/llvm-mca/AArch64/Neoverse/V1-sve-instructions.s

Large diffs are not rendered by default.

152 changes: 152 additions & 0 deletions llvm/tools/llvm-mca/Views/InstructionInfoView.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,121 @@
#include "Views/InstructionInfoView.h"
#include "llvm/Support/FormattedStream.h"
#include "llvm/Support/JSON.h"
#include "llvm/Support/WithColor.h"

namespace llvm {
namespace mca {

void InstructionInfoView::getComment(const MCInst &MCI,
std::string &CommentString) const {
StringRef s = MCI.getLoc().getPointer();
std::string InstrStr;
size_t pos = 0, pos_cmt = 0;

// Recognized comments are after assembly instructions on the same line.
// It is usefull to add in comment scheduling information from architecture
// specification.
// '#' comment mark is not supported by llvm-mca

CommentString = "";
if ((pos = s.find("\n")) != std::string::npos) {
InstrStr = s.substr(0, pos);
// C style comment
if (((pos_cmt = InstrStr.find("/*")) != std::string::npos) &&
((pos = InstrStr.find("*/")) != std::string::npos)) {
CommentString = InstrStr.substr(pos_cmt, pos);
return;
}
// C++ style comment
if ((pos_cmt = InstrStr.find("//")) != std::string::npos) {
CommentString = InstrStr.substr(pos_cmt, pos);
return;
}
}
return;
}

void InstructionInfoView::printSchedulingInfoView(raw_ostream &OS) const {
std::string Buffer;
std::string CommentString;
raw_string_ostream TempStream(Buffer);
formatted_raw_ostream FOS(TempStream);

ArrayRef<MCInst> Source = getSource();
if (!Source.size())
return;

IIVDVec IIVD(Source.size());
collectData(IIVD);

FOS << "\n\nResources:\n";
const MCSchedModel &SM = getSubTargetInfo().getSchedModel();
for (unsigned I = 1, ResourceIndex = 0, E = SM.getNumProcResourceKinds();
I < E; ++I) {
const MCProcResourceDesc &ProcResource = *SM.getProcResource(I);
unsigned NumUnits = ProcResource.NumUnits;
// Skip invalid resources with zero units.
if (!NumUnits)
continue;

FOS << '[' << ResourceIndex << ']';
FOS.PadToColumn(6);
FOS << "- " << ProcResource.Name << ':' << NumUnits;
if (ProcResource.SubUnitsIdxBegin) {
FOS.PadToColumn(20);
for (unsigned U = 0; U < NumUnits; ++U) {
FOS << SM.getProcResource(ProcResource.SubUnitsIdxBegin[U])->Name;
if ((U + 1) < NumUnits) {
FOS << ", ";
}
}
}
FOS << '\n';
ResourceIndex++;
}

FOS << "\n\nScheduling Info:\n";
FOS << "[1]: #uOps\n[2]: Latency\n[3]: Bypass Latency\n"
<< "[4]: Throughput\n[5]: Resources\n"
<< "[6]: LLVM OpcodeName\n";

// paddings for each scheduling info output. Start at [2]
std::vector<unsigned> paddings = {7, 12, 18, 27, 94, 113, 150};
for (unsigned i = 0; i < paddings.size() - 1; i++) {
FOS << "[" << i + 1 << "]";
FOS.PadToColumn(paddings[i]);
}
FOS << "Instructions:\n";

for (const auto &[Index, IIVDEntry, Inst] : enumerate(IIVD, Source)) {
getComment(Inst, CommentString);

FOS << " " << IIVDEntry.NumMicroOpcodes;
FOS.PadToColumn(paddings[0]);
FOS << " " << IIVDEntry.Latency;
FOS.PadToColumn(paddings[1]);
FOS << " " << IIVDEntry.Bypass;
FOS.PadToColumn(paddings[2]);
if (IIVDEntry.RThroughput) {
double RT = 1.0 / *IIVDEntry.RThroughput;
FOS << " " << format("%.2f", RT);
} else {
FOS << " -";
}
FOS.PadToColumn(paddings[3]);
FOS << " " << IIVDEntry.Resources;
FOS.PadToColumn(paddings[4]);
FOS << " " << IIVDEntry.OpcodeName;
FOS.PadToColumn(paddings[5]);
FOS << " " << printInstructionString(Inst);
FOS.PadToColumn(paddings[6]);
FOS << CommentString << '\n';
}

FOS.flush();
OS << Buffer;
}

void InstructionInfoView::printView(raw_ostream &OS) const {
std::string Buffer;
raw_string_ostream TempStream(Buffer);
Expand All @@ -29,6 +140,18 @@ void InstructionInfoView::printView(raw_ostream &OS) const {
IIVDVec IIVD(Source.size());
collectData(IIVD);

if (PrintSchedulingInfo) {
if (PrintEncodings)
WithColor::warning()
<< "No encodings printed when -scheduling-info option enabled.\n";
if (PrintBarriers)
WithColor::warning()
<< "No barrier printed when -scheduling-info option enabled.\n";

printSchedulingInfoView(OS);
return;
}

TempStream << "\n\nInstruction Info:\n";
TempStream << "[1]: #uOps\n[2]: Latency\n[3]: RThroughput\n"
<< "[4]: MayLoad\n[5]: MayStore\n[6]: HasSideEffects (U)\n";
Expand Down Expand Up @@ -141,6 +264,35 @@ void InstructionInfoView::collectData(
IIVDEntry.mayLoad = MCDesc.mayLoad();
IIVDEntry.mayStore = MCDesc.mayStore();
IIVDEntry.hasUnmodeledSideEffects = MCDesc.hasUnmodeledSideEffects();

if (PrintSchedulingInfo) {
// Get latency with bypass
IIVDEntry.Bypass =
IIVDEntry.Latency - MCSchedModel::getBypassDelayCycles(STI, SCDesc);
IIVDEntry.OpcodeName = (std::string)MCII.getName(Inst.getOpcode());
raw_string_ostream TempStream(IIVDEntry.Resources);
const MCWriteProcResEntry *Index = STI.getWriteProcResBegin(&SCDesc);
const MCWriteProcResEntry *Last = STI.getWriteProcResEnd(&SCDesc);
auto sep = "";
for (; Index != Last; ++Index) {
if (!Index->ReleaseAtCycle)
continue;
const MCProcResourceDesc *MCProc =
SM.getProcResource(Index->ProcResourceIdx);
if (Index->ReleaseAtCycle > 1) {
// Output ReleaseAtCycle between [] if not 1 (default)
// This is to be able to evaluate throughput.
// See getReciprocalThroughput in MCSchedule.cpp
// TODO: report AcquireAtCycle to check this scheduling info.
TempStream << sep
<< format("%s[%d]", MCProc->Name, Index->ReleaseAtCycle);
} else {
TempStream << sep << format("%s", MCProc->Name);
}
sep = ",";
}
TempStream.flush();
}
}
}

Expand Down
19 changes: 17 additions & 2 deletions llvm/tools/llvm-mca/Views/InstructionInfoView.h
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ class InstructionInfoView : public InstructionView {
CodeEmitter &CE;
bool PrintEncodings;
bool PrintBarriers;
bool PrintSchedulingInfo;
using UniqueInst = std::unique_ptr<Instruction>;
ArrayRef<UniqueInst> LoweredInsts;
const InstrumentManager &IM;
Expand All @@ -65,28 +66,42 @@ class InstructionInfoView : public InstructionView {

struct InstructionInfoViewData {
unsigned NumMicroOpcodes = 0;
// Latency + ForwardingDelayCycles: negative ReadAdvance
unsigned Latency = 0;
// ReadAvance Bypasses cycles: Latency - ReadAdvance (positive value)
unsigned Bypass = 0;
std::optional<double> RThroughput = 0.0;
bool mayLoad = false;
bool mayStore = false;
bool hasUnmodeledSideEffects = false;
std::string OpcodeName = "";
std::string Resources = "";
};
using IIVDVec = SmallVector<InstructionInfoViewData, 16>;

/// Place the data into the array of InstructionInfoViewData IIVD.
void collectData(MutableArrayRef<InstructionInfoViewData> IIVD) const;

/// Extract comment (//, /* */) from the source assembly placed just after
/// instruction.
void getComment(const llvm::MCInst &Inst, std::string &CommentString) const;
/// Print Scheduling Info to avoid mixing too much options
void printSchedulingInfoView(raw_ostream &OS) const;

public:
InstructionInfoView(const llvm::MCSubtargetInfo &ST,
const llvm::MCInstrInfo &II, CodeEmitter &C,
bool ShouldPrintEncodings, llvm::ArrayRef<llvm::MCInst> S,
llvm::MCInstPrinter &IP,
ArrayRef<UniqueInst> LoweredInsts,
bool ShouldPrintBarriers, const InstrumentManager &IM,
bool ShouldPrintBarriers, bool ShouldPrintSchedulingInfo,
const InstrumentManager &IM,
const InstToInstrumentsT &InstToInstruments)
: InstructionView(ST, IP, S), MCII(II), CE(C),
PrintEncodings(ShouldPrintEncodings),
PrintBarriers(ShouldPrintBarriers), LoweredInsts(LoweredInsts), IM(IM),
PrintBarriers(ShouldPrintBarriers),
PrintSchedulingInfo(ShouldPrintSchedulingInfo),
LoweredInsts(LoweredInsts), IM(IM),
InstToInstruments(InstToInstruments) {}

void printView(llvm::raw_ostream &OS) const override;
Expand Down
11 changes: 9 additions & 2 deletions llvm/tools/llvm-mca/llvm-mca.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -259,6 +259,12 @@ static cl::opt<bool> ShowBarriers(
cl::desc("Print memory barrier information in the instruction info view"),
cl::cat(ViewOptions), cl::init(false));

static cl::opt<bool>
ShowSchedulingInfo("scheduling-info",
cl::desc("Print the instruction scheduling information "
"in the instruction info view"),
cl::cat(ViewOptions), cl::init(false));

static cl::opt<bool> DisableCustomBehaviour(
"disable-cb",
cl::desc(
Expand Down Expand Up @@ -680,8 +686,9 @@ int main(int argc, char **argv) {
if (PrintInstructionInfoView) {
Printer.addView(std::make_unique<mca::InstructionInfoView>(
*STI, *MCII, CE, ShowEncoding, Insts, *IP, LoweredSequence,
ShowBarriers, *IM, InstToInstruments));
ShowBarriers, ShowSchedulingInfo, *IM, InstToInstruments));
}

Printer.addView(
std::make_unique<mca::ResourcePressureView>(*STI, *IP, Insts));

Expand Down Expand Up @@ -757,7 +764,7 @@ int main(int argc, char **argv) {
if (PrintInstructionInfoView)
Printer.addView(std::make_unique<mca::InstructionInfoView>(
*STI, *MCII, CE, ShowEncoding, Insts, *IP, LoweredSequence,
ShowBarriers, *IM, InstToInstruments));
ShowBarriers, ShowSchedulingInfo, *IM, InstToInstruments));

// Fetch custom Views that are to be placed after the InstructionInfoView.
// Refer to the comment paired with the CB->getStartViews(*IP, Insts); line
Expand Down