aboutsummaryrefslogtreecommitdiff
path: root/llvm/tools/llvm-exegesis/lib
diff options
context:
space:
mode:
authorAiden Grossman <agrossman154@yahoo.com>2024-01-19 02:00:33 -0800
committerGitHub <noreply@github.com>2024-01-19 02:00:33 -0800
commitf670112a591c83498e348f3ff2f73f02baf8e303 (patch)
treea68f2fa6c8ab80ddd580c4df49f42c6cf9752ecf /llvm/tools/llvm-exegesis/lib
parent4619147911c2a955bb605618bc518b45da994a81 (diff)
downloadllvm-f670112a591c83498e348f3ff2f73f02baf8e303.zip
llvm-f670112a591c83498e348f3ff2f73f02baf8e303.tar.gz
llvm-f670112a591c83498e348f3ff2f73f02baf8e303.tar.bz2
[llvm-exegesis] Add support for validation counters (#76653)
This patch adds support for validation counters. Validation counters can be used to measure events that occur during snippet execution like cache misses to ensure that certain assumed invariants about the benchmark actually hold. Validation counters are setup within a perf event group, so are turned on and off at exactly the same time as the "group leader" counter that measures the desired value.
Diffstat (limited to 'llvm/tools/llvm-exegesis/lib')
-rw-r--r--llvm/tools/llvm-exegesis/lib/BenchmarkResult.cpp37
-rw-r--r--llvm/tools/llvm-exegesis/lib/BenchmarkResult.h10
-rw-r--r--llvm/tools/llvm-exegesis/lib/BenchmarkRunner.cpp86
-rw-r--r--llvm/tools/llvm-exegesis/lib/BenchmarkRunner.h16
-rw-r--r--llvm/tools/llvm-exegesis/lib/LatencyBenchmarkRunner.cpp41
-rw-r--r--llvm/tools/llvm-exegesis/lib/LatencyBenchmarkRunner.h2
-rw-r--r--llvm/tools/llvm-exegesis/lib/PerfHelper.cpp43
-rw-r--r--llvm/tools/llvm-exegesis/lib/PerfHelper.h9
-rw-r--r--llvm/tools/llvm-exegesis/lib/Target.cpp35
-rw-r--r--llvm/tools/llvm-exegesis/lib/Target.h10
-rw-r--r--llvm/tools/llvm-exegesis/lib/UopsBenchmarkRunner.cpp32
-rw-r--r--llvm/tools/llvm-exegesis/lib/UopsBenchmarkRunner.h6
-rw-r--r--llvm/tools/llvm-exegesis/lib/X86/Target.cpp22
-rw-r--r--llvm/tools/llvm-exegesis/lib/X86/X86Counter.cpp2
14 files changed, 283 insertions, 68 deletions
diff --git a/llvm/tools/llvm-exegesis/lib/BenchmarkResult.cpp b/llvm/tools/llvm-exegesis/lib/BenchmarkResult.cpp
index 02c4da1..60264ca 100644
--- a/llvm/tools/llvm-exegesis/lib/BenchmarkResult.cpp
+++ b/llvm/tools/llvm-exegesis/lib/BenchmarkResult.cpp
@@ -14,6 +14,7 @@
#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/bit.h"
#include "llvm/ObjectYAML/YAML.h"
+#include "llvm/Support/Errc.h"
#include "llvm/Support/FileOutputBuffer.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/Format.h"
@@ -192,6 +193,41 @@ template <> struct SequenceElementTraits<exegesis::BenchmarkMeasure> {
static const bool flow = false;
};
+const char *validationEventToString(exegesis::ValidationEvent VE) {
+ switch (VE) {
+ case exegesis::ValidationEvent::InstructionRetired:
+ return "instructions-retired";
+ }
+}
+
+Expected<exegesis::ValidationEvent> stringToValidationEvent(StringRef Input) {
+ if (Input == "instructions-retired")
+ return exegesis::ValidationEvent::InstructionRetired;
+ else
+ return make_error<StringError>("Invalid validation event string",
+ errc::invalid_argument);
+}
+
+template <>
+struct CustomMappingTraits<std::map<exegesis::ValidationEvent, int64_t>> {
+ static void inputOne(IO &Io, StringRef KeyStr,
+ std::map<exegesis::ValidationEvent, int64_t> &VI) {
+ Expected<exegesis::ValidationEvent> Key = stringToValidationEvent(KeyStr);
+ if (!Key) {
+ Io.setError("Key is not a valid validation event");
+ return;
+ }
+ Io.mapRequired(KeyStr.str().c_str(), VI[*Key]);
+ }
+
+ static void output(IO &Io, std::map<exegesis::ValidationEvent, int64_t> &VI) {
+ for (auto &IndividualVI : VI) {
+ Io.mapRequired(validationEventToString(IndividualVI.first),
+ IndividualVI.second);
+ }
+ }
+};
+
// exegesis::Measure is rendererd as a flow instead of a list.
// e.g. { "key": "the key", "value": 0123 }
template <> struct MappingTraits<exegesis::BenchmarkMeasure> {
@@ -203,6 +239,7 @@ template <> struct MappingTraits<exegesis::BenchmarkMeasure> {
}
Io.mapRequired("value", Obj.PerInstructionValue);
Io.mapOptional("per_snippet_value", Obj.PerSnippetValue);
+ Io.mapOptional("validation_counters", Obj.ValidationCounters);
}
static const bool flow = true;
};
diff --git a/llvm/tools/llvm-exegesis/lib/BenchmarkResult.h b/llvm/tools/llvm-exegesis/lib/BenchmarkResult.h
index 0d08feb..c983d6d 100644
--- a/llvm/tools/llvm-exegesis/lib/BenchmarkResult.h
+++ b/llvm/tools/llvm-exegesis/lib/BenchmarkResult.h
@@ -32,6 +32,8 @@ class Error;
namespace exegesis {
+enum ValidationEvent { InstructionRetired };
+
enum class BenchmarkPhaseSelectorE {
PrepareSnippet,
PrepareAndAssembleSnippet,
@@ -77,8 +79,10 @@ struct BenchmarkKey {
struct BenchmarkMeasure {
// A helper to create an unscaled BenchmarkMeasure.
- static BenchmarkMeasure Create(std::string Key, double Value) {
- return {Key, Value, Value};
+ static BenchmarkMeasure
+ Create(std::string Key, double Value,
+ std::map<ValidationEvent, int64_t> ValCounters) {
+ return {Key, Value, Value, ValCounters};
}
std::string Key;
// This is the per-instruction value, i.e. measured quantity scaled per
@@ -87,6 +91,8 @@ struct BenchmarkMeasure {
// This is the per-snippet value, i.e. measured quantity for one repetition of
// the whole snippet.
double PerSnippetValue;
+ // These are the validation counter values.
+ std::map<ValidationEvent, int64_t> ValidationCounters;
};
// The result of an instruction benchmark.
diff --git a/llvm/tools/llvm-exegesis/lib/BenchmarkRunner.cpp b/llvm/tools/llvm-exegesis/lib/BenchmarkRunner.cpp
index eb1393a..2b51228 100644
--- a/llvm/tools/llvm-exegesis/lib/BenchmarkRunner.cpp
+++ b/llvm/tools/llvm-exegesis/lib/BenchmarkRunner.cpp
@@ -54,9 +54,11 @@ namespace exegesis {
BenchmarkRunner::BenchmarkRunner(const LLVMState &State, Benchmark::ModeE Mode,
BenchmarkPhaseSelectorE BenchmarkPhaseSelector,
- ExecutionModeE ExecutionMode)
+ ExecutionModeE ExecutionMode,
+ ArrayRef<ValidationEvent> ValCounters)
: State(State), Mode(Mode), BenchmarkPhaseSelector(BenchmarkPhaseSelector),
- ExecutionMode(ExecutionMode), Scratch(std::make_unique<ScratchSpace>()) {}
+ ExecutionMode(ExecutionMode), ValidationCounters(ValCounters),
+ Scratch(std::make_unique<ScratchSpace>()) {}
BenchmarkRunner::~BenchmarkRunner() = default;
@@ -71,7 +73,9 @@ void BenchmarkRunner::FunctionExecutor::accumulateCounterValues(
}
Expected<llvm::SmallVector<int64_t, 4>>
-BenchmarkRunner::FunctionExecutor::runAndSample(const char *Counters) const {
+BenchmarkRunner::FunctionExecutor::runAndSample(
+ const char *Counters, ArrayRef<const char *> ValidationCounters,
+ SmallVectorImpl<int64_t> &ValidationCounterValues) const {
// We sum counts when there are several counters for a single ProcRes
// (e.g. P23 on SandyBridge).
llvm::SmallVector<int64_t, 4> CounterValues;
@@ -79,8 +83,8 @@ BenchmarkRunner::FunctionExecutor::runAndSample(const char *Counters) const {
StringRef(Counters).split(CounterNames, '+');
for (auto &CounterName : CounterNames) {
CounterName = CounterName.trim();
- Expected<SmallVector<int64_t, 4>> ValueOrError =
- runWithCounter(CounterName);
+ Expected<SmallVector<int64_t, 4>> ValueOrError = runWithCounter(
+ CounterName, ValidationCounters, ValidationCounterValues);
if (!ValueOrError)
return ValueOrError.takeError();
accumulateCounterValues(ValueOrError.get(), &CounterValues);
@@ -120,11 +124,13 @@ private:
(*Result)[I] += NewValues[I];
}
- Expected<llvm::SmallVector<int64_t, 4>>
- runWithCounter(StringRef CounterName) const override {
+ Expected<llvm::SmallVector<int64_t, 4>> runWithCounter(
+ StringRef CounterName, ArrayRef<const char *> ValidationCounters,
+ SmallVectorImpl<int64_t> &ValidationCounterValues) const override {
const ExegesisTarget &ET = State.getExegesisTarget();
char *const ScratchPtr = Scratch->ptr();
- auto CounterOrError = ET.createCounter(CounterName, State);
+ auto CounterOrError =
+ ET.createCounter(CounterName, State, ValidationCounters);
if (!CounterOrError)
return CounterOrError.takeError();
@@ -156,6 +162,14 @@ private:
}
}
+ auto ValidationValuesOrErr = Counter->readValidationCountersOrError();
+ if (!ValidationValuesOrErr)
+ return ValidationValuesOrErr.takeError();
+
+ ArrayRef RealValidationValues = *ValidationValuesOrErr;
+ for (size_t I = 0; I < RealValidationValues.size(); ++I)
+ ValidationCounterValues[I] = RealValidationValues[I];
+
return Counter->readOrError(Function.getFunctionBytes());
}
@@ -266,7 +280,9 @@ private:
}
Error createSubProcessAndRunBenchmark(
- StringRef CounterName, SmallVectorImpl<int64_t> &CounterValues) const {
+ StringRef CounterName, SmallVectorImpl<int64_t> &CounterValues,
+ ArrayRef<const char *> ValidationCounters,
+ SmallVectorImpl<int64_t> &ValidationCounterValues) const {
int PipeFiles[2];
int PipeSuccessOrErr = socketpair(AF_UNIX, SOCK_DGRAM, 0, PipeFiles);
if (PipeSuccessOrErr != 0) {
@@ -306,8 +322,8 @@ private:
}
const ExegesisTarget &ET = State.getExegesisTarget();
- auto CounterOrError =
- ET.createCounter(CounterName, State, ParentOrChildPID);
+ auto CounterOrError = ET.createCounter(
+ CounterName, State, ValidationCounters, ParentOrChildPID);
if (!CounterOrError)
return CounterOrError.takeError();
@@ -362,6 +378,14 @@ private:
return CounterValueOrErr.takeError();
CounterValues = std::move(*CounterValueOrErr);
+ auto ValidationValuesOrErr = Counter->readValidationCountersOrError();
+ if (!ValidationValuesOrErr)
+ return ValidationValuesOrErr.takeError();
+
+ ArrayRef RealValidationValues = *ValidationValuesOrErr;
+ for (size_t I = 0; I < RealValidationValues.size(); ++I)
+ ValidationCounterValues[I] = RealValidationValues[I];
+
return Error::success();
}
// The child exited, but not successfully
@@ -460,15 +484,15 @@ private:
exit(0);
}
- Expected<llvm::SmallVector<int64_t, 4>>
- runWithCounter(StringRef CounterName) const override {
+ Expected<llvm::SmallVector<int64_t, 4>> runWithCounter(
+ StringRef CounterName, ArrayRef<const char *> ValidationCounters,
+ SmallVectorImpl<int64_t> &ValidationCounterValues) const override {
SmallVector<int64_t, 4> Value(1, 0);
- Error PossibleBenchmarkError =
- createSubProcessAndRunBenchmark(CounterName, Value);
+ Error PossibleBenchmarkError = createSubProcessAndRunBenchmark(
+ CounterName, Value, ValidationCounters, ValidationCounterValues);
- if (PossibleBenchmarkError) {
+ if (PossibleBenchmarkError)
return std::move(PossibleBenchmarkError);
- }
return Value;
}
@@ -642,6 +666,34 @@ BenchmarkRunner::writeObjectFile(StringRef Buffer, StringRef FileName) const {
return std::string(ResultPath);
}
+static bool EventLessThan(const std::pair<ValidationEvent, const char *> LHS,
+ const ValidationEvent RHS) {
+ return static_cast<int>(LHS.first) < static_cast<int>(RHS);
+}
+
+Error BenchmarkRunner::getValidationCountersToRun(
+ SmallVector<const char *> &ValCountersToRun) const {
+ const PfmCountersInfo &PCI = State.getPfmCounters();
+ ValCountersToRun.reserve(ValidationCounters.size());
+
+ ValCountersToRun.reserve(ValidationCounters.size());
+ ArrayRef TargetValidationEvents(PCI.ValidationEvents,
+ PCI.NumValidationEvents);
+ for (const ValidationEvent RequestedValEvent : ValidationCounters) {
+ auto ValCounterIt =
+ lower_bound(TargetValidationEvents, RequestedValEvent, EventLessThan);
+ if (ValCounterIt == TargetValidationEvents.end() ||
+ ValCounterIt->first != RequestedValEvent)
+ return make_error<Failure>("Cannot create validation counter");
+
+ assert(ValCounterIt->first == RequestedValEvent &&
+ "The array of validation events from the target should be sorted");
+ ValCountersToRun.push_back(ValCounterIt->second);
+ }
+
+ return Error::success();
+}
+
BenchmarkRunner::FunctionExecutor::~FunctionExecutor() {}
} // namespace exegesis
diff --git a/llvm/tools/llvm-exegesis/lib/BenchmarkRunner.h b/llvm/tools/llvm-exegesis/lib/BenchmarkRunner.h
index d746a0f..aab4b54 100644
--- a/llvm/tools/llvm-exegesis/lib/BenchmarkRunner.h
+++ b/llvm/tools/llvm-exegesis/lib/BenchmarkRunner.h
@@ -38,7 +38,8 @@ public:
explicit BenchmarkRunner(const LLVMState &State, Benchmark::ModeE Mode,
BenchmarkPhaseSelectorE BenchmarkPhaseSelector,
- ExecutionModeE ExecutionMode);
+ ExecutionModeE ExecutionMode,
+ ArrayRef<ValidationEvent> ValCounters);
virtual ~BenchmarkRunner();
@@ -93,14 +94,18 @@ public:
virtual ~FunctionExecutor();
Expected<llvm::SmallVector<int64_t, 4>>
- runAndSample(const char *Counters) const;
+ runAndSample(const char *Counters,
+ ArrayRef<const char *> ValidationCounters,
+ SmallVectorImpl<int64_t> &ValidationCounterValues) const;
protected:
static void
accumulateCounterValues(const llvm::SmallVectorImpl<int64_t> &NewValues,
llvm::SmallVectorImpl<int64_t> *Result);
virtual Expected<llvm::SmallVector<int64_t, 4>>
- runWithCounter(StringRef CounterName) const = 0;
+ runWithCounter(StringRef CounterName,
+ ArrayRef<const char *> ValidationCounters,
+ SmallVectorImpl<int64_t> &ValidationCounterValues) const = 0;
};
protected:
@@ -109,6 +114,11 @@ protected:
const BenchmarkPhaseSelectorE BenchmarkPhaseSelector;
const ExecutionModeE ExecutionMode;
+ SmallVector<ValidationEvent> ValidationCounters;
+
+ Error
+ getValidationCountersToRun(SmallVector<const char *> &ValCountersToRun) const;
+
private:
virtual Expected<std::vector<BenchmarkMeasure>>
runMeasurements(const FunctionExecutor &Executor) const = 0;
diff --git a/llvm/tools/llvm-exegesis/lib/LatencyBenchmarkRunner.cpp b/llvm/tools/llvm-exegesis/lib/LatencyBenchmarkRunner.cpp
index eda4505..eb7f70f 100644
--- a/llvm/tools/llvm-exegesis/lib/LatencyBenchmarkRunner.cpp
+++ b/llvm/tools/llvm-exegesis/lib/LatencyBenchmarkRunner.cpp
@@ -22,8 +22,9 @@ LatencyBenchmarkRunner::LatencyBenchmarkRunner(
const LLVMState &State, Benchmark::ModeE Mode,
BenchmarkPhaseSelectorE BenchmarkPhaseSelector,
Benchmark::ResultAggregationModeE ResultAgg, ExecutionModeE ExecutionMode,
- unsigned BenchmarkRepeatCount)
- : BenchmarkRunner(State, Mode, BenchmarkPhaseSelector, ExecutionMode) {
+ ArrayRef<ValidationEvent> ValCounters, unsigned BenchmarkRepeatCount)
+ : BenchmarkRunner(State, Mode, BenchmarkPhaseSelector, ExecutionMode,
+ ValCounters) {
assert((Mode == Benchmark::Latency || Mode == Benchmark::InverseThroughput) &&
"invalid mode");
ResultAggMode = ResultAgg;
@@ -72,11 +73,21 @@ Expected<std::vector<BenchmarkMeasure>> LatencyBenchmarkRunner::runMeasurements(
// ResultAggMode.
llvm::SmallVector<int64_t, 4> AccumulatedValues;
double MinVariance = std::numeric_limits<double>::infinity();
- const char *CounterName = State.getPfmCounters().CycleCounter;
+ const PfmCountersInfo &PCI = State.getPfmCounters();
+ const char *CounterName = PCI.CycleCounter;
+
+ SmallVector<const char *> ValCountersToRun;
+ Error ValCounterErr = getValidationCountersToRun(ValCountersToRun);
+ if (ValCounterErr)
+ return std::move(ValCounterErr);
+
+ SmallVector<int64_t> ValCounterValues(ValCountersToRun.size(), 0);
// Values count for each run.
int ValuesCount = 0;
for (size_t I = 0; I < NumMeasurements; ++I) {
- auto ExpectedCounterValues = Executor.runAndSample(CounterName);
+ SmallVector<int64_t> IterationValCounterValues(ValCountersToRun.size(), -1);
+ auto ExpectedCounterValues = Executor.runAndSample(
+ CounterName, ValCountersToRun, IterationValCounterValues);
if (!ExpectedCounterValues)
return ExpectedCounterValues.takeError();
ValuesCount = ExpectedCounterValues.get().size();
@@ -90,8 +101,15 @@ Expected<std::vector<BenchmarkMeasure>> LatencyBenchmarkRunner::runMeasurements(
MinVariance = Variance;
}
}
+
+ for (size_t I = 0; I < ValCounterValues.size(); ++I)
+ ValCounterValues[I] += IterationValCounterValues[I];
}
+ std::map<ValidationEvent, int64_t> ValidationInfo;
+ for (size_t I = 0; I < ValidationCounters.size(); ++I)
+ ValidationInfo[ValidationCounters[I]] = ValCounterValues[I];
+
std::string ModeName;
switch (Mode) {
case Benchmark::Latency:
@@ -112,25 +130,26 @@ Expected<std::vector<BenchmarkMeasure>> LatencyBenchmarkRunner::runMeasurements(
std::vector<BenchmarkMeasure> Result;
Result.reserve(AccumulatedValues.size());
for (const int64_t Value : AccumulatedValues)
- Result.push_back(BenchmarkMeasure::Create(ModeName, Value));
+ Result.push_back(
+ BenchmarkMeasure::Create(ModeName, Value, ValidationInfo));
return std::move(Result);
}
case Benchmark::Min: {
std::vector<BenchmarkMeasure> Result;
- Result.push_back(
- BenchmarkMeasure::Create(ModeName, findMin(AccumulatedValues)));
+ Result.push_back(BenchmarkMeasure::Create(
+ ModeName, findMin(AccumulatedValues), ValidationInfo));
return std::move(Result);
}
case Benchmark::Max: {
std::vector<BenchmarkMeasure> Result;
- Result.push_back(
- BenchmarkMeasure::Create(ModeName, findMax(AccumulatedValues)));
+ Result.push_back(BenchmarkMeasure::Create(
+ ModeName, findMax(AccumulatedValues), ValidationInfo));
return std::move(Result);
}
case Benchmark::Mean: {
std::vector<BenchmarkMeasure> Result;
- Result.push_back(
- BenchmarkMeasure::Create(ModeName, findMean(AccumulatedValues)));
+ Result.push_back(BenchmarkMeasure::Create(
+ ModeName, findMean(AccumulatedValues), ValidationInfo));
return std::move(Result);
}
}
diff --git a/llvm/tools/llvm-exegesis/lib/LatencyBenchmarkRunner.h b/llvm/tools/llvm-exegesis/lib/LatencyBenchmarkRunner.h
index fc159d7..6e21197 100644
--- a/llvm/tools/llvm-exegesis/lib/LatencyBenchmarkRunner.h
+++ b/llvm/tools/llvm-exegesis/lib/LatencyBenchmarkRunner.h
@@ -15,6 +15,7 @@
#define LLVM_TOOLS_LLVM_EXEGESIS_LATENCY_H
#include "BenchmarkRunner.h"
+#include "Target.h"
namespace llvm {
namespace exegesis {
@@ -25,6 +26,7 @@ public:
BenchmarkPhaseSelectorE BenchmarkPhaseSelector,
Benchmark::ResultAggregationModeE ResultAggMode,
ExecutionModeE ExecutionMode,
+ ArrayRef<ValidationEvent> ValCounters,
unsigned BenchmarkRepeatCount);
~LatencyBenchmarkRunner() override;
diff --git a/llvm/tools/llvm-exegesis/lib/PerfHelper.cpp b/llvm/tools/llvm-exegesis/lib/PerfHelper.cpp
index 1dab880..6b8df01 100644
--- a/llvm/tools/llvm-exegesis/lib/PerfHelper.cpp
+++ b/llvm/tools/llvm-exegesis/lib/PerfHelper.cpp
@@ -113,9 +113,8 @@ ConfiguredEvent::ConfiguredEvent(PerfEvent &&EventToConfigure)
}
#ifdef HAVE_LIBPFM
-void ConfiguredEvent::initRealEvent(const pid_t ProcessID) {
+void ConfiguredEvent::initRealEvent(const pid_t ProcessID, const int GroupFD) {
const int CPU = -1;
- const int GroupFD = -1;
const uint32_t Flags = 0;
perf_event_attr AttrCopy = *Event.attribute();
FileDescriptor = perf_event_open(&AttrCopy, ProcessID, CPU, GroupFD, Flags);
@@ -147,7 +146,7 @@ ConfiguredEvent::readOrError(StringRef /*unused*/) const {
ConfiguredEvent::~ConfiguredEvent() { close(FileDescriptor); }
#else
-void ConfiguredEvent::initRealEvent(pid_t ProcessID) {}
+void ConfiguredEvent::initRealEvent(pid_t ProcessID, const int GroupFD) {}
Expected<SmallVector<int64_t>>
ConfiguredEvent::readOrError(StringRef /*unused*/) const {
@@ -158,9 +157,14 @@ ConfiguredEvent::readOrError(StringRef /*unused*/) const {
ConfiguredEvent::~ConfiguredEvent() = default;
#endif // HAVE_LIBPFM
-CounterGroup::CounterGroup(PerfEvent &&E, pid_t ProcessID)
+CounterGroup::CounterGroup(PerfEvent &&E, std::vector<PerfEvent> &&ValEvents,
+ pid_t ProcessID)
: EventCounter(std::move(E)) {
IsDummyEvent = EventCounter.isDummyEvent();
+
+ for (auto &&ValEvent : ValEvents)
+ ValidationEventCounters.emplace_back(std::move(ValEvent));
+
if (!IsDummyEvent)
initRealEvent(ProcessID);
}
@@ -168,16 +172,19 @@ CounterGroup::CounterGroup(PerfEvent &&E, pid_t ProcessID)
#ifdef HAVE_LIBPFM
void CounterGroup::initRealEvent(pid_t ProcessID) {
EventCounter.initRealEvent(ProcessID);
+
+ for (auto &ValCounter : ValidationEventCounters)
+ ValCounter.initRealEvent(ProcessID, getFileDescriptor());
}
void CounterGroup::start() {
if (!IsDummyEvent)
- ioctl(getFileDescriptor(), PERF_EVENT_IOC_RESET, 0);
+ ioctl(getFileDescriptor(), PERF_EVENT_IOC_RESET, PERF_IOC_FLAG_GROUP);
}
void CounterGroup::stop() {
if (!IsDummyEvent)
- ioctl(getFileDescriptor(), PERF_EVENT_IOC_DISABLE, 0);
+ ioctl(getFileDescriptor(), PERF_EVENT_IOC_DISABLE, PERF_IOC_FLAG_GROUP);
}
llvm::Expected<llvm::SmallVector<int64_t, 4>>
@@ -188,6 +195,25 @@ CounterGroup::readOrError(StringRef FunctionBytes) const {
return SmallVector<int64_t, 1>(1, 42);
}
+llvm::Expected<llvm::SmallVector<int64_t>>
+CounterGroup::readValidationCountersOrError() const {
+ llvm::SmallVector<int64_t, 4> Result;
+ for (const auto &ValCounter : ValidationEventCounters) {
+ Expected<SmallVector<int64_t>> ValueOrError =
+ ValCounter.readOrError(StringRef());
+
+ if (!ValueOrError)
+ return ValueOrError.takeError();
+
+ // Reading a validation counter will only return a single value, so it is
+ // safe to only append the first value here. Also assert that this is true.
+ assert(ValueOrError->size() == 1 &&
+ "Validation counters should only return a single value");
+ Result.push_back((*ValueOrError)[0]);
+ }
+ return Result;
+}
+
int CounterGroup::numValues() const { return 1; }
#else
@@ -208,6 +234,11 @@ CounterGroup::readOrError(StringRef /*unused*/) const {
llvm::errc::io_error);
}
+llvm::Expected<llvm::SmallVector<int64_t>>
+CounterGroup::readValidationCountersOrError() const {
+ return SmallVector<int64_t>(0);
+}
+
int CounterGroup::numValues() const { return 1; }
#endif
diff --git a/llvm/tools/llvm-exegesis/lib/PerfHelper.h b/llvm/tools/llvm-exegesis/lib/PerfHelper.h
index e9b73da..7d050b8 100644
--- a/llvm/tools/llvm-exegesis/lib/PerfHelper.h
+++ b/llvm/tools/llvm-exegesis/lib/PerfHelper.h
@@ -83,7 +83,7 @@ class ConfiguredEvent {
public:
ConfiguredEvent(PerfEvent &&EventToConfigure);
- void initRealEvent(const pid_t ProcessID);
+ void initRealEvent(const pid_t ProcessID, const int GroupFD = -1);
Expected<SmallVector<int64_t>> readOrError(StringRef FunctionBytes) const;
int getFileDescriptor() const { return FileDescriptor; }
bool isDummyEvent() const {
@@ -107,7 +107,8 @@ private:
class CounterGroup {
public:
// event: the PerfEvent to measure.
- explicit CounterGroup(PerfEvent &&event, pid_t ProcessID = 0);
+ explicit CounterGroup(PerfEvent &&event, std::vector<PerfEvent> &&ValEvents,
+ pid_t ProcessID = 0);
CounterGroup(const CounterGroup &) = delete;
CounterGroup(CounterGroup &&other) = default;
@@ -129,6 +130,9 @@ public:
virtual llvm::Expected<llvm::SmallVector<int64_t, 4>>
readOrError(StringRef FunctionBytes = StringRef()) const;
+ virtual llvm::Expected<llvm::SmallVector<int64_t>>
+ readValidationCountersOrError() const;
+
virtual int numValues() const;
int getFileDescriptor() const { return EventCounter.getFileDescriptor(); }
@@ -136,6 +140,7 @@ public:
protected:
ConfiguredEvent EventCounter;
bool IsDummyEvent;
+ std::vector<ConfiguredEvent> ValidationEventCounters;
private:
void initRealEvent(pid_t ProcessID);
diff --git a/llvm/tools/llvm-exegesis/lib/Target.cpp b/llvm/tools/llvm-exegesis/lib/Target.cpp
index 8f1c5a1..58cf1b9 100644
--- a/llvm/tools/llvm-exegesis/lib/Target.cpp
+++ b/llvm/tools/llvm-exegesis/lib/Target.cpp
@@ -37,6 +37,7 @@ const ExegesisTarget *ExegesisTarget::lookup(Triple TT) {
Expected<std::unique_ptr<pfm::CounterGroup>>
ExegesisTarget::createCounter(StringRef CounterName, const LLVMState &,
+ ArrayRef<const char *> ValidationCounters,
const pid_t ProcessID) const {
pfm::PerfEvent Event(CounterName);
if (!Event.valid())
@@ -45,7 +46,18 @@ ExegesisTarget::createCounter(StringRef CounterName, const LLVMState &,
.concat(CounterName)
.concat("'"));
- return std::make_unique<pfm::CounterGroup>(std::move(Event), ProcessID);
+ std::vector<pfm::PerfEvent> ValidationEvents;
+ for (const char *ValCounterName : ValidationCounters) {
+ ValidationEvents.emplace_back(ValCounterName);
+ if (!ValidationEvents.back().valid())
+ return llvm::make_error<Failure>(
+ llvm::Twine("Unable to create validation counter with name '")
+ .concat(ValCounterName)
+ .concat("'"));
+ }
+
+ return std::make_unique<pfm::CounterGroup>(
+ std::move(Event), std::move(ValidationEvents), ProcessID);
}
void ExegesisTarget::registerTarget(ExegesisTarget *Target) {
@@ -79,7 +91,7 @@ ExegesisTarget::createBenchmarkRunner(
Benchmark::ModeE Mode, const LLVMState &State,
BenchmarkPhaseSelectorE BenchmarkPhaseSelector,
BenchmarkRunner::ExecutionModeE ExecutionMode,
- unsigned BenchmarkRepeatCount,
+ unsigned BenchmarkRepeatCount, ArrayRef<ValidationEvent> ValidationCounters,
Benchmark::ResultAggregationModeE ResultAggMode) const {
PfmCountersInfo PfmCounters = State.getPfmCounters();
switch (Mode) {
@@ -101,9 +113,9 @@ ExegesisTarget::createBenchmarkRunner(
"benchmarking or --use-dummy-perf-counters to not query "
"the kernel for real event counts."));
}
- return createLatencyBenchmarkRunner(State, Mode, BenchmarkPhaseSelector,
- ResultAggMode, ExecutionMode,
- BenchmarkRepeatCount);
+ return createLatencyBenchmarkRunner(
+ State, Mode, BenchmarkPhaseSelector, ResultAggMode, ExecutionMode,
+ ValidationCounters, BenchmarkRepeatCount);
case Benchmark::Uops:
if (BenchmarkPhaseSelector == BenchmarkPhaseSelectorE::Measure &&
!PfmCounters.UopsCounter && !PfmCounters.IssueCounters)
@@ -113,7 +125,8 @@ ExegesisTarget::createBenchmarkRunner(
"benchmarking or --use-dummy-perf-counters to not query the kernel "
"for real event counts.");
return createUopsBenchmarkRunner(State, BenchmarkPhaseSelector,
- ResultAggMode, ExecutionMode);
+ ResultAggMode, ExecutionMode,
+ ValidationCounters);
}
return nullptr;
}
@@ -133,18 +146,20 @@ std::unique_ptr<BenchmarkRunner> ExegesisTarget::createLatencyBenchmarkRunner(
BenchmarkPhaseSelectorE BenchmarkPhaseSelector,
Benchmark::ResultAggregationModeE ResultAggMode,
BenchmarkRunner::ExecutionModeE ExecutionMode,
+ ArrayRef<ValidationEvent> ValidationCounters,
unsigned BenchmarkRepeatCount) const {
return std::make_unique<LatencyBenchmarkRunner>(
State, Mode, BenchmarkPhaseSelector, ResultAggMode, ExecutionMode,
- BenchmarkRepeatCount);
+ ValidationCounters, BenchmarkRepeatCount);
}
std::unique_ptr<BenchmarkRunner> ExegesisTarget::createUopsBenchmarkRunner(
const LLVMState &State, BenchmarkPhaseSelectorE BenchmarkPhaseSelector,
Benchmark::ResultAggregationModeE /*unused*/,
- BenchmarkRunner::ExecutionModeE ExecutionMode) const {
- return std::make_unique<UopsBenchmarkRunner>(State, BenchmarkPhaseSelector,
- ExecutionMode);
+ BenchmarkRunner::ExecutionModeE ExecutionMode,
+ ArrayRef<ValidationEvent> ValidationCounters) const {
+ return std::make_unique<UopsBenchmarkRunner>(
+ State, BenchmarkPhaseSelector, ExecutionMode, ValidationCounters);
}
static_assert(std::is_trivial_v<PfmCountersInfo>,
diff --git a/llvm/tools/llvm-exegesis/lib/Target.h b/llvm/tools/llvm-exegesis/lib/Target.h
index da6d446..3d6169c 100644
--- a/llvm/tools/llvm-exegesis/lib/Target.h
+++ b/llvm/tools/llvm-exegesis/lib/Target.h
@@ -39,10 +39,6 @@ extern cl::OptionCategory Options;
extern cl::OptionCategory BenchmarkOptions;
extern cl::OptionCategory AnalysisOptions;
-enum ValidationEvent {
- InstructionRetired
-};
-
struct PfmCountersInfo {
// An optional name of a performance counter that can be used to measure
// cycles.
@@ -86,6 +82,7 @@ public:
// Targets can use this to create target-specific perf counters.
virtual Expected<std::unique_ptr<pfm::CounterGroup>>
createCounter(StringRef CounterName, const LLVMState &State,
+ ArrayRef<const char *> ValidationCounters,
const pid_t ProcessID = 0) const;
// Targets can use this to add target-specific passes in assembleToStream();
@@ -270,6 +267,7 @@ public:
BenchmarkPhaseSelectorE BenchmarkPhaseSelector,
BenchmarkRunner::ExecutionModeE ExecutionMode,
unsigned BenchmarkRepeatCount,
+ ArrayRef<ValidationEvent> ValidationCounters,
Benchmark::ResultAggregationModeE ResultAggMode = Benchmark::Min) const;
// Returns the ExegesisTarget for the given triple or nullptr if the target
@@ -314,11 +312,13 @@ private:
BenchmarkPhaseSelectorE BenchmarkPhaseSelector,
Benchmark::ResultAggregationModeE ResultAggMode,
BenchmarkRunner::ExecutionModeE ExecutionMode,
+ ArrayRef<ValidationEvent> ValidationCounters,
unsigned BenchmarkRepeatCount) const;
std::unique_ptr<BenchmarkRunner> virtual createUopsBenchmarkRunner(
const LLVMState &State, BenchmarkPhaseSelectorE BenchmarkPhaseSelector,
Benchmark::ResultAggregationModeE ResultAggMode,
- BenchmarkRunner::ExecutionModeE ExecutionMode) const;
+ BenchmarkRunner::ExecutionModeE ExecutionMode,
+ ArrayRef<ValidationEvent> ValidationCounters) const;
const ExegesisTarget *Next = nullptr;
const ArrayRef<CpuAndPfmCounters> CpuPfmCounters;
diff --git a/llvm/tools/llvm-exegesis/lib/UopsBenchmarkRunner.cpp b/llvm/tools/llvm-exegesis/lib/UopsBenchmarkRunner.cpp
index 6351fdd..d6fb599 100644
--- a/llvm/tools/llvm-exegesis/lib/UopsBenchmarkRunner.cpp
+++ b/llvm/tools/llvm-exegesis/lib/UopsBenchmarkRunner.cpp
@@ -19,25 +19,45 @@ Expected<std::vector<BenchmarkMeasure>>
UopsBenchmarkRunner::runMeasurements(const FunctionExecutor &Executor) const {
std::vector<BenchmarkMeasure> Result;
const PfmCountersInfo &PCI = State.getPfmCounters();
+
+ SmallVector<const char *> ValCountersToRun;
+ Error ValCounterErr = getValidationCountersToRun(ValCountersToRun);
+ if (ValCounterErr)
+ return std::move(ValCounterErr);
+
// Uops per port.
for (const auto *IssueCounter = PCI.IssueCounters,
*IssueCounterEnd = PCI.IssueCounters + PCI.NumIssueCounters;
IssueCounter != IssueCounterEnd; ++IssueCounter) {
+ SmallVector<int64_t> ValCounterPortValues(ValCountersToRun.size(), -1);
if (!IssueCounter->Counter)
continue;
- auto ExpectedCounterValue = Executor.runAndSample(IssueCounter->Counter);
+ auto ExpectedCounterValue = Executor.runAndSample(
+ IssueCounter->Counter, ValCountersToRun, ValCounterPortValues);
if (!ExpectedCounterValue)
return ExpectedCounterValue.takeError();
- Result.push_back(BenchmarkMeasure::Create(IssueCounter->ProcResName,
- (*ExpectedCounterValue)[0]));
+
+ std::map<ValidationEvent, int64_t> ValidationInfo;
+ for (size_t I = 0; I < ValidationCounters.size(); ++I)
+ ValidationInfo[ValidationCounters[I]] = ValCounterPortValues[I];
+
+ Result.push_back(BenchmarkMeasure::Create(
+ IssueCounter->ProcResName, (*ExpectedCounterValue)[0], ValidationInfo));
}
// NumMicroOps.
if (const char *const UopsCounter = PCI.UopsCounter) {
- auto ExpectedCounterValue = Executor.runAndSample(UopsCounter);
+ SmallVector<int64_t> ValCounterUopsValues(ValCountersToRun.size(), -1);
+ auto ExpectedCounterValue = Executor.runAndSample(
+ UopsCounter, ValCountersToRun, ValCounterUopsValues);
if (!ExpectedCounterValue)
return ExpectedCounterValue.takeError();
- Result.push_back(
- BenchmarkMeasure::Create("NumMicroOps", (*ExpectedCounterValue)[0]));
+
+ std::map<ValidationEvent, int64_t> ValidationInfo;
+ for (size_t I = 0; I < ValidationCounters.size(); ++I)
+ ValidationInfo[ValidationCounters[I]] = ValCounterUopsValues[I];
+
+ Result.push_back(BenchmarkMeasure::Create(
+ "NumMicroOps", (*ExpectedCounterValue)[0], ValidationInfo));
}
return std::move(Result);
}
diff --git a/llvm/tools/llvm-exegesis/lib/UopsBenchmarkRunner.h b/llvm/tools/llvm-exegesis/lib/UopsBenchmarkRunner.h
index 337f093..ef47b7f 100644
--- a/llvm/tools/llvm-exegesis/lib/UopsBenchmarkRunner.h
+++ b/llvm/tools/llvm-exegesis/lib/UopsBenchmarkRunner.h
@@ -15,6 +15,7 @@
#define LLVM_TOOLS_LLVM_EXEGESIS_UOPSBENCHMARKRUNNER_H
#include "BenchmarkRunner.h"
+#include "Target.h"
namespace llvm {
namespace exegesis {
@@ -23,9 +24,10 @@ class UopsBenchmarkRunner : public BenchmarkRunner {
public:
UopsBenchmarkRunner(const LLVMState &State,
BenchmarkPhaseSelectorE BenchmarkPhaseSelector,
- ExecutionModeE ExecutionMode)
+ ExecutionModeE ExecutionMode,
+ ArrayRef<ValidationEvent> ValCounters)
: BenchmarkRunner(State, Benchmark::Uops, BenchmarkPhaseSelector,
- ExecutionMode) {}
+ ExecutionMode, ValCounters) {}
~UopsBenchmarkRunner() override;
static constexpr const size_t kMinNumDifferentAddresses = 6;
diff --git a/llvm/tools/llvm-exegesis/lib/X86/Target.cpp b/llvm/tools/llvm-exegesis/lib/X86/Target.cpp
index 25df89f..adb345f 100644
--- a/llvm/tools/llvm-exegesis/lib/X86/Target.cpp
+++ b/llvm/tools/llvm-exegesis/lib/X86/Target.cpp
@@ -45,6 +45,9 @@
#include <sys/mman.h>
#include <sys/syscall.h>
#include <unistd.h>
+#ifdef HAVE_LIBPFM
+#include <perfmon/perf_event.h>
+#endif // HAVE_LIBPFM
#endif
#define GET_AVAILABLE_OPCODE_CHECKER
@@ -681,6 +684,7 @@ public:
Expected<std::unique_ptr<pfm::CounterGroup>>
createCounter(StringRef CounterName, const LLVMState &State,
+ ArrayRef<const char *> ValidationCounters,
const pid_t ProcessID) const override {
// If LbrSamplingPeriod was provided, then ignore the
// CounterName because we only have one for LBR.
@@ -689,6 +693,13 @@ public:
// __linux__ (for now)
#if defined(HAVE_LIBPFM) && defined(LIBPFM_HAS_FIELD_CYCLES) && \
defined(__linux__)
+ // TODO(boomanaiden154): Add in support for using validation counters when
+ // using LBR counters.
+ if (ValidationCounters.size() > 0)
+ return llvm::make_error<llvm::StringError>(
+ "Using LBR is not currently supported with validation counters",
+ llvm::errc::invalid_argument);
+
return std::make_unique<X86LbrCounter>(
X86LbrPerfEvent(LbrSamplingPeriod));
#else
@@ -698,7 +709,8 @@ public:
llvm::errc::invalid_argument);
#endif
}
- return ExegesisTarget::createCounter(CounterName, State, ProcessID);
+ return ExegesisTarget::createCounter(CounterName, State, ValidationCounters,
+ ProcessID);
}
enum ArgumentRegisters { CodeSize = X86::R12, AuxiliaryMemoryFD = X86::R13 };
@@ -1243,7 +1255,7 @@ std::vector<MCInst>
ExegesisX86Target::configurePerfCounter(long Request, bool SaveRegisters) const {
std::vector<MCInst> ConfigurePerfCounterCode;
if (SaveRegisters)
- saveSyscallRegisters(ConfigurePerfCounterCode, 2);
+ saveSyscallRegisters(ConfigurePerfCounterCode, 3);
ConfigurePerfCounterCode.push_back(
loadImmediate(X86::RDI, 64, APInt(64, getAuxiliaryMemoryStartAddress())));
ConfigurePerfCounterCode.push_back(MCInstBuilder(X86::MOV32rm)
@@ -1255,9 +1267,13 @@ ExegesisX86Target::configurePerfCounter(long Request, bool SaveRegisters) const
.addReg(0));
ConfigurePerfCounterCode.push_back(
loadImmediate(X86::RSI, 64, APInt(64, Request)));
+#ifdef HAVE_LIBPFM
+ ConfigurePerfCounterCode.push_back(
+ loadImmediate(X86::RDX, 64, APInt(64, PERF_IOC_FLAG_GROUP)));
+#endif // HAVE_LIBPFM
generateSyscall(SYS_ioctl, ConfigurePerfCounterCode);
if (SaveRegisters)
- restoreSyscallRegisters(ConfigurePerfCounterCode, 2);
+ restoreSyscallRegisters(ConfigurePerfCounterCode, 3);
return ConfigurePerfCounterCode;
}
diff --git a/llvm/tools/llvm-exegesis/lib/X86/X86Counter.cpp b/llvm/tools/llvm-exegesis/lib/X86/X86Counter.cpp
index 96fb0f0..26be9f8 100644
--- a/llvm/tools/llvm-exegesis/lib/X86/X86Counter.cpp
+++ b/llvm/tools/llvm-exegesis/lib/X86/X86Counter.cpp
@@ -141,7 +141,7 @@ X86LbrPerfEvent::X86LbrPerfEvent(unsigned SamplingPeriod) {
}
X86LbrCounter::X86LbrCounter(pfm::PerfEvent &&NewEvent)
- : CounterGroup(std::move(NewEvent)) {
+ : CounterGroup(std::move(NewEvent), {}) {
MMappedBuffer = mmap(nullptr, kMappedBufferSize, PROT_READ | PROT_WRITE,
MAP_SHARED, getFileDescriptor(), 0);
if (MMappedBuffer == MAP_FAILED)