Browse Source

[llvm-exegesis] Add options to SnippetGenerator.

Summary:
This adds a `-max-configs-per-opcode` option to limit the number of
configs per opcode.

Reviewers: gchatelet

Subscribers: tschuett, llvm-commits

Tags: #llvm

Differential Revision: https://reviews.llvm.org/D68642

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@374054 91177308-0d34-0410-b5e6-96231b3b80d8
Clement Courbet 5 years ago
parent
commit
55589bce20

+ 13 - 1
docs/CommandGuide/llvm-exegesis.rst

@@ -195,11 +195,23 @@ OPTIONS
  to specify at least one of the `-analysis-clusters-output-file=` and
  to specify at least one of the `-analysis-clusters-output-file=` and
  `-analysis-inconsistencies-output-file=`.
  `-analysis-inconsistencies-output-file=`.
 
 
-.. option:: -num-repetitions=<Number of repetition>
+.. option:: -num-repetitions=<Number of repetitions>
 
 
  Specify the number of repetitions of the asm snippet.
  Specify the number of repetitions of the asm snippet.
  Higher values lead to more accurate measurements but lengthen the benchmark.
  Higher values lead to more accurate measurements but lengthen the benchmark.
 
 
+.. option:: -max-configs-per-opcode=<value>
+
+ Specify the maximum configurations that can be generated for each opcode.
+ By default this is `1`, meaning that we assume that a single measurement is
+ enough to characterize an opcode. This might not be true of all instructions:
+ for example, the performance characteristics of the LEA instruction on X86
+ depends on the value of assigned registers and immediates. Setting a value of
+ `-max-configs-per-opcode` larger than `1` allows `llvm-exegesis` to explore
+ more configurations to discover if some register or immediate assignments
+ lead to different performance characteristics.
+
+
 .. option:: -benchmarks-file=</path/to/file>
 .. option:: -benchmarks-file=</path/to/file>
 
 
  File to read (`analysis` mode) or write (`latency`/`uops`/`inverse_throughput`
  File to read (`analysis` mode) or write (`latency`/`uops`/`inverse_throughput`

+ 24 - 0
test/tools/llvm-exegesis/X86/max-configs.test

@@ -0,0 +1,24 @@
+# RUN: llvm-exegesis -mode=latency -opcode-name=SBB8rr -max-configs-per-opcode=1 | FileCheck -check-prefixes=CHECK,CHECK1 %s
+# RUN: llvm-exegesis -mode=latency -opcode-name=SBB8rr -max-configs-per-opcode=2 | FileCheck -check-prefixes=CHECK,CHECK2 %s
+
+CHECK:      ---
+CHECK-NEXT: mode: latency
+CHECK-NEXT: key:
+CHECK-NEXT:   instructions:
+CHECK-NEXT:     SBB8rr
+CHECK-NEXT: config: ''
+CHECK-NEXT: register_initial_values:
+CHECK-DAG: - '[[REG1:[A-Z0-9]+]]=0x0'
+CHECK-LAST: ...
+
+CHECK1-NOT: SBB8rr
+
+CHECK2:      ---
+CHECK2-NEXT: mode: latency
+CHECK2-NEXT: key:
+CHECK2-NEXT:   instructions:
+CHECK2-NEXT:     SBB8rr
+CHECK2-NEXT: config: ''
+CHECK2-NEXT: register_initial_values:
+CHECK2-DAG: - '[[REG1:[A-Z0-9]+]]=0x0'
+CHECK2-LAST: ...

+ 1 - 1
tools/llvm-exegesis/lib/Latency.h

@@ -24,7 +24,7 @@ namespace exegesis {
 
 
 class LatencySnippetGenerator : public SnippetGenerator {
 class LatencySnippetGenerator : public SnippetGenerator {
 public:
 public:
-  LatencySnippetGenerator(const LLVMState &State) : SnippetGenerator(State) {}
+  using SnippetGenerator::SnippetGenerator;
   ~LatencySnippetGenerator() override;
   ~LatencySnippetGenerator() override;
 
 
   llvm::Expected<std::vector<CodeTemplate>>
   llvm::Expected<std::vector<CodeTemplate>>

+ 5 - 1
tools/llvm-exegesis/lib/SnippetGenerator.cpp

@@ -33,7 +33,8 @@ std::vector<CodeTemplate> getSingleton(CodeTemplate &&CT) {
 SnippetGeneratorFailure::SnippetGeneratorFailure(const llvm::Twine &S)
 SnippetGeneratorFailure::SnippetGeneratorFailure(const llvm::Twine &S)
     : llvm::StringError(S, llvm::inconvertibleErrorCode()) {}
     : llvm::StringError(S, llvm::inconvertibleErrorCode()) {}
 
 
-SnippetGenerator::SnippetGenerator(const LLVMState &State) : State(State) {}
+SnippetGenerator::SnippetGenerator(const LLVMState &State, const Options &Opts)
+    : State(State), Opts(Opts) {}
 
 
 SnippetGenerator::~SnippetGenerator() = default;
 SnippetGenerator::~SnippetGenerator() = default;
 
 
@@ -81,6 +82,9 @@ SnippetGenerator::generateConfigurations(
             computeRegisterInitialValues(CT.Instructions);
             computeRegisterInitialValues(CT.Instructions);
         BC.Key.Config = CT.Config;
         BC.Key.Config = CT.Config;
         Output.push_back(std::move(BC));
         Output.push_back(std::move(BC));
+        if (Output.size() >= Opts.MaxConfigsPerOpcode)
+          return Output; // Early exit if we exceeded the number of allowed
+                         // configs.
       }
       }
     }
     }
     return Output;
     return Output;

+ 6 - 1
tools/llvm-exegesis/lib/SnippetGenerator.h

@@ -51,7 +51,11 @@ public:
 // Common code for all benchmark modes.
 // Common code for all benchmark modes.
 class SnippetGenerator {
 class SnippetGenerator {
 public:
 public:
-  explicit SnippetGenerator(const LLVMState &State);
+  struct Options {
+    unsigned MaxConfigsPerOpcode = 1;
+  };
+
+  explicit SnippetGenerator(const LLVMState &State, const Options &Opts);
 
 
   virtual ~SnippetGenerator();
   virtual ~SnippetGenerator();
 
 
@@ -66,6 +70,7 @@ public:
 
 
 protected:
 protected:
   const LLVMState &State;
   const LLVMState &State;
+  const Options Opts;
 
 
 private:
 private:
   // API to be implemented by subclasses.
   // API to be implemented by subclasses.

+ 11 - 11
tools/llvm-exegesis/lib/Target.cpp

@@ -36,17 +36,17 @@ void ExegesisTarget::registerTarget(ExegesisTarget *Target) {
   FirstTarget = Target;
   FirstTarget = Target;
 }
 }
 
 
-std::unique_ptr<SnippetGenerator>
-ExegesisTarget::createSnippetGenerator(InstructionBenchmark::ModeE Mode,
-                                       const LLVMState &State) const {
+std::unique_ptr<SnippetGenerator> ExegesisTarget::createSnippetGenerator(
+    InstructionBenchmark::ModeE Mode, const LLVMState &State,
+    const SnippetGenerator::Options &Opts) const {
   switch (Mode) {
   switch (Mode) {
   case InstructionBenchmark::Unknown:
   case InstructionBenchmark::Unknown:
     return nullptr;
     return nullptr;
   case InstructionBenchmark::Latency:
   case InstructionBenchmark::Latency:
-    return createLatencySnippetGenerator(State);
+    return createLatencySnippetGenerator(State, Opts);
   case InstructionBenchmark::Uops:
   case InstructionBenchmark::Uops:
   case InstructionBenchmark::InverseThroughput:
   case InstructionBenchmark::InverseThroughput:
-    return createUopsSnippetGenerator(State);
+    return createUopsSnippetGenerator(State, Opts);
   }
   }
   return nullptr;
   return nullptr;
 }
 }
@@ -66,14 +66,14 @@ ExegesisTarget::createBenchmarkRunner(InstructionBenchmark::ModeE Mode,
   return nullptr;
   return nullptr;
 }
 }
 
 
-std::unique_ptr<SnippetGenerator>
-ExegesisTarget::createLatencySnippetGenerator(const LLVMState &State) const {
-  return std::make_unique<LatencySnippetGenerator>(State);
+std::unique_ptr<SnippetGenerator> ExegesisTarget::createLatencySnippetGenerator(
+    const LLVMState &State, const SnippetGenerator::Options &Opts) const {
+  return std::make_unique<LatencySnippetGenerator>(State, Opts);
 }
 }
 
 
-std::unique_ptr<SnippetGenerator>
-ExegesisTarget::createUopsSnippetGenerator(const LLVMState &State) const {
-  return std::make_unique<UopsSnippetGenerator>(State);
+std::unique_ptr<SnippetGenerator> ExegesisTarget::createUopsSnippetGenerator(
+    const LLVMState &State, const SnippetGenerator::Options &Opts) const {
+  return std::make_unique<UopsSnippetGenerator>(State, Opts);
 }
 }
 
 
 std::unique_ptr<BenchmarkRunner> ExegesisTarget::createLatencyBenchmarkRunner(
 std::unique_ptr<BenchmarkRunner> ExegesisTarget::createLatencyBenchmarkRunner(

+ 4 - 3
tools/llvm-exegesis/lib/Target.h

@@ -125,7 +125,8 @@ public:
   // Creates a snippet generator for the given mode.
   // Creates a snippet generator for the given mode.
   std::unique_ptr<SnippetGenerator>
   std::unique_ptr<SnippetGenerator>
   createSnippetGenerator(InstructionBenchmark::ModeE Mode,
   createSnippetGenerator(InstructionBenchmark::ModeE Mode,
-                         const LLVMState &State) const;
+                         const LLVMState &State,
+                         const SnippetGenerator::Options &Opts) const;
   // Creates a benchmark runner for the given mode.
   // Creates a benchmark runner for the given mode.
   std::unique_ptr<BenchmarkRunner>
   std::unique_ptr<BenchmarkRunner>
   createBenchmarkRunner(InstructionBenchmark::ModeE Mode,
   createBenchmarkRunner(InstructionBenchmark::ModeE Mode,
@@ -151,9 +152,9 @@ private:
   // Targets can implement their own snippet generators/benchmarks runners by
   // Targets can implement their own snippet generators/benchmarks runners by
   // implementing these.
   // implementing these.
   std::unique_ptr<SnippetGenerator> virtual createLatencySnippetGenerator(
   std::unique_ptr<SnippetGenerator> virtual createLatencySnippetGenerator(
-      const LLVMState &State) const;
+      const LLVMState &State, const SnippetGenerator::Options &Opts) const;
   std::unique_ptr<SnippetGenerator> virtual createUopsSnippetGenerator(
   std::unique_ptr<SnippetGenerator> virtual createUopsSnippetGenerator(
-      const LLVMState &State) const;
+      const LLVMState &State, const SnippetGenerator::Options &Opts) const;
   std::unique_ptr<BenchmarkRunner> virtual createLatencyBenchmarkRunner(
   std::unique_ptr<BenchmarkRunner> virtual createLatencyBenchmarkRunner(
       const LLVMState &State, InstructionBenchmark::ModeE Mode) const;
       const LLVMState &State, InstructionBenchmark::ModeE Mode) const;
   std::unique_ptr<BenchmarkRunner> virtual createUopsBenchmarkRunner(
   std::unique_ptr<BenchmarkRunner> virtual createUopsBenchmarkRunner(

+ 1 - 1
tools/llvm-exegesis/lib/Uops.h

@@ -22,7 +22,7 @@ namespace exegesis {
 
 
 class UopsSnippetGenerator : public SnippetGenerator {
 class UopsSnippetGenerator : public SnippetGenerator {
 public:
 public:
-  UopsSnippetGenerator(const LLVMState &State) : SnippetGenerator(State) {}
+  using SnippetGenerator::SnippetGenerator;
   ~UopsSnippetGenerator() override;
   ~UopsSnippetGenerator() override;
 
 
   llvm::Expected<std::vector<CodeTemplate>>
   llvm::Expected<std::vector<CodeTemplate>>

+ 8 - 6
tools/llvm-exegesis/lib/X86/Target.cpp

@@ -462,14 +462,16 @@ private:
                             sizeof(kUnavailableRegisters[0]));
                             sizeof(kUnavailableRegisters[0]));
   }
   }
 
 
-  std::unique_ptr<SnippetGenerator>
-  createLatencySnippetGenerator(const LLVMState &State) const override {
-    return std::make_unique<X86LatencySnippetGenerator>(State);
+  std::unique_ptr<SnippetGenerator> createLatencySnippetGenerator(
+      const LLVMState &State,
+      const SnippetGenerator::Options &Opts) const override {
+    return std::make_unique<X86LatencySnippetGenerator>(State, Opts);
   }
   }
 
 
-  std::unique_ptr<SnippetGenerator>
-  createUopsSnippetGenerator(const LLVMState &State) const override {
-    return std::make_unique<X86UopsSnippetGenerator>(State);
+  std::unique_ptr<SnippetGenerator> createUopsSnippetGenerator(
+      const LLVMState &State,
+      const SnippetGenerator::Options &Opts) const override {
+    return std::make_unique<X86UopsSnippetGenerator>(State, Opts);
   }
   }
 
 
   bool matchesArch(llvm::Triple::ArchType Arch) const override {
   bool matchesArch(llvm::Triple::ArchType Arch) const override {

+ 10 - 1
tools/llvm-exegesis/llvm-exegesis.cpp

@@ -95,6 +95,12 @@ static cl::opt<unsigned>
                    cl::desc("number of time to repeat the asm snippet"),
                    cl::desc("number of time to repeat the asm snippet"),
                    cl::cat(BenchmarkOptions), cl::init(10000));
                    cl::cat(BenchmarkOptions), cl::init(10000));
 
 
+static cl::opt<unsigned> MaxConfigsPerOpcode(
+    "max-configs-per-opcode",
+    cl::desc(
+        "allow to snippet generator to generate at most that many configs"),
+    cl::cat(BenchmarkOptions), cl::init(1));
+
 static cl::opt<bool> IgnoreInvalidSchedClass(
 static cl::opt<bool> IgnoreInvalidSchedClass(
     "ignore-invalid-sched-class",
     "ignore-invalid-sched-class",
     cl::desc("ignore instructions that do not define a sched class"),
     cl::desc("ignore instructions that do not define a sched class"),
@@ -214,8 +220,11 @@ generateSnippets(const LLVMState &State, unsigned Opcode,
   if (InstrDesc.isCall() || InstrDesc.isReturn())
   if (InstrDesc.isCall() || InstrDesc.isReturn())
     return make_error<Failure>("Unsupported opcode: isCall/isReturn");
     return make_error<Failure>("Unsupported opcode: isCall/isReturn");
 
 
+  SnippetGenerator::Options Options;
+  Options.MaxConfigsPerOpcode = MaxConfigsPerOpcode;
   const std::unique_ptr<SnippetGenerator> Generator =
   const std::unique_ptr<SnippetGenerator> Generator =
-      State.getExegesisTarget().createSnippetGenerator(BenchmarkMode, State);
+      State.getExegesisTarget().createSnippetGenerator(BenchmarkMode, State,
+                                                       Options);
   if (!Generator)
   if (!Generator)
     llvm::report_fatal_error("cannot create snippet generator");
     llvm::report_fatal_error("cannot create snippet generator");
   return Generator->generateConfigurations(Instr, ForbiddenRegs);
   return Generator->generateConfigurations(Instr, ForbiddenRegs);

+ 3 - 2
unittests/tools/llvm-exegesis/X86/SnippetGeneratorTest.cpp

@@ -45,7 +45,7 @@ protected:
 template <typename SnippetGeneratorT>
 template <typename SnippetGeneratorT>
 class SnippetGeneratorTest : public X86SnippetGeneratorTest {
 class SnippetGeneratorTest : public X86SnippetGeneratorTest {
 protected:
 protected:
-  SnippetGeneratorTest() : Generator(State) {}
+  SnippetGeneratorTest() : Generator(State, SnippetGenerator::Options()) {}
 
 
   std::vector<CodeTemplate> checkAndGetCodeTemplates(unsigned Opcode) {
   std::vector<CodeTemplate> checkAndGetCodeTemplates(unsigned Opcode) {
     randomGenerator().seed(0); // Initialize seed.
     randomGenerator().seed(0); // Initialize seed.
@@ -335,7 +335,8 @@ TEST_F(UopsSnippetGeneratorTest, MemoryUse) {
 
 
 class FakeSnippetGenerator : public SnippetGenerator {
 class FakeSnippetGenerator : public SnippetGenerator {
 public:
 public:
-  FakeSnippetGenerator(const LLVMState &State) : SnippetGenerator(State) {}
+  FakeSnippetGenerator(const LLVMState &State, const Options &Opts)
+      : SnippetGenerator(State, Opts) {}
 
 
   Instruction createInstruction(unsigned Opcode) {
   Instruction createInstruction(unsigned Opcode) {
     return State.getIC().getInstr(Opcode);
     return State.getIC().getInstr(Opcode);