[NFC][llvm-exegesis] `BenchmarkRunner`: split `runConfiguration()` into `getRunnableC...
authorRoman Lebedev <lebedev.ri@gmail.com>
Sun, 18 Dec 2022 01:15:04 +0000 (04:15 +0300)
committerRoman Lebedev <lebedev.ri@gmail.com>
Sun, 18 Dec 2022 01:23:20 +0000 (04:23 +0300)
We can run as many `getRunnableConfiguration()` in parallel as we want,
but `runConfiguration()` must be run *completely* standalone from everything.
This is a step towards enabling threading.

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

index db7d49f..eb90f43 100644 (file)
@@ -150,10 +150,15 @@ Expected<SmallString<0>> BenchmarkRunner::assembleSnippet(
   return Buffer;
 }
 
-Expected<InstructionBenchmark> BenchmarkRunner::runConfiguration(
-    const BenchmarkCode &BC, unsigned NumRepetitions, unsigned LoopBodySize,
-    const SnippetRepetitor &Repetitor, bool DumpObjectToDisk) const {
-  InstructionBenchmark InstrBenchmark;
+Expected<BenchmarkRunner::RunnableConfiguration>
+BenchmarkRunner::getRunnableConfiguration(const BenchmarkCode &BC,
+                                          unsigned NumRepetitions,
+                                          unsigned LoopBodySize,
+                                          const SnippetRepetitor &Repetitor,
+                                          bool DumpObjectToDisk) const {
+  RunnableConfiguration RC;
+
+  InstructionBenchmark &InstrBenchmark = RC.InstrBenchmark;
   InstrBenchmark.Mode = Mode;
   InstrBenchmark.CpuName = std::string(State.getTargetMachine().getTargetCPU());
   InstrBenchmark.LLVMTriple =
@@ -183,7 +188,6 @@ Expected<InstructionBenchmark> BenchmarkRunner::runConfiguration(
 
   // Assemble NumRepetitions instructions repetitions of the snippet for
   // measurements.
-  object::OwningBinary<object::ObjectFile> ObjectFile;
   {
     auto Snippet = assembleSnippet(BC, Repetitor, InstrBenchmark.NumRepetitions,
                                    LoopBodySize);
@@ -193,18 +197,26 @@ Expected<InstructionBenchmark> BenchmarkRunner::runConfiguration(
       auto ObjectFilePath = writeObjectFile(*Snippet);
       if (Error E = ObjectFilePath.takeError()) {
         InstrBenchmark.Error = toString(std::move(E));
-        return InstrBenchmark;
+        return std::move(RC);
       }
       outs() << "Check generated assembly with: /usr/bin/objdump -d "
              << *ObjectFilePath << "\n";
     }
-    ObjectFile = getObjectFromBuffer(*Snippet);
+    RC.ObjectFile = getObjectFromBuffer(*Snippet);
   }
 
+  return std::move(RC);
+}
+
+Expected<InstructionBenchmark>
+BenchmarkRunner::runConfiguration(RunnableConfiguration &&RC) const {
+  InstructionBenchmark &InstrBenchmark = RC.InstrBenchmark;
+  object::OwningBinary<object::ObjectFile> &ObjectFile = RC.ObjectFile;
+
   if (BenchmarkSkipMeasurements) {
     InstrBenchmark.Error =
         "in --skip-measurements mode, actual measurements skipped.";
-    return InstrBenchmark;
+    return std::move(InstrBenchmark);
   }
 
   const FunctionExecutorImpl Executor(State, std::move(ObjectFile),
@@ -214,19 +226,20 @@ Expected<InstructionBenchmark> BenchmarkRunner::runConfiguration(
     if (!E.isA<SnippetCrash>())
       return std::move(E);
     InstrBenchmark.Error = toString(std::move(E));
-    return InstrBenchmark;
+    return std::move(InstrBenchmark);
   }
   assert(InstrBenchmark.NumRepetitions > 0 && "invalid NumRepetitions");
   for (BenchmarkMeasure &BM : *NewMeasurements) {
     // Scale the measurements by instruction.
     BM.PerInstructionValue /= InstrBenchmark.NumRepetitions;
     // Scale the measurements by snippet.
-    BM.PerSnippetValue *= static_cast<double>(Instructions.size()) /
-                          InstrBenchmark.NumRepetitions;
+    BM.PerSnippetValue *=
+        static_cast<double>(InstrBenchmark.Key.Instructions.size()) /
+        InstrBenchmark.NumRepetitions;
   }
   InstrBenchmark.Measurements = std::move(*NewMeasurements);
 
-  return InstrBenchmark;
+  return std::move(InstrBenchmark);
 }
 
 Expected<std::string> BenchmarkRunner::writeObjectFile(StringRef Buffer) const {
index dd935c3..5bd9bc2 100644 (file)
@@ -40,10 +40,32 @@ public:
 
   virtual ~BenchmarkRunner();
 
+  class RunnableConfiguration {
+    friend class BenchmarkRunner;
+
+  public:
+    ~RunnableConfiguration() = default;
+    RunnableConfiguration(RunnableConfiguration &&) = default;
+
+    RunnableConfiguration(const RunnableConfiguration &) = delete;
+    RunnableConfiguration &operator=(RunnableConfiguration &&) = delete;
+    RunnableConfiguration &operator=(const RunnableConfiguration &) = delete;
+
+  private:
+    RunnableConfiguration() = default;
+
+    InstructionBenchmark InstrBenchmark;
+    object::OwningBinary<object::ObjectFile> ObjectFile;
+  };
+
+  Expected<RunnableConfiguration>
+  getRunnableConfiguration(const BenchmarkCode &Configuration,
+                           unsigned NumRepetitions, unsigned LoopUnrollFactor,
+                           const SnippetRepetitor &Repetitor,
+                           bool DumpObjectToDisk) const;
+
   Expected<InstructionBenchmark>
-  runConfiguration(const BenchmarkCode &Configuration, unsigned NumRepetitions,
-                   unsigned LoopUnrollFactor, const SnippetRepetitor &Repetitor,
-                   bool DumpObjectToDisk) const;
+  runConfiguration(RunnableConfiguration &&RC) const;
 
   // Scratch space to run instructions that touch memory.
   struct ScratchSpace {
index e74fb15..02d3b90 100644 (file)
@@ -421,8 +421,10 @@ void benchmarkMain() {
 
     for (const std::unique_ptr<const SnippetRepetitor> &Repetitor :
          Repetitors) {
-      AllResults.emplace_back(ExitOnErr(Runner->runConfiguration(
-          Conf, NumRepetitions, LoopBodySize, *Repetitor, DumpObjectToDisk)));
+      auto RC = ExitOnErr(Runner->getRunnableConfiguration(
+          Conf, NumRepetitions, LoopBodySize, *Repetitor, DumpObjectToDisk));
+      AllResults.emplace_back(
+          ExitOnErr(Runner->runConfiguration(std::move(RC))));
     }
     InstructionBenchmark &Result = AllResults.front();