Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Conversation

boomanaiden154
Copy link
Contributor

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.

This method was simply a wrapper around readOrError. All users within
the llvm-exegesis code base should have been processing an actual error
rather than using the wrapper. This patch removes the wrapper and
rewrites the users (just 1) to use the readOrError method.
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.
@llvmbot
Copy link
Collaborator

llvmbot commented Dec 31, 2023

@llvm/pr-subscribers-backend-x86

@llvm/pr-subscribers-tools-llvm-exegesis

Author: Aiden Grossman (boomanaiden154)

Changes

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.


Patch is 40.60 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/76653.diff

18 Files Affected:

  • (modified) llvm/tools/llvm-exegesis/lib/BenchmarkResult.cpp (+52)
  • (modified) llvm/tools/llvm-exegesis/lib/BenchmarkResult.h (+13-2)
  • (modified) llvm/tools/llvm-exegesis/lib/BenchmarkRunner.cpp (+37-15)
  • (modified) llvm/tools/llvm-exegesis/lib/BenchmarkRunner.h (+6-2)
  • (modified) llvm/tools/llvm-exegesis/lib/LatencyBenchmarkRunner.cpp (+35-11)
  • (modified) llvm/tools/llvm-exegesis/lib/LatencyBenchmarkRunner.h (+3)
  • (modified) llvm/tools/llvm-exegesis/lib/PerfHelper.cpp (+34-3)
  • (modified) llvm/tools/llvm-exegesis/lib/PerfHelper.h (+8-2)
  • (modified) llvm/tools/llvm-exegesis/lib/Target.cpp (+25-10)
  • (modified) llvm/tools/llvm-exegesis/lib/Target.h (+5-8)
  • (modified) llvm/tools/llvm-exegesis/lib/UopsBenchmarkRunner.cpp (+31-6)
  • (modified) llvm/tools/llvm-exegesis/lib/UopsBenchmarkRunner.h (+7-2)
  • (modified) llvm/tools/llvm-exegesis/lib/X86/Target.cpp (+10-1)
  • (modified) llvm/tools/llvm-exegesis/lib/X86/X86Counter.cpp (+1-1)
  • (modified) llvm/tools/llvm-exegesis/llvm-exegesis.cpp (+17-1)
  • (modified) llvm/unittests/tools/llvm-exegesis/ClusteringTest.cpp (+15-21)
  • (modified) llvm/unittests/tools/llvm-exegesis/Mips/BenchmarkResultTest.cpp (+6-6)
  • (modified) llvm/unittests/tools/llvm-exegesis/X86/BenchmarkResultTest.cpp (+6-6)
diff --git a/llvm/tools/llvm-exegesis/lib/BenchmarkResult.cpp b/llvm/tools/llvm-exegesis/lib/BenchmarkResult.cpp
index 02c4da11e032d6..1079df24b457b8 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,56 @@ template <> struct SequenceElementTraits<exegesis::BenchmarkMeasure> {
   static const bool flow = false;
 };
 
