[llvm] r332601 - [llvm-exegesis] Analysis: detect clustering inconsistencies.

Clement Courbet via llvm-commits llvm-commits at lists.llvm.org
Thu May 17 05:25:18 PDT 2018


Author: courbet
Date: Thu May 17 05:25:18 2018
New Revision: 332601

URL: http://llvm.org/viewvc/llvm-project?rev=332601&view=rev
Log:
[llvm-exegesis] Analysis: detect clustering inconsistencies.

Summary:
Warn on instructions that should have the same performance
characteristics according to the sched model but actually
differ in their benchmarks.

Next step: Make the display nicer to browse, I was thinking maybe html.

Reviewers: gchatelet

Subscribers: tschuett, llvm-commits

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

Modified:
    llvm/trunk/tools/llvm-exegesis/lib/Analysis.cpp
    llvm/trunk/tools/llvm-exegesis/lib/Analysis.h
    llvm/trunk/tools/llvm-exegesis/llvm-exegesis.cpp

Modified: llvm/trunk/tools/llvm-exegesis/lib/Analysis.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-exegesis/lib/Analysis.cpp?rev=332601&r1=332600&r2=332601&view=diff
==============================================================================
--- llvm/trunk/tools/llvm-exegesis/lib/Analysis.cpp (original)
+++ llvm/trunk/tools/llvm-exegesis/lib/Analysis.cpp Thu May 17 05:25:18 2018
@@ -10,6 +10,7 @@
 #include "Analysis.h"
 #include "BenchmarkResult.h"
 #include "llvm/Support/FormatVariadic.h"
