Skip to content

Commit f8f8598

Browse files
authored
[Exegesis] Add the ability to dry-run the measurement phase (#121991)
With the new benchmark phase, `dry-run-measurement`, llvm-exegesis can run everything except the actual snippet execution. It is useful when we want to test some parts of the code between the `assemble-measured-code` and `measure` phase without actually running on native platforms.
1 parent c87ef14 commit f8f8598

File tree

6 files changed

+46
-13
lines changed

6 files changed

+46
-13
lines changed

llvm/docs/CommandGuide/llvm-exegesis.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -301,6 +301,7 @@ OPTIONS
301301
* ``prepare-and-assemble-snippet``: Same as ``prepare-snippet``, but also dumps an excerpt of the sequence (hex encoded).
302302
* ``assemble-measured-code``: Same as ``prepare-and-assemble-snippet``. but also creates the full sequence that can be dumped to a file using ``--dump-object-to-disk``.
303303
* ``measure``: Same as ``assemble-measured-code``, but also runs the measurement.
304+
* ``dry-run-measurement``: Same as measure, but does not actually execute the snippet.
304305

305306
.. option:: --x86-lbr-sample-period=<nBranches/sample>
306307

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
# RUN: llvm-exegesis --mtriple=riscv64 --mcpu=sifive-p470 --mode=latency --opcode-name=ADD --use-dummy-perf-counters --benchmark-phase=dry-run-measurement | FileCheck %s
2+
# REQUIRES: riscv-registered-target
3+
4+
# This test makes sure that llvm-exegesis doesn't execute "cross-compiled" snippets in the presence of
5+
# --dry-run-measurement. RISC-V was chosen simply because most of the time we run tests on X86 machines.
6+
7+
# Should not contain misleading results.
8+
# CHECK: measurements: []
9+
10+
# Should not contain error messages like "snippet crashed while running: Segmentation fault".
11+
# CHECK: error: ''

llvm/tools/llvm-exegesis/lib/BenchmarkResult.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ enum class BenchmarkPhaseSelectorE {
3838
PrepareAndAssembleSnippet,
3939
AssembleMeasuredCode,
4040
Measure,
41+
DryRunMeasure,
4142
};
4243

4344
enum class BenchmarkFilter { All, RegOnly, WithMem };

llvm/tools/llvm-exegesis/lib/BenchmarkRunner.cpp

Lines changed: 25 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -99,22 +99,25 @@ class InProcessFunctionExecutorImpl : public BenchmarkRunner::FunctionExecutor {
9999
static Expected<std::unique_ptr<InProcessFunctionExecutorImpl>>
100100
create(const LLVMState &State, object::OwningBinary<object::ObjectFile> Obj,
101101
BenchmarkRunner::ScratchSpace *Scratch,
102-
std::optional<int> BenchmarkProcessCPU) {
102+
std::optional<int> BenchmarkProcessCPU, bool DryRun) {
103103
Expected<ExecutableFunction> EF =
104104
ExecutableFunction::create(State.createTargetMachine(), std::move(Obj));
105105

106106
if (!EF)
107107
return EF.takeError();
108108

109109
return std::unique_ptr<InProcessFunctionExecutorImpl>(
110-
new InProcessFunctionExecutorImpl(State, std::move(*EF), Scratch));
110+
new InProcessFunctionExecutorImpl(State, std::move(*EF), Scratch,
111+
DryRun));
111112
}
112113

113114
private:
114115
InProcessFunctionExecutorImpl(const LLVMState &State,
115116
ExecutableFunction Function,
116-
BenchmarkRunner::ScratchSpace *Scratch)
117-
: State(State), Function(std::move(Function)), Scratch(Scratch) {}
117+
BenchmarkRunner::ScratchSpace *Scratch,
118+
bool DryRun)
119+
: State(State), Function(std::move(Function)), Scratch(Scratch),
120+
DryRun(DryRun) {}
118121