+const char *validationEventToString(exegesis::ValidationEvent VE) {
+  switch (VE) {
+  case exegesis::ValidationEvent::L1DCacheLoadMiss:
+    return "l1d-load-miss";
+  case exegesis::ValidationEvent::InstructionRetired:
+    return "instructions-retired";
+  case exegesis::ValidationEvent::DataTLBLoadMiss:
+    return "data-tlb-load-misses";
+  case exegesis::ValidationEvent::DataTLBStoreMiss:
+    return "data-tlb-store-misses";
+  }
+}
+
+Expected<exegesis::ValidationEvent> stringToValidationEvent(StringRef Input) {
+  if (Input == "l1d-load-miss")
+    return exegesis::ValidationEvent::L1DCacheLoadMiss;
+  else if (Input == "instructions-retired")
+    return exegesis::ValidationEvent::InstructionRetired;
+  else if (Input == "data-tlb-load-misses")
+    return exegesis::ValidationEvent::DataTLBLoadMiss;
+  else if (Input == "data-tlb-store-misses")
+    return exegesis::ValidationEvent::DataTLBStoreMiss;
+  else
+    return make_error<StringError>("Invalid validation event string",
+                                   errc::invalid_argument);
+}
+
+template <>
+struct CustomMappingTraits<
+    std::unordered_map<exegesis::ValidationEvent, int64_t>> {
+  static void
+  inputOne(IO &Io, StringRef KeyStr,
+           std::unordered_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::unordered_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 +254,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 0d08febae20cb3..f142da07e0a47d 100644
--- a/llvm/tools/llvm-exegesis/lib/BenchmarkResult.h
+++ b/llvm/tools/llvm-exegesis/lib/BenchmarkResult.h
@@ -32,6 +32,13 @@ class Error;
 
 namespace exegesis {
 
+enum ValidationEvent {
+  L1DCacheLoadMiss,
+  InstructionRetired,
+  DataTLBLoadMiss,
+  DataTLBStoreMiss
+};
+
 enum class BenchmarkPhaseSelectorE {
   PrepareSnippet,
   PrepareAndAssembleSnippet,
@@ -77,8 +84,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::unordered_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 +96,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::unordered_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 c57fce970b2139..72b3a6e97b417d 100644
--- a/llvm/tools/llvm-exegesis/lib/BenchmarkRunner.cpp
+++ b/llvm/tools/llvm-exegesis/lib/BenchmarkRunner.cpp
@@ -70,7 +70,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;
@@ -78,8 +80,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);
@@ -119,11 +121,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();
@@ -155,6 +159,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());
   }
 
@@ -265,7 +277,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) {
@@ -305,8 +319,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();
@@ -361,6 +375,14 @@ class SubProcessFunctionExecutorImpl
           return CounterValueOrErr.takeError();
         CounterValues.swap(*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
@@ -459,15 +481,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;
   }
diff --git a/llvm/tools/llvm-exegesis/lib/BenchmarkRunner.h b/llvm/tools/llvm-exegesis/lib/BenchmarkRunner.h
index d746a0f775646f..80ec2d2fcfe576 100644
--- a/llvm/tools/llvm-exegesis/lib/BenchmarkRunner.h
+++ b/llvm/tools/llvm-exegesis/lib/BenchmarkRunner.h
@@ -93,14 +93,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:
diff --git a/llvm/tools/llvm-exegesis/lib/LatencyBenchmarkRunner.cpp b/llvm/tools/llvm-exegesis/lib/LatencyBenchmarkRunner.cpp
index eda450579a5838..c2179189d5dc0a 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),
+      ValidationCounters(ValCounters) {
   assert((Mode == Benchmark::Latency || Mode == Benchmark::InverseThroughput) &&
          "invalid mode");
   ResultAggMode = ResultAgg;
@@ -72,11 +73,26 @@ 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;
+  ValCountersToRun.reserve(ValidationCounters.size());
+  for (const ValidationEvent ValEvent : ValidationCounters) {
+    auto ValCounterIt = PCI.ValidationCounters.find(ValEvent);
+    if (ValCounterIt == PCI.ValidationCounters.end())
+      return make_error<Failure>("Cannot create validation counter");
+
+    ValCountersToRun.push_back(ValCounterIt->second);
+  }
+
+  SmallVector<int64_t> ValCounterValues(ValCountersToRun.size(), -1);
   // 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 +106,15 @@ Expected<std::vector<BenchmarkMeasure>> LatencyBenchmarkRunner::runMeasurements(
         MinVariance = Variance;
       }
     }
+
+    for (size_t I = 0; I < ValCounterValues.size(); ++I)
+      ValCounterValues[I] += IterationValCounterValues[I];
   }
 
+  std::unordered_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 +135,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 fc159d7d9b5e98..2192679d87127e 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;
 
@@ -34,6 +36,7 @@ class LatencyBenchmarkRunner : public BenchmarkRunner {
 
   Benchmark::ResultAggregationModeE ResultAggMode;
   unsigned NumMeasurements;
+  SmallVector<ValidationEvent> ValidationCounters;
 };
 } // namespace exegesis
 } // namespace llvm
diff --git a/llvm/tools/llvm-exegesis/lib/PerfHelper.cpp b/llvm/tools/llvm-exegesis/lib/PerfHelper.cpp
index 314de1ec32366f..742dc0f939de58 100644
--- a/llvm/tools/llvm-exegesis/lib/PerfHelper.cpp
+++ b/llvm/tools/llvm-exegesis/lib/PerfHelper.cpp
@@ -107,15 +107,18 @@ StringRef PerfEvent::getPfmEventString() const {
   return FullQualifiedEventString;
 }
 