+#include <unordered_set>
 #include <vector>
 
 namespace exegesis {
@@ -34,26 +35,36 @@ static void writeCsvEscaped(llvm::raw_os
 
 // Prints a row representing an instruction, along with scheduling info and
 // point coordinates (measurements).
-void Analysis::printInstructionRow(const size_t ClusterId, const size_t PointId,
+void Analysis::printInstructionRow(const bool PrintSchedClass,
+                                   const size_t PointId,
                                    llvm::raw_ostream &OS) const {
   const InstructionBenchmark &Point = Clustering_.getPoints()[PointId];
-
-  OS << ClusterId << kCsvSep;
+  const auto &ClusterId = Clustering_.getClusterIdForPoint(PointId);
+  if (ClusterId.isNoise())
+    OS << "[noise]";
+  else if (ClusterId.isError())
+    OS << "[error]";
+  else
+    OS << ClusterId.getId();
+  OS << kCsvSep;
   writeCsvEscaped(OS, Point.Key.OpcodeName);
   OS << kCsvSep;
   writeCsvEscaped(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();
+  if (PrintSchedClass) {
+    OS << kCsvSep;
+    const auto OpcodeIt = MnemonicToOpcode_.find(Point.Key.OpcodeName);
+    if (OpcodeIt != MnemonicToOpcode_.end()) {
+      const unsigned SchedClassId =
+          InstrInfo_->get(OpcodeIt->second).getSchedClass();
 #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
-    const auto &SchedModel = SubtargetInfo_->getSchedModel();
-    const llvm::MCSchedClassDesc *const SCDesc =
-       SchedModel.getSchedClassDesc(SchedClassId);
-    writeCsvEscaped(OS, SCDesc->Name);
+      const auto &SchedModel = SubtargetInfo_->getSchedModel();
+      const llvm::MCSchedClassDesc *const SCDesc =
+          SchedModel.getSchedClassDesc(SchedClassId);
+      writeCsvEscaped(OS, SCDesc->Name);
 #else
-    OS << SchedClassId;
+      OS << SchedClassId;
 #endif
+    }
   }
   // FIXME: Print the sched class once InstructionBenchmark separates key into
   // (mnemonic, mode, opaque).
@@ -72,8 +83,8 @@ Analysis::Analysis(const llvm::Target &T
 
   InstrInfo_.reset(Target.createMCInstrInfo());
   const InstructionBenchmark &FirstPoint = Clustering.getPoints().front();
-  SubtargetInfo_.reset(Target.createMCSubtargetInfo(
-      FirstPoint.LLVMTriple, FirstPoint.CpuName, ""));
+  SubtargetInfo_.reset(Target.createMCSubtargetInfo(FirstPoint.LLVMTriple,
+                                                    FirstPoint.CpuName, ""));
 
   // Build an index of mnemonic->opcode.
   for (int I = 0, E = InstrInfo_->getNumOpcodes(); I < E; ++I)
@@ -94,14 +105,66 @@ llvm::Error Analysis::printClusters(llvm
   OS << "\n";
 
   // Write the points.
-  const auto& Clusters = Clustering_.getValidClusters();
+  const auto &Clusters = Clustering_.getValidClusters();
   for (size_t I = 0, E = Clusters.size(); I < E; ++I) {
     for (const size_t PointId : Clusters[I].PointIndices) {
-      printInstructionRow(I, PointId, OS);
+      printInstructionRow(/*PrintSchedClass*/ true, PointId, OS);
     }
     OS << "\n\n";
   }
   return llvm::Error::success();
 }
+
+std::unordered_map<unsigned, std::vector<size_t>>
+Analysis::makePointsPerSchedClass() const {
+  std::unordered_map<unsigned, std::vector<size_t>> PointsPerSchedClass;
+  const auto &Points = Clustering_.getPoints();
+  for (size_t PointId = 0, E = Points.size(); PointId < E; ++PointId) {
+    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);
+  }
+  return PointsPerSchedClass;
+}
+
+llvm::Error
+Analysis::printSchedClassInconsistencies(llvm::raw_ostream &OS) const {
+  // All the points in a scheduling class should be in the same cluster.
+  // Print any scheduling class for which this is not the case.
+  for (const auto &SchedClassAndPoints : makePointsPerSchedClass()) {
+    std::unordered_set<size_t> ClustersForSchedClass;
+    for (const size_t PointId : SchedClassAndPoints.second) {
+      const auto &ClusterId = Clustering_.getClusterIdForPoint(PointId);
+      if (!ClusterId.isValid())
+        continue; // Ignore noise and errors.
+      ClustersForSchedClass.insert(ClusterId.getId());
+    }
+    if (ClustersForSchedClass.size() <= 1)
+      continue; // Nothing weird.
+
+    OS << "\nSched Class ";
+#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
+    const auto &SchedModel = SubtargetInfo_->getSchedModel();
+    const llvm::MCSchedClassDesc *const SCDesc =
+        SchedModel.getSchedClassDesc(SchedClassAndPoints.first);
+    OS << SCDesc->Name;
+#else
+    OS << SchedClassAndPoints.first;
+#endif
+    OS << " contains instructions with distinct performance "
+          "characteristics, falling into "
+       << ClustersForSchedClass.size() << " clusters:\n";
+    for (const size_t PointId : SchedClassAndPoints.second) {
+      printInstructionRow(/*PrintSchedClass*/ false, PointId, OS);
+    }
+  }
+  return llvm::Error::success();
+}
 
 } // namespace exegesis

Modified: llvm/trunk/tools/llvm-exegesis/lib/Analysis.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-exegesis/lib/Analysis.h?rev=332601&r1=332600&r2=332601&view=diff
==============================================================================
--- llvm/trunk/tools/llvm-exegesis/lib/Analysis.h (original)
+++ llvm/trunk/tools/llvm-exegesis/lib/Analysis.h Thu May 17 05:25:18 2018
@@ -18,8 +18,8 @@
 #include "Clustering.h"
 #include "llvm/MC/MCInstrInfo.h"
 #include "llvm/MC/MCSubtargetInfo.h"
-#include "llvm/Support/TargetRegistry.h"
 #include "llvm/Support/Error.h"
+#include "llvm/Support/TargetRegistry.h"
 #include "llvm/Support/raw_ostream.h"
 #include <string>
 #include <unordered_map>
@@ -29,19 +29,28 @@ namespace exegesis {
 // A helper class to analyze benchmark results for a target.
 class Analysis {
 public:
-  Analysis(const llvm::Target& Target, const InstructionBenchmarkClustering &Clustering);
+  Analysis(const llvm::Target &Target,
+           const InstructionBenchmarkClustering &Clustering);
 
   // Prints a csv of instructions for each cluster.
   llvm::Error printClusters(llvm::raw_ostream &OS) const;
 
- private:
-   void printInstructionRow(size_t ClusterId,  size_t PointId,
-                                   llvm::raw_ostream &OS) const;
-
-   const InstructionBenchmarkClustering & Clustering_;
-   std::unique_ptr<llvm::MCSubtargetInfo> SubtargetInfo_;
-   std::unique_ptr<llvm::MCInstrInfo> InstrInfo_;
-   std::unordered_map<std::string, unsigned> MnemonicToOpcode_;
+  // Find potential errors in the scheduling information given measurements.
+  llvm::Error printSchedClassInconsistencies(llvm::raw_ostream &OS) const;
+
+private:
+  void printInstructionRow(bool PrintSchedClass, size_t PointId,
+                           llvm::raw_ostream &OS) const;
+
+  // Builds a map of Sched Class -> indices of points that belong to the sched
+  // class.
+  std::unordered_map<unsigned, std::vector<size_t>>
+  makePointsPerSchedClass() const;
+
+  const InstructionBenchmarkClustering &Clustering_;
+  std::unique_ptr<llvm::MCSubtargetInfo> SubtargetInfo_;
+  std::unique_ptr<llvm::MCInstrInfo> InstrInfo_;
+  std::unordered_map<std::string, unsigned> MnemonicToOpcode_;
 };
 
 } // namespace exegesis

Modified: llvm/trunk/tools/llvm-exegesis/llvm-exegesis.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-exegesis/llvm-exegesis.cpp?rev=332601&r1=332600&r2=332601&view=diff
==============================================================================
--- llvm/trunk/tools/llvm-exegesis/llvm-exegesis.cpp (original)
+++ llvm/trunk/tools/llvm-exegesis/llvm-exegesis.cpp Thu May 17 05:25:18 2018
@@ -160,6 +160,9 @@ void analysisMain() {
 
   if (auto Err = Analyzer.printClusters(ClustersOS))
     llvm::report_fatal_error(std::move(Err));
+
+  if (auto Err = Analyzer.printSchedClassInconsistencies(llvm::outs()))
+    llvm::report_fatal_error(std::move(Err));
 }
 
 } // namespace exegesis




More information about the llvm-commits mailing list