[llvm] r344695 - [llvm-exegesis] Allow measuring several instructions in a single run.
Clement Courbet via llvm-commits
llvm-commits at lists.llvm.org
Wed Oct 17 08:04:15 PDT 2018
Author: courbet
Date: Wed Oct 17 08:04:15 2018
New Revision: 344695
URL: http://llvm.org/viewvc/llvm-project?rev=344695&view=rev
Log:
[llvm-exegesis] Allow measuring several instructions in a single run.
Summary:
We try to recover gracefully on instructions that would crash the
program.
This includes some refactoring of runMeasurement() implementations.
Reviewers: gchatelet
Subscribers: tschuett, llvm-commits
Differential Revision: https://reviews.llvm.org/D53371
Modified:
llvm/trunk/docs/CommandGuide/llvm-exegesis.rst
llvm/trunk/tools/llvm-exegesis/lib/BenchmarkRunner.cpp
llvm/trunk/tools/llvm-exegesis/lib/BenchmarkRunner.h
llvm/trunk/tools/llvm-exegesis/lib/Latency.cpp
llvm/trunk/tools/llvm-exegesis/lib/Latency.h
llvm/trunk/tools/llvm-exegesis/lib/Uops.cpp
llvm/trunk/tools/llvm-exegesis/lib/Uops.h
llvm/trunk/tools/llvm-exegesis/llvm-exegesis.cpp
Modified: llvm/trunk/docs/CommandGuide/llvm-exegesis.rst
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/docs/CommandGuide/llvm-exegesis.rst?rev=344695&r1=344694&r2=344695&view=diff
==============================================================================
--- llvm/trunk/docs/CommandGuide/llvm-exegesis.rst (original)
+++ llvm/trunk/docs/CommandGuide/llvm-exegesis.rst Wed Oct 17 08:04:15 2018
@@ -175,9 +175,10 @@ OPTIONS
Specify the opcode to measure, by index. See example 1 for details.
Either `opcode-index`, `opcode-name` or `snippets-file` must be set.
-.. option:: -opcode-name=<LLVM opcode name>
+.. option:: -opcode-name=<opcode name 1>,<opcode name 2>,...
- Specify the opcode to measure, by name. See example 1 for details.
+ Specify the opcode to measure, by name. Several opcodes can be specified as
+ a comma-separated list. See example 1 for details.
Either `opcode-index`, `opcode-name` or `snippets-file` must be set.
.. option:: -snippets-file=<filename>
Modified: llvm/trunk/tools/llvm-exegesis/lib/BenchmarkRunner.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-exegesis/lib/BenchmarkRunner.cpp?rev=344695&r1=344694&r2=344695&view=diff
==============================================================================
--- llvm/trunk/tools/llvm-exegesis/lib/BenchmarkRunner.cpp (original)
+++ llvm/trunk/tools/llvm-exegesis/lib/BenchmarkRunner.cpp Wed Oct 17 08:04:15 2018
@@ -13,9 +13,11 @@
#include "Assembler.h"
#include "BenchmarkRunner.h"
#include "MCInstrDescView.h"
+#include "PerfHelper.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/Twine.h"
+#include "llvm/Support/CrashRecoveryContext.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/Program.h"
@@ -43,6 +45,54 @@ GenerateInstructions(const BenchmarkCode
return Code;
}
+namespace {
+class FunctionExecutorImpl : public BenchmarkRunner::FunctionExecutor {
+public:
+ FunctionExecutorImpl(const LLVMState &State,
+ llvm::object::OwningBinary<llvm::object::ObjectFile> Obj,
+ BenchmarkRunner::ScratchSpace *Scratch)
+ : Function(State.createTargetMachine(), std::move(Obj)),
+ Scratch(Scratch) {}
+
+private:
+ llvm::Expected<int64_t> runAndMeasure(const char *Counters) const override {
+ // We sum counts when there are several counters for a single ProcRes
+ // (e.g. P23 on SandyBridge).
+ int64_t CounterValue = 0;
+ llvm::SmallVector<llvm::StringRef, 2> CounterNames;
+ llvm::StringRef(Counters).split(CounterNames, ',');
+ char *const ScratchPtr = Scratch->ptr();
+ for (const auto &CounterName : CounterNames) {
+ pfm::PerfEvent PerfEvent(CounterName);
+ if (!PerfEvent.valid())
+ llvm::report_fatal_error(
+ llvm::Twine("invalid perf event ").concat(Counters));
+ pfm::Counter Counter(PerfEvent);
+ Scratch->clear();
+ {
+ llvm::CrashRecoveryContext CRC;
+ llvm::CrashRecoveryContext::Enable();
+ const bool Crashed = !CRC.RunSafely([this, &Counter, ScratchPtr]() {
+ Counter.start();
+ Function(ScratchPtr);
+ Counter.stop();
+ });
+ llvm::CrashRecoveryContext::Disable();
+ // FIXME: Better diagnosis.
+ if (Crashed)
+ return llvm::make_error<BenchmarkFailure>(
+ "snippet crashed while running");
+ }
+ CounterValue += Counter.read();
+ }
+ return CounterValue;
+ }
+
+ const ExecutableFunction Function;
+ BenchmarkRunner::ScratchSpace *const Scratch;
+};
+} // namespace
+
InstructionBenchmark
BenchmarkRunner::runConfiguration(const BenchmarkCode &BC,
unsigned NumRepetitions) const {
@@ -86,16 +136,21 @@ BenchmarkRunner::runConfiguration(const
}
llvm::outs() << "Check generated assembly with: /usr/bin/objdump -d "
<< *ObjectFilePath << "\n";
- const ExecutableFunction EF(State.createTargetMachine(),
- getObjectFromFile(*ObjectFilePath));
- InstrBenchmark.Measurements = runMeasurements(EF, *Scratch);
+ const FunctionExecutorImpl Executor(State, getObjectFromFile(*ObjectFilePath),
+ Scratch.get());
+ auto Measurements = runMeasurements(Executor);
+ if (llvm::Error E = Measurements.takeError()) {
+ InstrBenchmark.Error = llvm::toString(std::move(E));
+ return InstrBenchmark;
+ }
+ InstrBenchmark.Measurements = std::move(*Measurements);
assert(InstrBenchmark.NumRepetitions > 0 && "invalid NumRepetitions");
for (BenchmarkMeasure &BM : InstrBenchmark.Measurements) {
// Scale the measurements by instruction.
BM.PerInstructionValue /= InstrBenchmark.NumRepetitions;
// Scale the measurements by snippet.
BM.PerSnippetValue *= static_cast<double>(BC.Instructions.size()) /
- InstrBenchmark.NumRepetitions;
+ InstrBenchmark.NumRepetitions;
}
return InstrBenchmark;
@@ -115,4 +170,6 @@ BenchmarkRunner::writeObjectFile(const B
return ResultPath.str();
}
+BenchmarkRunner::FunctionExecutor::~FunctionExecutor() {}
+
} // namespace exegesis
Modified: llvm/trunk/tools/llvm-exegesis/lib/BenchmarkRunner.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-exegesis/lib/BenchmarkRunner.h?rev=344695&r1=344694&r2=344695&view=diff
==============================================================================
--- llvm/trunk/tools/llvm-exegesis/lib/BenchmarkRunner.h (original)
+++ llvm/trunk/tools/llvm-exegesis/lib/BenchmarkRunner.h Wed Oct 17 08:04:15 2018
@@ -64,13 +64,21 @@ public:
char *const AlignedPtr;
};
+ // A helper to measure counters while executing a function in a sandboxed
+ // context.
+ class FunctionExecutor {
+ public:
+ ~FunctionExecutor();
+ virtual llvm::Expected<int64_t>
+ runAndMeasure(const char *Counters) const = 0;
+ };
+
protected:
const LLVMState &State;
private:
- virtual std::vector<BenchmarkMeasure>
- runMeasurements(const ExecutableFunction &EF,
- ScratchSpace &Scratch) const = 0;
+ virtual llvm::Expected<std::vector<BenchmarkMeasure>>
+ runMeasurements(const FunctionExecutor &Executor) const = 0;
llvm::Expected<std::string>
writeObjectFile(const BenchmarkCode &Configuration,
Modified: llvm/trunk/tools/llvm-exegesis/lib/Latency.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-exegesis/lib/Latency.cpp?rev=344695&r1=344694&r2=344695&view=diff
==============================================================================
--- llvm/trunk/tools/llvm-exegesis/lib/Latency.cpp (original)
+++ llvm/trunk/tools/llvm-exegesis/lib/Latency.cpp Wed Oct 17 08:04:15 2018
@@ -12,7 +12,6 @@
#include "Assembler.h"
#include "BenchmarkRunner.h"
#include "MCInstrDescView.h"
-#include "PerfHelper.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/MC/MCInst.h"
#include "llvm/MC/MCInstBuilder.h"
@@ -178,30 +177,26 @@ const char *LatencyBenchmarkRunner::getC
LatencyBenchmarkRunner::~LatencyBenchmarkRunner() = default;
-std::vector<BenchmarkMeasure>
-LatencyBenchmarkRunner::runMeasurements(const ExecutableFunction &Function,
- ScratchSpace &Scratch) const {
+llvm::Expected<std::vector<BenchmarkMeasure>>
+LatencyBenchmarkRunner::runMeasurements(
+ const FunctionExecutor &Executor) const {
// Cycle measurements include some overhead from the kernel. Repeat the
// measure several times and take the minimum value.
constexpr const int NumMeasurements = 30;
- int64_t MinLatency = std::numeric_limits<int64_t>::max();
+ int64_t MinValue = std::numeric_limits<int64_t>::max();
const char *CounterName = getCounterName();
if (!CounterName)
llvm::report_fatal_error("could not determine cycle counter name");
- const pfm::PerfEvent CyclesPerfEvent(CounterName);
- if (!CyclesPerfEvent.valid())
- llvm::report_fatal_error("invalid perf event");
for (size_t I = 0; I < NumMeasurements; ++I) {
- pfm::Counter Counter(CyclesPerfEvent);
- Scratch.clear();
- Counter.start();
- Function(Scratch.ptr());
- Counter.stop();
- const int64_t Value = Counter.read();
- if (Value < MinLatency)
- MinLatency = Value;
- }
- return {BenchmarkMeasure::Create("latency", MinLatency)};
+ auto ExpectedCounterValue = Executor.runAndMeasure(CounterName);
+ if (!ExpectedCounterValue)
+ return ExpectedCounterValue.takeError();
+ if (*ExpectedCounterValue < MinValue)
+ MinValue = *ExpectedCounterValue;
+ }
+ std::vector<BenchmarkMeasure> Result = {
+ BenchmarkMeasure::Create("latency", MinValue)};
+ return std::move(Result);
}
} // namespace exegesis
Modified: llvm/trunk/tools/llvm-exegesis/lib/Latency.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-exegesis/lib/Latency.h?rev=344695&r1=344694&r2=344695&view=diff
==============================================================================
--- llvm/trunk/tools/llvm-exegesis/lib/Latency.h (original)
+++ llvm/trunk/tools/llvm-exegesis/lib/Latency.h Wed Oct 17 08:04:15 2018
@@ -37,9 +37,8 @@ public:
~LatencyBenchmarkRunner() override;
private:
- std::vector<BenchmarkMeasure>
- runMeasurements(const ExecutableFunction &EF,
- ScratchSpace &Scratch) const override;
+ llvm::Expected<std::vector<BenchmarkMeasure>>
+ runMeasurements(const FunctionExecutor &Executor) const override;
virtual const char *getCounterName() const;
};
Modified: llvm/trunk/tools/llvm-exegesis/lib/Uops.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-exegesis/lib/Uops.cpp?rev=344695&r1=344694&r2=344695&view=diff
==============================================================================
--- llvm/trunk/tools/llvm-exegesis/lib/Uops.cpp (original)
+++ llvm/trunk/tools/llvm-exegesis/lib/Uops.cpp Wed Oct 17 08:04:15 2018
@@ -12,7 +12,6 @@
#include "Assembler.h"
#include "BenchmarkRunner.h"
#include "MCInstrDescView.h"
-#include "PerfHelper.h"
#include "Target.h"
// FIXME: Load constants into registers (e.g. with fld1) to not break
@@ -221,33 +220,10 @@ UopsSnippetGenerator::generateCodeTempla
return getSingleton(std::move(CT));
}
-std::vector<BenchmarkMeasure>
-UopsBenchmarkRunner::runMeasurements(const ExecutableFunction &Function,
- ScratchSpace &Scratch) const {
+llvm::Expected<std::vector<BenchmarkMeasure>>
+UopsBenchmarkRunner::runMeasurements(const FunctionExecutor &Executor) const {
const auto &SchedModel = State.getSubtargetInfo().getSchedModel();
- const auto RunMeasurement = [&Function,
- &Scratch](const char *const Counters) {
- // We sum counts when there are several counters for a single ProcRes
- // (e.g. P23 on SandyBridge).
- int64_t CounterValue = 0;
- llvm::SmallVector<llvm::StringRef, 2> CounterNames;
- llvm::StringRef(Counters).split(CounterNames, ',');
- for (const auto &CounterName : CounterNames) {
- pfm::PerfEvent UopPerfEvent(CounterName);
- if (!UopPerfEvent.valid())
- llvm::report_fatal_error(
- llvm::Twine("invalid perf event ").concat(Counters));
- pfm::Counter Counter(UopPerfEvent);
- Scratch.clear();
- Counter.start();
- Function(Scratch.ptr());
- Counter.stop();
- CounterValue += Counter.read();
- }
- return CounterValue;
- };
-
std::vector<BenchmarkMeasure> Result;
const auto &PfmCounters = SchedModel.getExtraProcessorInfo().PfmCounters;
// Uops per port.
@@ -256,16 +232,21 @@ UopsBenchmarkRunner::runMeasurements(con
const char *const Counters = PfmCounters.IssueCounters[ProcResIdx];
if (!Counters)
continue;
- const double CounterValue = RunMeasurement(Counters);
+ auto ExpectedCounterValue = Executor.runAndMeasure(Counters);
+ if (!ExpectedCounterValue)
+ return ExpectedCounterValue.takeError();
Result.push_back(BenchmarkMeasure::Create(
- SchedModel.getProcResource(ProcResIdx)->Name, CounterValue));
+ SchedModel.getProcResource(ProcResIdx)->Name, *ExpectedCounterValue));
}
// NumMicroOps.
if (const char *const UopsCounter = PfmCounters.UopsCounter) {
- const double CounterValue = RunMeasurement(UopsCounter);
- Result.push_back(BenchmarkMeasure::Create("NumMicroOps", CounterValue));
+ auto ExpectedCounterValue = Executor.runAndMeasure(UopsCounter);
+ if (!ExpectedCounterValue)
+ return ExpectedCounterValue.takeError();
+ Result.push_back(
+ BenchmarkMeasure::Create("NumMicroOps", *ExpectedCounterValue));
}
- return Result;
+ return std::move(Result);
}
constexpr const size_t UopsSnippetGenerator::kMinNumDifferentAddresses;
Modified: llvm/trunk/tools/llvm-exegesis/lib/Uops.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-exegesis/lib/Uops.h?rev=344695&r1=344694&r2=344695&view=diff
==============================================================================
--- llvm/trunk/tools/llvm-exegesis/lib/Uops.h (original)
+++ llvm/trunk/tools/llvm-exegesis/lib/Uops.h Wed Oct 17 08:04:15 2018
@@ -68,9 +68,8 @@ public:
static constexpr const size_t kMinNumDifferentAddresses = 6;
private:
- std::vector<BenchmarkMeasure>
- runMeasurements(const ExecutableFunction &EF,
- ScratchSpace &Scratch) const override;
+ llvm::Expected<std::vector<BenchmarkMeasure>>
+ runMeasurements(const FunctionExecutor &Executor) const override;
};
} // namespace exegesis
Modified: llvm/trunk/tools/llvm-exegesis/llvm-exegesis.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-exegesis/llvm-exegesis.cpp?rev=344695&r1=344694&r2=344695&view=diff
==============================================================================
--- llvm/trunk/tools/llvm-exegesis/llvm-exegesis.cpp (original)
+++ llvm/trunk/tools/llvm-exegesis/llvm-exegesis.cpp Wed Oct 17 08:04:15 2018
@@ -38,13 +38,14 @@
#include <algorithm>
#include <string>
-static llvm::cl::opt<unsigned>
+static llvm::cl::opt<int>
OpcodeIndex("opcode-index", llvm::cl::desc("opcode to measure, by index"),
llvm::cl::init(0));
-static llvm::cl::opt<std::string>
- OpcodeName("opcode-name", llvm::cl::desc("opcode to measure, by name"),
- llvm::cl::init(""));
+static llvm::cl::opt<std::string> OpcodeNames(
+ "opcode-name",
+ llvm::cl::desc("comma-separated list of opcodes to measure, by name"),
+ llvm::cl::init(""));
static llvm::cl::opt<std::string>
SnippetsFile("snippets-file", llvm::cl::desc("code snippets to measure"),
@@ -99,11 +100,12 @@ static llvm::ExitOnError ExitOnErr;
void LLVM_EXEGESIS_INITIALIZE_NATIVE_TARGET();
#endif
-// Checks that only one of OpcodeName, OpcodeIndex or SnippetsFile is provided,
-// and returns the opcode index or 0 if snippets should be read from
+// Checks that only one of OpcodeNames, OpcodeIndex or SnippetsFile is provided,
+// and returns the opcode indices or {} if snippets should be read from
// `SnippetsFile`.
-static unsigned getOpcodeOrDie(const llvm::MCInstrInfo &MCInstrInfo) {
- const size_t NumSetFlags = (OpcodeName.empty() ? 0 : 1) +
+static std::vector<unsigned>
+getOpcodesOrDie(const llvm::MCInstrInfo &MCInstrInfo) {
+ const size_t NumSetFlags = (OpcodeNames.empty() ? 0 : 1) +
(OpcodeIndex == 0 ? 0 : 1) +
(SnippetsFile.empty() ? 0 : 1);
if (NumSetFlags != 1)
@@ -111,14 +113,35 @@ static unsigned getOpcodeOrDie(const llv
"please provide one and only one of 'opcode-index', 'opcode-name' or "
"'snippets-file'");
if (!SnippetsFile.empty())
- return 0;
+ return {};
if (OpcodeIndex > 0)
- return OpcodeIndex;
+ return {static_cast<unsigned>(OpcodeIndex)};
+ if (OpcodeIndex < 0) {
+ std::vector<unsigned> Result;
+ for (unsigned I = 1, E = MCInstrInfo.getNumOpcodes(); I <= E; ++I)
+ Result.push_back(I);
+ return Result;
+ }
// Resolve opcode name -> opcode.
- for (unsigned I = 0, E = MCInstrInfo.getNumOpcodes(); I < E; ++I)
- if (MCInstrInfo.getName(I) == OpcodeName)
- return I;
- llvm::report_fatal_error(llvm::Twine("unknown opcode ").concat(OpcodeName));
+ const auto ResolveName =
+ [&MCInstrInfo](llvm::StringRef OpcodeName) -> unsigned {
+ for (unsigned I = 1, E = MCInstrInfo.getNumOpcodes(); I < E; ++I)
+ if (MCInstrInfo.getName(I) == OpcodeName)
+ return I;
+ return 0u;
+ };
+ llvm::SmallVector<llvm::StringRef, 2> Pieces;
+ llvm::StringRef(OpcodeNames.getValue())
+ .split(Pieces, ",", /* MaxSplit */ -1, /* KeepEmpty */ false);
+ std::vector<unsigned> Result;
+ for (const llvm::StringRef OpcodeName : Pieces) {
+ if (unsigned Opcode = ResolveName(OpcodeName))
+ Result.push_back(Opcode);
+ else
+ llvm::report_fatal_error(
+ llvm::Twine("unknown opcode ").concat(OpcodeName));
+ }
+ return Result;
}
// Generates code snippets for opcode `Opcode`.
@@ -299,18 +322,29 @@ void benchmarkMain() {
#endif
const LLVMState State;
- const auto Opcode = getOpcodeOrDie(State.getInstrInfo());
+ const auto Opcodes = getOpcodesOrDie(State.getInstrInfo());
std::vector<BenchmarkCode> Configurations;
- if (Opcode > 0) {
- // Ignore instructions without a sched class if -ignore-invalid-sched-class
- // is passed.
- if (IgnoreInvalidSchedClass &&
- State.getInstrInfo().get(Opcode).getSchedClass() == 0) {
- llvm::errs() << "ignoring instruction without sched class\n";
- return;
+ if (!Opcodes.empty()) {
+ for (const unsigned Opcode : Opcodes) {
+ // Ignore instructions without a sched class if
+ // -ignore-invalid-sched-class is passed.
+ if (IgnoreInvalidSchedClass &&
+ State.getInstrInfo().get(Opcode).getSchedClass() == 0) {
+ llvm::errs() << State.getInstrInfo().getName(Opcode)
+ << ": ignoring instruction without sched class\n";
+ continue;
+ }
+ auto ConfigsForInstr = generateSnippets(State, Opcode);
+ if (!ConfigsForInstr) {
+ llvm::logAllUnhandledErrors(
+ ConfigsForInstr.takeError(), llvm::errs(),
+ llvm::Twine(State.getInstrInfo().getName(Opcode)).concat(": "));
+ continue;
+ }
+ std::move(ConfigsForInstr->begin(), ConfigsForInstr->end(),
+ std::back_inserter(Configurations));
}
- Configurations = ExitOnErr(generateSnippets(State, Opcode));
} else {
Configurations = ExitOnErr(readSnippets(State, SnippetsFile));
}
More information about the llvm-commits
mailing list