119122
static void accumulateCounterValues(const SmallVector<int64_t, 4> &NewValues,
120123
SmallVector<int64_t, 4> *Result) {
@@ -143,9 +146,14 @@ class InProcessFunctionExecutorImpl : public BenchmarkRunner::FunctionExecutor {
143146
CrashRecoveryContext CRC;
144147
CrashRecoveryContext::Enable();
145148
const bool Crashed = !CRC.RunSafely([this, Counter, ScratchPtr]() {
146-
Counter->start();
147-
this->Function(ScratchPtr);
148-
Counter->stop();
149+
if (DryRun) {
150+
Counter->start();
151+
Counter->stop();
152+
} else {
153+
Counter->start();
154+
this->Function(ScratchPtr);
155+
Counter->stop();
156+
}
149157
});
150158
CrashRecoveryContext::Disable();
151159
PS.reset();
@@ -177,6 +185,7 @@ class InProcessFunctionExecutorImpl : public BenchmarkRunner::FunctionExecutor {
177185
const LLVMState &State;
178186
const ExecutableFunction Function;
179187
BenchmarkRunner::ScratchSpace *const Scratch;
188+
bool DryRun = false;
180189
};
181190

182191
#ifdef __linux__
@@ -664,21 +673,29 @@ Expected<std::unique_ptr<BenchmarkRunner::FunctionExecutor>>
664673
BenchmarkRunner::createFunctionExecutor(
665674
object::OwningBinary<object::ObjectFile> ObjectFile,
666675
const BenchmarkKey &Key, std::optional<int> BenchmarkProcessCPU) const {
676+
bool DryRun =
677+
BenchmarkPhaseSelector == BenchmarkPhaseSelectorE::DryRunMeasure;
678+
667679
switch (ExecutionMode) {
668680
case ExecutionModeE::InProcess: {
669681
if (BenchmarkProcessCPU.has_value())
670682
return make_error<Failure>("The inprocess execution mode does not "
671683
"support benchmark core pinning.");
672684

673685
auto InProcessExecutorOrErr = InProcessFunctionExecutorImpl::create(
674-
State, std::move(ObjectFile), Scratch.get(), BenchmarkProcessCPU);
686+
State, std::move(ObjectFile), Scratch.get(), BenchmarkProcessCPU,
687+
DryRun);
675688
if (!InProcessExecutorOrErr)
676689
return InProcessExecutorOrErr.takeError();
677690

678691
return std::move(*InProcessExecutorOrErr);
679692
}
680693
case ExecutionModeE::SubProcess: {
681694
#ifdef __linux__
695+
if (DryRun)
696+
return make_error<Failure>("The subprocess execution mode cannot "
697+
"dry-run measurement at this moment.");
698+
682699
auto SubProcessExecutorOrErr = SubProcessFunctionExecutorImpl::create(
683700
State, std::move(ObjectFile), Key, BenchmarkProcessCPU);
684701
if (!SubProcessExecutorOrErr)

llvm/tools/llvm-exegesis/lib/Target.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,7 @@ ExegesisTarget::createBenchmarkRunner(
9898
return nullptr;
9999
case Benchmark::Latency:
100100
case Benchmark::InverseThroughput:
101-
if (BenchmarkPhaseSelector == BenchmarkPhaseSelectorE::Measure &&
101+
if (BenchmarkPhaseSelector >= BenchmarkPhaseSelectorE::Measure &&
102102
!PfmCounters.CycleCounter) {
103103
const char *ModeName = Mode == Benchmark::Latency
104104
? "latency"
@@ -116,7 +116,7 @@ ExegesisTarget::createBenchmarkRunner(
116116
State, Mode, BenchmarkPhaseSelector, ResultAggMode, ExecutionMode,
117117
ValidationCounters, BenchmarkRepeatCount);
118118
case Benchmark::Uops:
119-
if (BenchmarkPhaseSelector == BenchmarkPhaseSelectorE::Measure &&
119+
if (BenchmarkPhaseSelector >= BenchmarkPhaseSelectorE::Measure &&
120120
!PfmCounters.UopsCounter && !PfmCounters.IssueCounters)
121121
return make_error<Failure>(
122122
"can't run 'uops' mode, sched model does not define uops or issue "

llvm/tools/llvm-exegesis/llvm-exegesis.cpp

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -132,7 +132,10 @@ static cl::opt<BenchmarkPhaseSelectorE> BenchmarkPhaseSelector(
132132
clEnumValN(
133133
BenchmarkPhaseSelectorE::Measure, "measure",
134134
"Same as prepare-measured-code, but also runs the measurement "
135-
"(default)")),
135+
"(default)"),
136+
clEnumValN(
137+
BenchmarkPhaseSelectorE::DryRunMeasure, "dry-run-measurement",
138+
"Same as measure, but does not actually execute the snippet")),
136139
cl::init(BenchmarkPhaseSelectorE::Measure));
137140

138141
static cl::opt<bool>
@@ -476,7 +479,7 @@ static void runBenchmarkConfigurations(
476479
}
477480

478481
void benchmarkMain() {
479-
if (BenchmarkPhaseSelector == BenchmarkPhaseSelectorE::Measure &&
482+
if (BenchmarkPhaseSelector >= BenchmarkPhaseSelectorE::Measure &&
480483
!UseDummyPerfCounters) {
481484
#ifndef HAVE_LIBPFM
482485
ExitWithError(
@@ -501,7 +504,7 @@ void benchmarkMain() {
501504

502505
// Preliminary check to ensure features needed for requested
503506
// benchmark mode are present on target CPU and/or OS.
504-
if (BenchmarkPhaseSelector == BenchmarkPhaseSelectorE::Measure)
507+
if (BenchmarkPhaseSelector >= BenchmarkPhaseSelectorE::Measure)
505508
ExitOnErr(State.getExegesisTarget().checkFeatureSupport());
506509

507510
if (ExecutionMode == BenchmarkRunner::ExecutionModeE::SubProcess &&

0 commit comments

Comments
 (0)