[llvm] f670112 - [llvm-exegesis] Add support for validation counters (#76653)

via llvm-commits llvm-commits at lists.llvm.org
Fri Jan 19 02:00:38 PST 2024


Author: Aiden Grossman
Date: 2024-01-19T02:00:33-08:00
New Revision: f670112a591c83498e348f3ff2f73f02baf8e303

URL: https://github.com/llvm/llvm-project/commit/f670112a591c83498e348f3ff2f73f02baf8e303
DIFF: https://github.com/llvm/llvm-project/commit/f670112a591c83498e348f3ff2f73f02baf8e303.diff

LOG: [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.

Added: 
    llvm/test/tools/llvm-exegesis/X86/validation-counters.asm

Modified: 
    llvm/tools/llvm-exegesis/lib/BenchmarkResult.cpp
    llvm/tools/llvm-exegesis/lib/BenchmarkResult.h
    llvm/tools/llvm-exegesis/lib/BenchmarkRunner.cpp
    llvm/tools/llvm-exegesis/lib/BenchmarkRunner.h
    llvm/tools/llvm-exegesis/lib/LatencyBenchmarkRunner.cpp
    llvm/tools/llvm-exegesis/lib/LatencyBenchmarkRunner.h
    llvm/tools/llvm-exegesis/lib/PerfHelper.cpp
    llvm/tools/llvm-exegesis/lib/PerfHelper.h
    llvm/tools/llvm-exegesis/lib/Target.cpp
    llvm/tools/llvm-exegesis/lib/Target.h
    llvm/tools/llvm-exegesis/lib/UopsBenchmarkRunner.cpp
    llvm/tools/llvm-exegesis/lib/UopsBenchmarkRunner.h
    llvm/tools/llvm-exegesis/lib/X86/Target.cpp
    llvm/tools/llvm-exegesis/lib/X86/X86Counter.cpp
    llvm/tools/llvm-exegesis/llvm-exegesis.cpp
    llvm/unittests/tools/llvm-exegesis/ClusteringTest.cpp
    llvm/unittests/tools/llvm-exegesis/Mips/BenchmarkResultTest.cpp
    llvm/unittests/tools/llvm-exegesis/X86/BenchmarkResultTest.cpp

Removed: 
    


################################################################################
diff  --git a/llvm/test/tools/llvm-exegesis/X86/validation-counters.asm b/llvm/test/tools/llvm-exegesis/X86/validation-counters.asm
new file mode 100644
index 000000000000000..7d0c940519e6ab1
--- /dev/null
+++ b/llvm/test/tools/llvm-exegesis/X86/validation-counters.asm
@@ -0,0 +1,12 @@
+# REQUIRES: exegesis-can-measure-latency, exegesis-can-measure-uops, x86_64-linux
+
+# Check that when specifying validation counters, the validation counter is
+# collected and the information is displayed in the output. Test across
+# multiple configurations that need to be wired up separately for validation
+# counter support.
+
+# RUN: llvm-exegesis -mtriple=x86_64-unknown-unknown -mode=latency -opcode-name=ADD64rr --validation-counter=instructions-retired | FileCheck %s
+# RUN: llvm-exegesis -mtriple=x86_64-unknown-unknown -mode=latency -opcode-name=ADD64rr --validation-counter=instructions-retired -execution-mode=subprocess | FileCheck %s
+# RUN: llvm-exegesis -mtriple=x86_64-unknown-unknown -mode=uops -opcode-name=ADD64rr --validation-counter=instructions-retired -execution-mode=subprocess | FileCheck %s
+
+# CHECK: instructions-retired: {{[0-9]+}}

diff  --git a/llvm/tools/llvm-exegesis/lib/BenchmarkResult.cpp b/llvm/tools/llvm-exegesis/lib/BenchmarkResult.cpp
index 02c4da11e032d66..60264ca87a988e8 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 0d08febae20cb3e..c983d6d6e00d9f5 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 eb1393ad94ff935..2b512284f9409aa 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 @@ class InProcessFunctionExecutorImpl : public BenchmarkRunner::FunctionExecutor {
       (*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 @@ class InProcessFunctionExecutorImpl : public BenchmarkRunner::FunctionExecutor {
       }
     }
 
+    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 @@ class SubProcessFunctionExecutorImpl
   }
 
   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 @@ class SubProcessFunctionExecutorImpl
     }
 
     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 @@ class SubProcessFunctionExecutorImpl
           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 @@ class SubProcessFunctionExecutorImpl
     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 d746a0f775646f4..aab4b54242e4b1a 100644
--- a/llvm/tools/llvm-exegesis/lib/BenchmarkRunner.h
+++ b/llvm/tools/llvm-exegesis/lib/BenchmarkRunner.h
@@ -38,7 +38,8 @@ class BenchmarkRunner {
 
   explicit BenchmarkRunner(const LLVMState &State, Benchmark::ModeE Mode,
                            BenchmarkPhaseSelectorE BenchmarkPhaseSelector,
-                           ExecutionModeE ExecutionMode);
+                           ExecutionModeE ExecutionMode,
+                           ArrayRef<ValidationEvent> ValCounters);
 
   virtual ~BenchmarkRunner();
 
@@ -93,14 +94,18 @@ class BenchmarkRunner {
     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 @@ class BenchmarkRunner {
   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 eda450579a5838c..eb7f70fb2b84017 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 fc159d7d9b5e984..6e21197b698b9fb 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 @@ class LatencyBenchmarkRunner : public BenchmarkRunner {
                          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 1dab8809d30280b..6b8df01e9f5440e 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 e9b73da3836287f..7d050b85c9a8c3b 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 @@ class ConfiguredEvent {
 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 @@ class CounterGroup {
   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 @@ class CounterGroup {
 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 8f1c5a157eea390..58cf1b96fea4e66 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 da6d44611eca7ce..3d6169c96502132 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 @@ class ExegesisTarget {
   // 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 @@ class ExegesisTarget {
       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 @@ class ExegesisTarget {
       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 6351fdd3345a837..d6fb59970b94af2 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 337f0936701225b..ef47b7fe8a655ec 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 25df89fb0cf31da..adb345f023a8e13 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 @@ class ExegesisX86Target : public ExegesisTarget {
 
   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 @@ class ExegesisX86Target : public ExegesisTarget {
       // __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 @@ class ExegesisX86Target : public ExegesisTarget {
           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 96fb0f085a1ee1e..26be9f846a21076 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)

diff  --git a/llvm/tools/llvm-exegesis/llvm-exegesis.cpp b/llvm/tools/llvm-exegesis/llvm-exegesis.cpp
index ffbf94ce0fcb267..2a121bec98d9553 100644
--- a/llvm/tools/llvm-exegesis/llvm-exegesis.cpp
+++ b/llvm/tools/llvm-exegesis/llvm-exegesis.cpp
@@ -268,6 +268,16 @@ static cl::opt<unsigned> BenchmarkRepeatCount(
              "before aggregating the results"),
     cl::cat(BenchmarkOptions), cl::init(30));
 
+static cl::list<ValidationEvent> ValidationCounters(
+    "validation-counter",
+    cl::desc(
+        "The name of a validation counter to run concurrently with the main "
+        "counter to validate benchmarking assumptions"),
+    cl::CommaSeparated, cl::cat(BenchmarkOptions),
+    cl::values(clEnumValN(ValidationEvent::InstructionRetired,
+                          "instructions-retired",
+                          "Count retired instructions")));
+
 static ExitOnError ExitOnErr("llvm-exegesis error: ");
 
 // Helper function that logs the error(s) and exits.
@@ -501,7 +511,7 @@ void benchmarkMain() {
   const std::unique_ptr<BenchmarkRunner> Runner =
       ExitOnErr(State.getExegesisTarget().createBenchmarkRunner(
           BenchmarkMode, State, BenchmarkPhaseSelector, ExecutionMode,
-          BenchmarkRepeatCount, ResultAggMode));
+          BenchmarkRepeatCount, ValidationCounters, ResultAggMode));
   if (!Runner) {
     ExitWithError("cannot create benchmark runner");
   }

diff  --git a/llvm/unittests/tools/llvm-exegesis/ClusteringTest.cpp b/llvm/unittests/tools/llvm-exegesis/ClusteringTest.cpp
index 25fe813502e54ab..26bb6c5d2e4c2f0 100644
--- a/llvm/unittests/tools/llvm-exegesis/ClusteringTest.cpp
+++ b/llvm/unittests/tools/llvm-exegesis/ClusteringTest.cpp
@@ -32,17 +32,17 @@ TEST(ClusteringTest, Clusters3D) {
 
   // Cluster around (x=0, y=1, z=2): points {0, 3}.
   Points[0].Measurements = {
-      {"x", 0.01, 0.0}, {"y", 1.02, 0.0}, {"z", 1.98, 0.0}};
+      {"x", 0.01, 0.0, {}}, {"y", 1.02, 0.0, {}}, {"z", 1.98, 0.0, {}}};
   Points[3].Measurements = {
-      {"x", -0.01, 0.0}, {"y", 1.02, 0.0}, {"z", 1.98, 0.0}};
+      {"x", -0.01, 0.0, {}}, {"y", 1.02, 0.0, {}}, {"z", 1.98, 0.0, {}}};
   // Cluster around (x=1, y=1, z=2): points {1, 4}.
   Points[1].Measurements = {
-      {"x", 1.01, 0.0}, {"y", 1.02, 0.0}, {"z", 1.98, 0.0}};
+      {"x", 1.01, 0.0, {}}, {"y", 1.02, 0.0, {}}, {"z", 1.98, 0.0, {}}};
   Points[4].Measurements = {
-      {"x", 0.99, 0.0}, {"y", 1.02, 0.0}, {"z", 1.98, 0.0}};
+      {"x", 0.99, 0.0, {}}, {"y", 1.02, 0.0, {}}, {"z", 1.98, 0.0, {}}};
   // Cluster around (x=0, y=0, z=0): points {5}, marked as noise.
   Points[5].Measurements = {
-      {"x", 0.0, 0.0}, {"y", 0.01, 0.0}, {"z", -0.02, 0.0}};
+      {"x", 0.0, 0.0, {}}, {"y", 0.01, 0.0, {}}, {"z", -0.02, 0.0, {}}};
   // Error cluster: points {2}
   Points[2].Error = "oops";
 
@@ -71,8 +71,8 @@ TEST(ClusteringTest, Clusters3D) {
 TEST(ClusteringTest, Clusters3D_InvalidSize) {
   std::vector<Benchmark> Points(6);
   Points[0].Measurements = {
-      {"x", 0.01, 0.0}, {"y", 1.02, 0.0}, {"z", 1.98, 0.0}};
-  Points[1].Measurements = {{"y", 1.02, 0.0}, {"z", 1.98, 0.0}};
+      {"x", 0.01, 0.0, {}}, {"y", 1.02, 0.0, {}}, {"z", 1.98, 0.0, {}}};
+  Points[1].Measurements = {{"y", 1.02, 0.0, {}}, {"z", 1.98, 0.0, {}}};
   auto Error =
       BenchmarkClustering::create(
           Points, BenchmarkClustering::ModeE::Dbscan, 2, 0.25)
@@ -83,8 +83,8 @@ TEST(ClusteringTest, Clusters3D_InvalidSize) {
 
 TEST(ClusteringTest, Clusters3D_InvalidOrder) {
   std::vector<Benchmark> Points(6);
-  Points[0].Measurements = {{"x", 0.01, 0.0}, {"y", 1.02, 0.0}};
-  Points[1].Measurements = {{"y", 1.02, 0.0}, {"x", 1.98, 0.0}};
+  Points[0].Measurements = {{"x", 0.01, 0.0, {}}, {"y", 1.02, 0.0, {}}};
+  Points[1].Measurements = {{"y", 1.02, 0.0, {}}, {"x", 1.98, 0.0, {}}};
   auto Error =
       BenchmarkClustering::create(
           Points, BenchmarkClustering::ModeE::Dbscan, 2, 0.25)
@@ -110,12 +110,9 @@ TEST(ClusteringTest, Ordering) {
 TEST(ClusteringTest, Ordering1) {
   std::vector<Benchmark> Points(3);
 
-  Points[0].Measurements = {
-      {"x", 0.0, 0.0}};
-  Points[1].Measurements = {
-      {"x", 1.0, 0.0}};
-  Points[2].Measurements = {
-      {"x", 2.0, 0.0}};
+  Points[0].Measurements = {{"x", 0.0, 0.0, {}}};
+  Points[1].Measurements = {{"x", 1.0, 0.0, {}}};
+  Points[2].Measurements = {{"x", 2.0, 0.0, {}}};
 
   auto Clustering = BenchmarkClustering::create(
       Points, BenchmarkClustering::ModeE::Dbscan, 2, 1.1);
@@ -127,12 +124,9 @@ TEST(ClusteringTest, Ordering1) {
 TEST(ClusteringTest, Ordering2) {
   std::vector<Benchmark> Points(3);
 
-  Points[0].Measurements = {
-      {"x", 0.0, 0.0}};
-  Points[1].Measurements = {
-      {"x", 2.0, 0.0}};
-  Points[2].Measurements = {
-      {"x", 1.0, 0.0}};
+  Points[0].Measurements = {{"x", 0.0, 0.0, {}}};
+  Points[1].Measurements = {{"x", 2.0, 0.0, {}}};
+  Points[2].Measurements = {{"x", 1.0, 0.0, {}}};
 
   auto Clustering = BenchmarkClustering::create(
       Points, BenchmarkClustering::ModeE::Dbscan, 2, 1.1);

diff  --git a/llvm/unittests/tools/llvm-exegesis/Mips/BenchmarkResultTest.cpp b/llvm/unittests/tools/llvm-exegesis/Mips/BenchmarkResultTest.cpp
index 201e0a8e7acce26..3d02b8f648411d7 100644
--- a/llvm/unittests/tools/llvm-exegesis/Mips/BenchmarkResultTest.cpp
+++ b/llvm/unittests/tools/llvm-exegesis/Mips/BenchmarkResultTest.cpp
@@ -65,8 +65,8 @@ TEST_F(MipsBenchmarkResultTest, WriteToAndReadFromDisk) {
   ToDisk.CpuName = "cpu_name";
   ToDisk.LLVMTriple = "llvm_triple";
   ToDisk.NumRepetitions = 1;
-  ToDisk.Measurements.push_back(BenchmarkMeasure{"a", 1, 1});
-  ToDisk.Measurements.push_back(BenchmarkMeasure{"b", 2, 2});
+  ToDisk.Measurements.push_back(BenchmarkMeasure{"a", 1, 1, {}});
+  ToDisk.Measurements.push_back(BenchmarkMeasure{"b", 2, 2, {}});
   ToDisk.Error = "error";
   ToDisk.Info = "info";
 
@@ -124,10 +124,10 @@ TEST_F(MipsBenchmarkResultTest, WriteToAndReadFromDisk) {
 
 TEST_F(MipsBenchmarkResultTest, PerInstructionStats) {
   PerInstructionStats Stats;
-  Stats.push(BenchmarkMeasure{"a", 0.5, 0.0});
-  Stats.push(BenchmarkMeasure{"a", 1.5, 0.0});
-  Stats.push(BenchmarkMeasure{"a", -1.0, 0.0});
-  Stats.push(BenchmarkMeasure{"a", 0.0, 0.0});
+  Stats.push(BenchmarkMeasure{"a", 0.5, 0.0, {}});
+  Stats.push(BenchmarkMeasure{"a", 1.5, 0.0, {}});
+  Stats.push(BenchmarkMeasure{"a", -1.0, 0.0, {}});
+  Stats.push(BenchmarkMeasure{"a", 0.0, 0.0, {}});
   EXPECT_EQ(Stats.min(), -1.0);
   EXPECT_EQ(Stats.max(), 1.5);
   EXPECT_EQ(Stats.avg(), 0.25); // (0.5+1.5-1.0+0.0) / 4

diff  --git a/llvm/unittests/tools/llvm-exegesis/X86/BenchmarkResultTest.cpp b/llvm/unittests/tools/llvm-exegesis/X86/BenchmarkResultTest.cpp
index 616f7bac54bc43c..fafd08131dffc60 100644
--- a/llvm/unittests/tools/llvm-exegesis/X86/BenchmarkResultTest.cpp
+++ b/llvm/unittests/tools/llvm-exegesis/X86/BenchmarkResultTest.cpp
@@ -84,8 +84,8 @@ TEST(BenchmarkResultTest, WriteToAndReadFromDisk) {
   ToDisk.CpuName = "cpu_name";
   ToDisk.LLVMTriple = "llvm_triple";
   ToDisk.NumRepetitions = 1;
-  ToDisk.Measurements.push_back(BenchmarkMeasure{"a", 1, 1});
-  ToDisk.Measurements.push_back(BenchmarkMeasure{"b", 2, 2});
+  ToDisk.Measurements.push_back(BenchmarkMeasure{"a", 1, 1, {}});
+  ToDisk.Measurements.push_back(BenchmarkMeasure{"b", 2, 2, {}});
   ToDisk.Error = "error";
   ToDisk.Info = "info";
 
@@ -162,10 +162,10 @@ TEST(BenchmarkResultTest, WriteToAndReadFromDisk) {
 
 TEST(BenchmarkResultTest, PerInstructionStats) {
   PerInstructionStats Stats;
-  Stats.push(BenchmarkMeasure{"a", 0.5, 0.0});
-  Stats.push(BenchmarkMeasure{"a", 1.5, 0.0});
-  Stats.push(BenchmarkMeasure{"a", -1.0, 0.0});
-  Stats.push(BenchmarkMeasure{"a", 0.0, 0.0});
+  Stats.push(BenchmarkMeasure{"a", 0.5, 0.0, {}});
+  Stats.push(BenchmarkMeasure{"a", 1.5, 0.0, {}});
+  Stats.push(BenchmarkMeasure{"a", -1.0, 0.0, {}});
+  Stats.push(BenchmarkMeasure{"a", 0.0, 0.0, {}});
   EXPECT_EQ(Stats.min(), -1.0);
   EXPECT_EQ(Stats.max(), 1.5);
   EXPECT_EQ(Stats.avg(), 0.25); // (0.5+1.5-1.0+0.0) / 4


        


More information about the llvm-commits mailing list