[llvm] [LLVM][MC] Add tracing support to llvm-mc to measure decode times (PR #151149)
Rahul Joshi via llvm-commits
llvm-commits at lists.llvm.org
Tue Jul 29 06:27:55 PDT 2025
https://github.com/jurahul created https://github.com/llvm/llvm-project/pull/151149
Add support for measuring decode times in llvm-mc tool. Add command line options to enable time-trace profiling (similar to llc or opt) and add option `num-benchmark-runs` to run the decoder N times on each instruction.
>From 6c49bdd429968a7e59332e122fea5c0015cfa25b Mon Sep 17 00:00:00 2001
From: Rahul Joshi <rjoshi at nvidia.com>
Date: Sat, 21 Jun 2025 10:32:11 -0700
Subject: [PATCH] LLVM-MC profiling to measure disassembly times
---
llvm/tools/llvm-mc/Disassembler.cpp | 49 +++++++++++++++++++----------
llvm/tools/llvm-mc/Disassembler.h | 3 +-
llvm/tools/llvm-mc/llvm-mc.cpp | 46 ++++++++++++++++++++++++---
3 files changed, 76 insertions(+), 22 deletions(-)
diff --git a/llvm/tools/llvm-mc/Disassembler.cpp b/llvm/tools/llvm-mc/Disassembler.cpp
index 86727931067a5..00dee06e847ce 100644
--- a/llvm/tools/llvm-mc/Disassembler.cpp
+++ b/llvm/tools/llvm-mc/Disassembler.cpp
@@ -12,6 +12,7 @@
//===----------------------------------------------------------------------===//
#include "Disassembler.h"
+#include "llvm/ADT/Sequence.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/MC/MCAsmInfo.h"
#include "llvm/MC/MCContext.h"
@@ -24,6 +25,7 @@
#include "llvm/MC/TargetRegistry.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/SourceMgr.h"
+#include "llvm/Support/TimeProfiler.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/TargetParser/Triple.h"
@@ -32,24 +34,25 @@ using namespace llvm;
typedef std::pair<std::vector<unsigned char>, std::vector<const char *>>
ByteArrayTy;
-static bool PrintInsts(const MCDisassembler &DisAsm, const ByteArrayTy &Bytes,
+static bool printInsts(const MCDisassembler &DisAsm, const ByteArrayTy &Bytes,
SourceMgr &SM, MCStreamer &Streamer, bool InAtomicBlock,
- const MCSubtargetInfo &STI) {
+ const MCSubtargetInfo &STI, unsigned BenchmarkNumRuns) {
ArrayRef<uint8_t> Data(Bytes.first);
// Disassemble it to strings.
uint64_t Size;
- uint64_t Index;
- for (Index = 0; Index < Bytes.first.size(); Index += Size) {
- MCInst Inst;
+ for (uint64_t Index = 0; Index < Bytes.first.size(); Index += Size) {
+ auto getInstruction = [&](MCInst &Inst) -> MCDisassembler::DecodeStatus {
+ if (STI.getTargetTriple().getArch() == Triple::hexagon)
+ return DisAsm.getInstructionBundle(Inst, Size, Data.slice(Index), Index,
+ nulls());
+ return DisAsm.getInstruction(Inst, Size, Data.slice(Index), Index,
+ nulls());
+ };
- MCDisassembler::DecodeStatus S;
- if (STI.getTargetTriple().getArch() == Triple::hexagon)
- S = DisAsm.getInstructionBundle(Inst, Size, Data.slice(Index), Index,
- nulls());
- else
- S = DisAsm.getInstruction(Inst, Size, Data.slice(Index), Index, nulls());
+ MCInst Inst;
+ MCDisassembler::DecodeStatus S = getInstruction(Inst);
switch (S) {
case MCDisassembler::Fail:
SM.PrintMessage(SMLoc::getFromPointer(Bytes.second[Index]),
@@ -74,12 +77,24 @@ static bool PrintInsts(const MCDisassembler &DisAsm, const ByteArrayTy &Bytes,
Streamer.emitInstruction(Inst, STI);
break;
}
+
+ if (S == MCDisassembler::Success && BenchmarkNumRuns != 0) {
+ // Benchmark mode, collect timing for decoding the instruction several
+ // times.
+ MCInst BMInst;
+ TimeTraceScope timeScope("getInstruction");
+ for (unsigned _ : llvm::seq<unsigned>(BenchmarkNumRuns)) {
+ BMInst.clear();
+ BMInst.setOpcode(0);
+ S = getInstruction(BMInst);
+ }
+ }
}
return false;
}
-static bool SkipToToken(StringRef &Str) {
+static bool skipToToken(StringRef &Str) {
for (;;) {
if (Str.empty())
return false;
@@ -101,7 +116,7 @@ static bool SkipToToken(StringRef &Str) {
static bool byteArrayFromString(ByteArrayTy &ByteArray, StringRef &Str,
SourceMgr &SM, bool HexBytes) {
- while (SkipToToken(Str)) {
+ while (skipToToken(Str)) {
// Handled by higher level
if (Str[0] == '[' || Str[0] == ']')
return false;
@@ -151,7 +166,7 @@ int Disassembler::disassemble(const Target &T, const std::string &Triple,
MCSubtargetInfo &STI, MCStreamer &Streamer,
MemoryBuffer &Buffer, SourceMgr &SM,
MCContext &Ctx, const MCTargetOptions &MCOptions,
- bool HexBytes) {
+ bool HexBytes, unsigned BenchmarkNumRuns) {
std::unique_ptr<const MCRegisterInfo> MRI(T.createMCRegInfo(Triple));
if (!MRI) {
errs() << "error: no register info for target " << Triple << "\n";
@@ -179,7 +194,7 @@ int Disassembler::disassemble(const Target &T, const std::string &Triple,
StringRef Str = Buffer.getBuffer();
bool InAtomicBlock = false;
- while (SkipToToken(Str)) {
+ while (skipToToken(Str)) {
ByteArray.first.clear();
ByteArray.second.clear();
@@ -207,8 +222,8 @@ int Disassembler::disassemble(const Target &T, const std::string &Triple,
ErrorOccurred |= byteArrayFromString(ByteArray, Str, SM, HexBytes);
if (!ByteArray.first.empty())
- ErrorOccurred |=
- PrintInsts(*DisAsm, ByteArray, SM, Streamer, InAtomicBlock, STI);
+ ErrorOccurred |= printInsts(*DisAsm, ByteArray, SM, Streamer,
+ InAtomicBlock, STI, BenchmarkNumRuns);
}
if (InAtomicBlock) {
diff --git a/llvm/tools/llvm-mc/Disassembler.h b/llvm/tools/llvm-mc/Disassembler.h
index 5efffca1e9926..334b72af8b522 100644
--- a/llvm/tools/llvm-mc/Disassembler.h
+++ b/llvm/tools/llvm-mc/Disassembler.h
@@ -32,7 +32,8 @@ class Disassembler {
static int disassemble(const Target &T, const std::string &Triple,
MCSubtargetInfo &STI, MCStreamer &Streamer,
MemoryBuffer &Buffer, SourceMgr &SM, MCContext &Ctx,
- const MCTargetOptions &MCOptions, bool HexBytes);
+ const MCTargetOptions &MCOptions, bool HexBytes,
+ unsigned BenchmarkNumRuns);
};
} // namespace llvm
diff --git a/llvm/tools/llvm-mc/llvm-mc.cpp b/llvm/tools/llvm-mc/llvm-mc.cpp
index da89af71bbbe8..4f3ff1569c158 100644
--- a/llvm/tools/llvm-mc/llvm-mc.cpp
+++ b/llvm/tools/llvm-mc/llvm-mc.cpp
@@ -12,6 +12,7 @@
//===----------------------------------------------------------------------===//
#include "Disassembler.h"
+#include "llvm/ADT/ScopeExit.h"
#include "llvm/DWARFCFIChecker/DWARFCFIFunctionFrameAnalyzer.h"
#include "llvm/DWARFCFIChecker/DWARFCFIFunctionFrameStreamer.h"
#include "llvm/MC/MCAsmBackend.h"
@@ -37,6 +38,7 @@
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/SourceMgr.h"
#include "llvm/Support/TargetSelect.h"
+#include "llvm/Support/TimeProfiler.h"
#include "llvm/Support/ToolOutputFile.h"
#include "llvm/Support/WithColor.h"
#include "llvm/TargetParser/Host.h"
@@ -240,6 +242,24 @@ static cl::opt<ActionType> Action(
"Colored disassembly of strings of hex bytes")),
cl::cat(MCCategory));
+static cl::opt<unsigned>
+ BenchmarkNumRuns("benchmark-num-runs",
+ cl::desc("Number of runs for decoder benchmarking"),
+ cl::cat(MCCategory));
+
+static cl::opt<bool> TimeTrace("time-trace", cl::desc("Record time trace"));
+
+static cl::opt<unsigned> TimeTraceGranularity(
+ "time-trace-granularity",
+ cl::desc(
+ "Minimum time granularity (in microseconds) traced by time profiler"),
+ cl::init(500), cl::Hidden);
+
+static cl::opt<std::string>
+ TimeTraceFile("time-trace-file",
+ cl::desc("Specify time trace file destination"),
+ cl::value_desc("filename"));
+
static const Target *GetTarget(const char *ProgName) {
// Figure out the target triple.
if (TripleName.empty())
@@ -371,6 +391,22 @@ int main(int argc, char **argv) {
cl::HideUnrelatedOptions({&MCCategory, &getColorCategory()});
cl::ParseCommandLineOptions(argc, argv, "llvm machine code playground\n");
+
+ if (TimeTrace)
+ timeTraceProfilerInitialize(TimeTraceGranularity, argv[0]);
+
+ auto TimeTraceScopeExit = make_scope_exit([]() {
+ if (!TimeTrace)
+ return;
+ if (auto E = timeTraceProfilerWrite(TimeTraceFile, OutputFilename)) {
+ handleAllErrors(std::move(E), [&](const StringError &SE) {
+ errs() << SE.getMessage() << "\n";
+ });
+ return;
+ }
+ timeTraceProfilerCleanup();
+ });
+
MCTargetOptions MCOptions = mc::InitMCTargetOptionsFromFlags();
MCOptions.CompressDebugSections = CompressDebugSections.getValue();
MCOptions.ShowMCInst = ShowInst;
@@ -603,7 +639,7 @@ int main(int argc, char **argv) {
}
int Res = 1;
- bool disassemble = false;
+ bool Disassemble = false;
switch (Action) {
case AC_AsLex:
Res = AsLexInput(SrcMgr, *MAI, Out->os());
@@ -615,12 +651,13 @@ int main(int argc, char **argv) {
case AC_MDisassemble:
case AC_CDisassemble:
case AC_Disassemble:
- disassemble = true;
+ Disassemble = true;
break;
}
- if (disassemble)
+ if (Disassemble)
Res = Disassembler::disassemble(*TheTarget, TripleName, *STI, *Str, *Buffer,
- SrcMgr, Ctx, MCOptions, HexBytes);
+ SrcMgr, Ctx, MCOptions, HexBytes,
+ BenchmarkNumRuns);
// Keep output if no errors.
if (Res == 0) {
@@ -628,5 +665,6 @@ int main(int argc, char **argv) {
if (DwoOut)
DwoOut->keep();
}
+
return Res;
}
More information about the llvm-commits
mailing list