Skip to content

Commit 4f39139

Browse files
authored
[llvm-mc] Add --runs option for benchmarking (#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 `runs` to run the decoder several times on each instruction.
1 parent e027b92 commit 4f39139

File tree

4 files changed

+82
-16
lines changed

4 files changed

+82
-16
lines changed
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
# REQUIRES: aarch64-registered-target
2+
# RUN: rm -rf %t.json
3+
# RUN: llvm-mc -triple=aarch64 -disassemble -o /dev/null %s -runs=1000 -time-trace -time-trace-file=%t.json
4+
# RUN: FileCheck --input-file %t.json %s
5+
6+
# Note: Test input taken from llvm/test/MC/Disassembler/AArch64/udf.txt
7+
8+
# CHECK: "name":"Total getInstruction"
9+
# CHECK: "args":{"count":3,"avg ms":{{.*}}}
10+
[0x00,0x00,0x00,0x00]
11+
[0x01,0x02,0x00,0x00]
12+
[0xff,0xff,0x00,0x00]

llvm/tools/llvm-mc/Disassembler.cpp

Lines changed: 32 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
#include "llvm/MC/TargetRegistry.h"
2525
#include "llvm/Support/MemoryBuffer.h"
2626
#include "llvm/Support/SourceMgr.h"
27+
#include "llvm/Support/TimeProfiler.h"
2728
#include "llvm/Support/raw_ostream.h"
2829
#include "llvm/TargetParser/Triple.h"
2930

@@ -32,24 +33,29 @@ using namespace llvm;
3233
typedef std::pair<std::vector<unsigned char>, std::vector<const char *>>
3334
ByteArrayTy;
3435

35-
static bool PrintInsts(const MCDisassembler &DisAsm, const ByteArrayTy &Bytes,
36+
static MCDisassembler::DecodeStatus getInstruction(const MCDisassembler &DisAsm,
37+
const MCSubtargetInfo &STI,
38+
MCInst &Inst, uint64_t &Size,
39+
ArrayRef<uint8_t> Bytes,
40+
uint64_t Address) {
41+
if (STI.getTargetTriple().getArch() == Triple::hexagon)
42+
return DisAsm.getInstructionBundle(Inst, Size, Bytes, Address, nulls());
43+
return DisAsm.getInstruction(Inst, Size, Bytes, Address, nulls());
44+
}
45+
46+
static bool printInsts(const MCDisassembler &DisAsm, const ByteArrayTy &Bytes,
3647
SourceMgr &SM, MCStreamer &Streamer, bool InAtomicBlock,
37-
const MCSubtargetInfo &STI) {
48+
const MCSubtargetInfo &STI, unsigned NumBenchmarkRuns) {
3849
ArrayRef<uint8_t> Data(Bytes.first);
3950

4051
// Disassemble it to strings.
4152
uint64_t Size;
42-
uint64_t Index;
4353

44-
for (Index = 0; Index < Bytes.first.size(); Index += Size) {
45-
MCInst Inst;
54+
for (uint64_t Index = 0; Index < Bytes.first.size(); Index += Size) {
4655

47-
MCDisassembler::DecodeStatus S;
48-
if (STI.getTargetTriple().getArch() == Triple::hexagon)
49-
S = DisAsm.getInstructionBundle(Inst, Size, Data.slice(Index), Index,
50-
nulls());
51-
else
52-
S = DisAsm.getInstruction(Inst, Size, Data.slice(Index), Index, nulls());
56+
MCInst Inst;
57+
MCDisassembler::DecodeStatus S =
58+
getInstruction(DisAsm, STI, Inst, Size, Data.slice(Index), Index);
5359
switch (S) {
5460
case MCDisassembler::Fail:
5561
SM.PrintMessage(SMLoc::getFromPointer(Bytes.second[Index]),
@@ -74,6 +80,18 @@ static bool PrintInsts(const MCDisassembler &DisAsm, const ByteArrayTy &Bytes,
7480
Streamer.emitInstruction(Inst, STI);
7581
break;
7682
}
83+
84+
if (S == MCDisassembler::Success && NumBenchmarkRuns != 0) {
85+
// Benchmark mode, collect timing for decoding the instruction several
86+
// times.
87+
MCInst BMInst;
88+
TimeTraceScope timeScope("getInstruction");
89+
for (unsigned I = 0; I < NumBenchmarkRuns; ++I) {
90+
BMInst.clear();
91+
BMInst.setOpcode(0);
92+
S = getInstruction(DisAsm, STI, BMInst, Size, Data.slice(Index), Index);
93+
}
94+
}
7795
}
7896

7997
return false;
@@ -151,7 +169,7 @@ int Disassembler::disassemble(const Target &T, const std::string &Triple,
151169
MCSubtargetInfo &STI, MCStreamer &Streamer,
152170
MemoryBuffer &Buffer, SourceMgr &SM,
153171
MCContext &Ctx, const MCTargetOptions &MCOptions,
154-
bool HexBytes) {
172+
bool HexBytes, unsigned NumBenchmarkRuns) {
155173
std::unique_ptr<const MCRegisterInfo> MRI(T.createMCRegInfo(Triple));
156174
if (!MRI) {
157175
errs() << "error: no register info for target " << Triple << "\n";
@@ -207,8 +225,8 @@ int Disassembler::disassemble(const Target &T, const std::string &Triple,
207225
ErrorOccurred |= byteArrayFromString(ByteArray, Str, SM, HexBytes);
208226

209227
if (!ByteArray.first.empty())
210-
ErrorOccurred |=
211-
PrintInsts(*DisAsm, ByteArray, SM, Streamer, InAtomicBlock, STI);
228+
ErrorOccurred |= printInsts(*DisAsm, ByteArray, SM, Streamer,
229+
InAtomicBlock, STI, NumBenchmarkRuns);
212230
}
213231

214232
if (InAtomicBlock) {

llvm/tools/llvm-mc/Disassembler.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,8 @@ class Disassembler {
3232
static int disassemble(const Target &T, const std::string &Triple,
3333
MCSubtargetInfo &STI, MCStreamer &Streamer,
3434
MemoryBuffer &Buffer, SourceMgr &SM, MCContext &Ctx,
35-
const MCTargetOptions &MCOptions, bool HexBytes);
35+
const MCTargetOptions &MCOptions, bool HexBytes,
36+
unsigned NumBenchmarkRuns);
3637
};
3738

3839
} // namespace llvm

llvm/tools/llvm-mc/llvm-mc.cpp

Lines changed: 36 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
//===----------------------------------------------------------------------===//
1313

1414
#include "Disassembler.h"
15+
#include "llvm/ADT/ScopeExit.h"
1516
#include "llvm/DWARFCFIChecker/DWARFCFIFunctionFrameAnalyzer.h"
1617
#include "llvm/DWARFCFIChecker/DWARFCFIFunctionFrameStreamer.h"
1718
#include "llvm/MC/MCAsmBackend.h"
@@ -37,6 +38,7 @@
3738
#include "llvm/Support/MemoryBuffer.h"
3839
#include "llvm/Support/SourceMgr.h"
3940
#include "llvm/Support/TargetSelect.h"
41+
#include "llvm/Support/TimeProfiler.h"
4042
#include "llvm/Support/ToolOutputFile.h"
4143
#include "llvm/Support/WithColor.h"
4244
#include "llvm/TargetParser/Host.h"
@@ -240,6 +242,23 @@ static cl::opt<ActionType> Action(
240242
"Colored disassembly of strings of hex bytes")),
241243
cl::cat(MCCategory));
242244

245+
static cl::opt<unsigned>
246+
NumBenchmarkRuns("runs", cl::desc("Number of runs for benchmarking"),
247+
cl::cat(MCCategory));
248+
249+
static cl::opt<bool> TimeTrace("time-trace", cl::desc("Record time trace"));
250+
251+
static cl::opt<unsigned> TimeTraceGranularity(
252+
"time-trace-granularity",
253+
cl::desc(
254+
"Minimum time granularity (in microseconds) traced by time profiler"),
255+
cl::init(500), cl::Hidden);
256+
257+
static cl::opt<std::string>
258+
TimeTraceFile("time-trace-file",
259+
cl::desc("Specify time trace file destination"),
260+
cl::value_desc("filename"));
261+
243262
static const Target *GetTarget(const char *ProgName) {
244263
// Figure out the target triple.
245264
if (TripleName.empty())
@@ -371,6 +390,20 @@ int main(int argc, char **argv) {
371390

372391
cl::HideUnrelatedOptions({&MCCategory, &getColorCategory()});
373392
cl::ParseCommandLineOptions(argc, argv, "llvm machine code playground\n");
393+
394+
if (TimeTrace)
395+
timeTraceProfilerInitialize(TimeTraceGranularity, argv[0]);
396+
397+
auto TimeTraceScopeExit = make_scope_exit([]() {
398+
if (!TimeTrace)
399+
return;
400+
if (auto E = timeTraceProfilerWrite(TimeTraceFile, OutputFilename)) {
401+
logAllUnhandledErrors(std::move(E), errs());
402+
return;
403+
}
404+
timeTraceProfilerCleanup();
405+
});
406+
374407
MCTargetOptions MCOptions = mc::InitMCTargetOptionsFromFlags();
375408
MCOptions.CompressDebugSections = CompressDebugSections.getValue();
376409
MCOptions.ShowMCInst = ShowInst;
@@ -620,13 +653,15 @@ int main(int argc, char **argv) {
620653
}
621654
if (disassemble)
622655
Res = Disassembler::disassemble(*TheTarget, TripleName, *STI, *Str, *Buffer,
623-
SrcMgr, Ctx, MCOptions, HexBytes);
656+
SrcMgr, Ctx, MCOptions, HexBytes,
657+
NumBenchmarkRuns);
624658

625659
// Keep output if no errors.
626660
if (Res == 0) {
627661
Out->keep();
628662
if (DwoOut)
629663
DwoOut->keep();
630664
}
665+
631666
return Res;
632667
}

0 commit comments

Comments
 (0)