[llvm-exegesis] Use BenchmarkResult::Instructions instead of OpcodeName
authorClement Courbet <courbet@google.com>
Thu, 14 Jun 2018 06:57:52 +0000 (06:57 +0000)
committerClement Courbet <courbet@google.com>
Thu, 14 Jun 2018 06:57:52 +0000 (06:57 +0000)
Summary:
Get rid of OpcodeName.

To remove the opcode name from an old file:
```
cat old_file | sed '/opcode_name.*/d'
```

Reviewers: gchatelet

Subscribers: tschuett, llvm-commits

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

llvm-svn: 334691

llvm/tools/llvm-exegesis/lib/Analysis.cpp
llvm/tools/llvm-exegesis/lib/BenchmarkResult.cpp
llvm/tools/llvm-exegesis/lib/BenchmarkResult.h
llvm/tools/llvm-exegesis/lib/BenchmarkRunner.cpp
llvm/unittests/tools/llvm-exegesis/BenchmarkResultTest.cpp

index df353dc..842790d 100644 (file)
@@ -20,7 +20,7 @@ static const char kCsvSep = ',';
 
 namespace {
 
-enum EscapeTag { kEscapeCsv, kEscapeHtml };
+enum EscapeTag { kEscapeCsv, kEscapeHtml, kEscapeHtmlString };
 
 template <EscapeTag Tag>
 void writeEscaped(llvm::raw_ostream &OS, const llvm::StringRef S);
@@ -56,6 +56,16 @@ void writeEscaped<kEscapeHtml>(llvm::raw_ostream &OS, const llvm::StringRef S) {
   }
 }
 
+template <>
+void writeEscaped<kEscapeHtmlString>(llvm::raw_ostream &OS, const llvm::StringRef S) {
+  for (const char C : S) {
+    if (C == '"')
+      OS << "\\\"";
+    else
+      OS << C;
+  }
+}
+
 } // namespace
 
 template <EscapeTag Tag>
@@ -75,6 +85,19 @@ static void writeMeasurementValue(llvm::raw_ostream &OS, const double Value) {
   writeEscaped<Tag>(OS, llvm::formatv("{0:F}", Value).str());
 }
 
+template <EscapeTag Tag>
+static void writeSnippet(llvm::raw_ostream &OS,
+                         const std::vector<llvm::MCInst> &Instructions,
+                         const llvm::MCInstrInfo &InstrInfo,
+                         const char* Separator) {
+  // FIXME: Print operands.
+  llvm::SmallVector<llvm::StringRef, 3> Opcodes;
+  for (const llvm::MCInst &Instr : Instructions) {
+    Opcodes.push_back(InstrInfo.getName(Instr.getOpcode()));
+  }
+  writeEscaped<Tag>(OS, llvm::join(Opcodes, Separator));
+}
+
 // Prints a row representing an instruction, along with scheduling info and
 // point coordinates (measurements).
 void Analysis::printInstructionRowCsv(const size_t PointId,
@@ -82,25 +105,22 @@ void Analysis::printInstructionRowCsv(const size_t PointId,
   const InstructionBenchmark &Point = Clustering_.getPoints()[PointId];
   writeClusterId<kEscapeCsv>(OS, Clustering_.getClusterIdForPoint(PointId));
   OS << kCsvSep;
-  writeEscaped<kEscapeCsv>(OS, Point.Key.OpcodeName);
+  writeSnippet<kEscapeCsv>(OS, Point.Key.Instructions, *InstrInfo_, "; ");
   OS << kCsvSep;
   writeEscaped<kEscapeCsv>(OS, Point.Key.Config);
   OS << kCsvSep;
-  const auto OpcodeIt = MnemonicToOpcode_.find(Point.Key.OpcodeName);
-  if (OpcodeIt != MnemonicToOpcode_.end()) {
-    const unsigned SchedClassId =
-        InstrInfo_->get(OpcodeIt->second).getSchedClass();
+  assert(!Point.Key.Instructions.empty());
+  // FIXME: Resolve variant classes.
+  const unsigned SchedClassId =
+      InstrInfo_->get(Point.Key.Instructions[0].getOpcode()).getSchedClass();
 #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
-    const auto &SchedModel = SubtargetInfo_->getSchedModel();
-    const llvm::MCSchedClassDesc *const SCDesc =
-        SchedModel.getSchedClassDesc(SchedClassId);
-    writeEscaped<kEscapeCsv>(OS, SCDesc->Name);
+  const auto &SchedModel = SubtargetInfo_->getSchedModel();
+  const llvm::MCSchedClassDesc *const SCDesc =
+      SchedModel.getSchedClassDesc(SchedClassId);
+  writeEscaped<kEscapeCsv>(OS, SCDesc->Name);
 #else
-    OS << SchedClassId;
+  OS << SchedClassId;
 #endif
-  }
-  // FIXME: Print the sched class once InstructionBenchmark separates key into
-  // (mnemonic, mode, opaque).
   for (const auto &Measurement : Point.Measurements) {
     OS << kCsvSep;
     writeMeasurementValue<kEscapeCsv>(OS, Measurement.Value);
@@ -118,10 +138,6 @@ Analysis::Analysis(const llvm::Target &Target,
   const InstructionBenchmark &FirstPoint = Clustering.getPoints().front();
   SubtargetInfo_.reset(Target.createMCSubtargetInfo(FirstPoint.LLVMTriple,
                                                     FirstPoint.CpuName, ""));
-
-  // Build an index of mnemonic->opcode.
-  for (int I = 0, E = InstrInfo_->getNumOpcodes(); I < E; ++I)
-    MnemonicToOpcode_.emplace(InstrInfo_->getName(I), I);
 }
 
 template <>
@@ -158,16 +174,42 @@ Analysis::makePointsPerSchedClass() const {
     const InstructionBenchmark &Point = Points[PointId];
     if (!Point.Error.empty())
       continue;
-    const auto OpcodeIt = MnemonicToOpcode_.find(Point.Key.OpcodeName);
-    if (OpcodeIt == MnemonicToOpcode_.end())
-      continue;
-    const unsigned SchedClassId =
-        InstrInfo_->get(OpcodeIt->second).getSchedClass();
-    PointsPerSchedClass[SchedClassId].push_back(PointId);
+    assert(!Point.Key.Instructions.empty());
+    const auto Opcode = Point.Key.Instructions[0].getOpcode();
+    // FIXME: Resolve variant classes.
+    PointsPerSchedClass[InstrInfo_->get(Opcode).getSchedClass()].push_back(
+        PointId);
   }
   return PointsPerSchedClass;
 }
 
+// Uops repeat the same opcode over again. Just show this opcode and show the
+// whole snippet only on hover.
+static void writeUopsSnippetHtml(llvm::raw_ostream &OS,
+                                 const std::vector<llvm::MCInst> &Instructions,
+                                 const llvm::MCInstrInfo &InstrInfo) {
+  if (Instructions.empty())
+    return;
+  writeEscaped<kEscapeHtml>(OS, InstrInfo.getName(Instructions[0].getOpcode()));
+  if (Instructions.size() > 1)
+    OS << " (x" << Instructions.size() << ")";
+}
+
+// Latency tries to find a serial path. Just show the opcode path and show the
+// whole snippet only on hover.
+static void writeLatencySnippetHtml(llvm::raw_ostream &OS,
+                                 const std::vector<llvm::MCInst> &Instructions,
+                                 const llvm::MCInstrInfo &InstrInfo) {
+  bool First = true;
+  for (const llvm::MCInst &Instr : Instructions) {
+    if (First)
+      First = false;
+    else
+      OS << " &rarr; ";
+    writeEscaped<kEscapeHtml>(OS, InstrInfo.getName(Instr.getOpcode()));
+  }
+}
+
 void Analysis::printSchedClassClustersHtml(
     const std::vector<SchedClassCluster> &Clusters, const SchedClass &SC,
     llvm::raw_ostream &OS) const {
@@ -195,8 +237,19 @@ void Analysis::printSchedClassClustersHtml(
     OS << "</td><td><ul>";
     for (const size_t PointId : Cluster.getPointIds()) {
       const auto &Point = Points[PointId];
-      OS << "<li><span class=\"mono\">";
-      writeEscaped<kEscapeHtml>(OS, Point.Key.OpcodeName);
+      OS << "<li><span class=\"mono\" title=\"";
+      writeSnippet<kEscapeHtmlString>(OS, Point.Key.Instructions, *InstrInfo_, "\n");
+      OS << "\">";
+      switch (Point.Mode) {
+        case InstructionBenchmark::Latency:
+          writeLatencySnippetHtml(OS, Point.Key.Instructions, *InstrInfo_);
+          break;
+        case InstructionBenchmark::Uops:
+          writeUopsSnippetHtml(OS, Point.Key.Instructions, *InstrInfo_);
+          break;
+        default:
+          llvm_unreachable("invalid mode");
+      }
       OS << "</span> <span class=\"mono\">";
       writeEscaped<kEscapeHtml>(OS, Point.Key.Config);
       OS << "</span></li>";
index 237a540..841219c 100644 (file)
@@ -140,8 +140,7 @@ struct ScalarEnumerationTraits<exegesis::InstructionBenchmark::ModeE> {
 
 template <> struct MappingTraits<exegesis::InstructionBenchmarkKey> {
   static void mapping(IO &Io, exegesis::InstructionBenchmarkKey &Obj) {
-    Io.mapRequired("opcode_name", Obj.OpcodeName);
-    Io.mapOptional("instructions", Obj.Instructions);
+    Io.mapRequired("instructions", Obj.Instructions);
     Io.mapOptional("config", Obj.Config);
   }
 };
index 5fa9af8..c226aa0 100644 (file)
@@ -32,7 +32,6 @@ struct BenchmarkResultContext; // Forward declaration.
 
 struct InstructionBenchmarkKey {
   // The LLVM opcode name.
-  std::string OpcodeName; // FIXME: Deprecated, use Instructions below.
   std::vector<llvm::MCInst> Instructions;
   // An opaque configuration, that can be used to separate several benchmarks of
   // the same instruction under different configurations.
index 5cdaf77..bed802d 100644 (file)
@@ -62,7 +62,6 @@ InstructionBenchmark
 BenchmarkRunner::runOne(const BenchmarkConfiguration &Configuration,
                         unsigned Opcode, unsigned NumRepetitions) const {
   InstructionBenchmark InstrBenchmark;
-  InstrBenchmark.Key.OpcodeName = State.getInstrInfo().getName(Opcode);
   InstrBenchmark.Mode = getMode();
   InstrBenchmark.CpuName = State.getCpuName();
   InstrBenchmark.LLVMTriple = State.getTriple();
index a35ea05..2b604dc 100644 (file)
@@ -63,7 +63,6 @@ TEST(BenchmarkResultTest, WriteToAndReadFromDisk) {
 
   InstructionBenchmark ToDisk;
 
-  ToDisk.Key.OpcodeName = "name";
   ToDisk.Key.Instructions.push_back(llvm::MCInstBuilder(kInstrId)
                                         .addReg(kReg1Id)
                                         .addReg(kReg2Id)
@@ -91,7 +90,6 @@ TEST(BenchmarkResultTest, WriteToAndReadFromDisk) {
     const auto FromDisk =
         ExitOnErr(InstructionBenchmark::readYaml(Ctx, Filename));
 
-    EXPECT_EQ(FromDisk.Key.OpcodeName, ToDisk.Key.OpcodeName);
     EXPECT_THAT(FromDisk.Key.Instructions,
                 Pointwise(EqMCInst(), ToDisk.Key.Instructions));
     EXPECT_EQ(FromDisk.Key.Config, ToDisk.Key.Config);
@@ -109,7 +107,6 @@ TEST(BenchmarkResultTest, WriteToAndReadFromDisk) {
         ExitOnErr(InstructionBenchmark::readYamls(Ctx, Filename));
     ASSERT_EQ(FromDiskVector.size(), size_t{1});
     const auto FromDisk = FromDiskVector[0];
-    EXPECT_EQ(FromDisk.Key.OpcodeName, ToDisk.Key.OpcodeName);
     EXPECT_THAT(FromDisk.Key.Instructions,
                 Pointwise(EqMCInst(), ToDisk.Key.Instructions));
     EXPECT_EQ(FromDisk.Key.Config, ToDisk.Key.Config);