-Counter::Counter(PerfEvent &&E, pid_t ProcessID) : Event(std::move(E)) {
+Counter::Counter(PerfEvent &&E, std::vector<PerfEvent> &&ValEvents,
+                 pid_t ProcessID)
+    : Event(std::move(E)), ValidationEvents(std::move(ValEvents)),
+      ValidationFDs(ValidationEvents.size(), -1) {
   assert(Event.valid());
   IsDummyEvent = Event.name() == PerfEvent::DummyEventString;
   if (!IsDummyEvent)
-    initRealEvent(E, ProcessID);
+    initRealEvent(ProcessID);
 }
 
 #ifdef HAVE_LIBPFM
-void Counter::initRealEvent(const PerfEvent &E, pid_t ProcessID) {
+void Counter::initRealEvent(pid_t ProcessID) {
   const int Cpu = -1;     // measure any processor.
   const int GroupFd = -1; // no grouping of counters.
   const uint32_t Flags = 0;
@@ -131,6 +134,17 @@ void Counter::initRealEvent(const PerfEvent &E, pid_t ProcessID) {
               "pass --use-dummy-perf-counters command line option.\n";
   }
   assert(FileDescriptor != -1 && "Unable to open event");
+
+  // Setup validation counters
+  assert(ValidationFDs.size() == ValidationEvents.size());
+  for (size_t I = 0; I < ValidationEvents.size(); ++I) {
+    perf_event_attr AttrCopy = *ValidationEvents[I].attribute();
+    ValidationFDs[I] =
+        perf_event_open(&AttrCopy, ProcessID, Cpu, FileDescriptor, Flags);
+    if (ValidationFDs[I] == -1)
+      errs() << "Unable to open validation event. ERRNO: " << strerror(errno)
+             << "\n";
+  }
 }
 
 Counter::~Counter() {
@@ -165,6 +179,23 @@ Counter::readOrError(StringRef /*unused*/) const {
   return Result;
 }
 
+llvm::Expected<llvm::SmallVector<int64_t>>
+Counter::readValidationCountersOrError() const {
+  llvm::SmallVector<int64_t, 4> Result;
+  for (const int ValidationFD : ValidationFDs) {
+    int64_t Count;
+    if (!IsDummyEvent) {
+      ssize_t ReadSize = ::read(ValidationFD, &Count, sizeof(Count));
+      if (ReadSize != sizeof(Count))
+        return llvm::make_error<llvm::StringError>(
+            "Failed to read validation ounter", llvm::errc::io_error);
+    } else
+      Count = -1;
+    Result.push_back(Count);
+  }
+  return Result;
+}
+
 int Counter::numValues() const { return 1; }
 #else
 
diff --git a/llvm/tools/llvm-exegesis/lib/PerfHelper.h b/llvm/tools/llvm-exegesis/lib/PerfHelper.h
index 894aac1f197ed1..e538023905bbe6 100644
--- a/llvm/tools/llvm-exegesis/lib/PerfHelper.h
+++ b/llvm/tools/llvm-exegesis/lib/PerfHelper.h
@@ -82,7 +82,8 @@ class PerfEvent {
 class Counter {
 public:
   // event: the PerfEvent to measure.
-  explicit Counter(PerfEvent &&event, pid_t ProcessID = 0);
+  explicit Counter(PerfEvent &&event, std::vector<PerfEvent> &&ValEvents,
+                   pid_t ProcessID = 0);
 
   Counter(const Counter &) = delete;
   Counter(Counter &&other) = default;
@@ -104,6 +105,9 @@ class Counter {
   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 FileDescriptor; }
@@ -112,9 +116,11 @@ class Counter {
   PerfEvent Event;
   int FileDescriptor = -1;
   bool IsDummyEvent;
+  std::vector<PerfEvent> ValidationEvents;
+  std::vector<int> ValidationFDs;
 
 private:
-  void initRealEvent(const PerfEvent &E, pid_t ProcessID);
+  void initRealEvent(pid_t ProcessID);
 };
 
 } // namespace pfm
diff --git a/llvm/tools/llvm-exegesis/lib/Target.cpp b/llvm/tools/llvm-exegesis/lib/Target.cpp
index 20b4afb9b8f676..1279c1d422387b 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::Counter>>
 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 CounterNa...
[truncated]

Base automatically changed from users/boomanaiden154/exegesis-validation-counters-tblgen to main January 10, 2024 23:06
boomanaiden154 added a commit that referenced this pull request Jan 10, 2024
While landing #76652, I realized I messed up a rebase/merge at some
point and some of the changes I intended to land with #76652 ended up in
a different PR (#76653) instead. This patch fixes the validation
counters to how they were intended to land in #76652.
This refactoring gets things ready for validation counters where the
plan is to reuse the existing Counter infrastructure to contain event
groups that consist of a single event that is being measured along with
validation counters.
@boomanaiden154 boomanaiden154 changed the base branch from main to users/boomanaiden154/exegesis-validation-counters-countergroup January 12, 2024 08:10
…ergroup' into users/boomanaiden154/exegesis-validation-counters-implementation
Copy link

github-actions bot commented Jan 12, 2024

✅ With the latest revision this PR passed the C/C++ code formatter.

This further sets things up for validation events. Having a separate
abstraction for a configured event that is setup as a counter allows for
much easier creation of more events in the future within a single
counter group (like validation counters) without duplicating any code.
@boomanaiden154 boomanaiden154 changed the base branch from users/boomanaiden154/exegesis-validation-counters-countergroup to users/boomanaiden154/exegesis-validation-counters-configuredevent January 12, 2024 10:08
@boomanaiden154
Copy link
Contributor Author

@legrosbuffle I saw you approved the two prerequisite PRs. Do you have any additional comments on this one?

@boomanaiden154 boomanaiden154 force-pushed the users/boomanaiden154/exegesis-validation-counters-configuredevent branch from 4300851 to 3741dcd Compare January 16, 2024 09:44
Base automatically changed from users/boomanaiden154/exegesis-validation-counters-configuredevent to main January 16, 2024 09:58
@boomanaiden154 boomanaiden154 merged commit f670112 into main Jan 19, 2024
3 of 4 checks passed
@boomanaiden154 boomanaiden154 deleted the users/boomanaiden154/exegesis-validation-counters-implementation branch January 19, 2024 10:00
justinfargnoli pushed a commit to justinfargnoli/llvm-project that referenced this pull request Jan 28, 2024
While landing llvm#76652, I realized I messed up a rebase/merge at some
point and some of the changes I intended to land with llvm#76652 ended up in
a different PR (llvm#76653) instead. This patch fixes the validation
counters to how they were intended to land in llvm#76652.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants