From abd471f6727ccf6702188f79454af9663323da5b Mon Sep 17 00:00:00 2001 From: Clement Courbet Date: Thu, 14 Jun 2018 06:57:52 +0000 Subject: [PATCH] [llvm-exegesis] Use BenchmarkResult::Instructions instead of OpcodeName 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 --- tools/llvm-exegesis/lib/Analysis.cpp | 105 +++++++++++++----- tools/llvm-exegesis/lib/BenchmarkResult.cpp | 3 +- tools/llvm-exegesis/lib/BenchmarkResult.h | 1 - tools/llvm-exegesis/lib/BenchmarkRunner.cpp | 1 - .../llvm-exegesis/BenchmarkResultTest.cpp | 3 - 5 files changed, 80 insertions(+), 33 deletions(-) diff --git a/tools/llvm-exegesis/lib/Analysis.cpp b/tools/llvm-exegesis/lib/Analysis.cpp index df353dcbf33..842790d74c7 100644 --- a/tools/llvm-exegesis/lib/Analysis.cpp +++ b/tools/llvm-exegesis/lib/Analysis.cpp @@ -20,7 +20,7 @@ static const char kCsvSep = ','; namespace { -enum EscapeTag { kEscapeCsv, kEscapeHtml }; +enum EscapeTag { kEscapeCsv, kEscapeHtml, kEscapeHtmlString }; template void writeEscaped(llvm::raw_ostream &OS, const llvm::StringRef S); @@ -56,6 +56,16 @@ void writeEscaped(llvm::raw_ostream &OS, const llvm::StringRef S) { } } +template <> +void writeEscaped(llvm::raw_ostream &OS, const llvm::StringRef S) { + for (const char C : S) { + if (C == '"') + OS << "\\\""; + else + OS << C; + } +} + } // namespace template @@ -75,6 +85,19 @@ static void writeMeasurementValue(llvm::raw_ostream &OS, const double Value) { writeEscaped(OS, llvm::formatv("{0:F}", Value).str()); } +template +static void writeSnippet(llvm::raw_ostream &OS, + const std::vector &Instructions, + const llvm::MCInstrInfo &InstrInfo, + const char* Separator) { + // FIXME: Print operands. + llvm::SmallVector Opcodes; + for (const llvm::MCInst &Instr : Instructions) { + Opcodes.push_back(InstrInfo.getName(Instr.getOpcode())); + } + writeEscaped(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(OS, Clustering_.getClusterIdForPoint(PointId)); OS << kCsvSep; - writeEscaped(OS, Point.Key.OpcodeName); + writeSnippet(OS, Point.Key.Instructions, *InstrInfo_, "; "); OS << kCsvSep; writeEscaped(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(OS, SCDesc->Name); + const auto &SchedModel = SubtargetInfo_->getSchedModel(); + const llvm::MCSchedClassDesc *const SCDesc = + SchedModel.getSchedClassDesc(SchedClassId); + writeEscaped(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(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 &Instructions, + const llvm::MCInstrInfo &InstrInfo) { + if (Instructions.empty()) + return; + writeEscaped(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 &Instructions, + const llvm::MCInstrInfo &InstrInfo) { + bool First = true; + for (const llvm::MCInst &Instr : Instructions) { + if (First) + First = false; + else + OS << " → "; + writeEscaped(OS, InstrInfo.getName(Instr.getOpcode())); + } +} + void Analysis::printSchedClassClustersHtml( const std::vector &Clusters, const SchedClass &SC, llvm::raw_ostream &OS) const { @@ -195,8 +237,19 @@ void Analysis::printSchedClassClustersHtml( OS << "
    "; for (const size_t PointId : Cluster.getPointIds()) { const auto &Point = Points[PointId]; - OS << "
  • "; - writeEscaped(OS, Point.Key.OpcodeName); + OS << "
  • (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 << " "; writeEscaped(OS, Point.Key.Config); OS << "
  • "; diff --git a/tools/llvm-exegesis/lib/BenchmarkResult.cpp b/tools/llvm-exegesis/lib/BenchmarkResult.cpp index 237a5404daa..841219cb7f2 100644 --- a/tools/llvm-exegesis/lib/BenchmarkResult.cpp +++ b/tools/llvm-exegesis/lib/BenchmarkResult.cpp @@ -140,8 +140,7 @@ struct ScalarEnumerationTraits { template <> struct MappingTraits { 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); } }; diff --git a/tools/llvm-exegesis/lib/BenchmarkResult.h b/tools/llvm-exegesis/lib/BenchmarkResult.h index 5fa9af8e9d3..c226aa0020a 100644 --- a/tools/llvm-exegesis/lib/BenchmarkResult.h +++ b/tools/llvm-exegesis/lib/BenchmarkResult.h @@ -32,7 +32,6 @@ struct BenchmarkResultContext; // Forward declaration. struct InstructionBenchmarkKey { // The LLVM opcode name. - std::string OpcodeName; // FIXME: Deprecated, use Instructions below. std::vector Instructions; // An opaque configuration, that can be used to separate several benchmarks of // the same instruction under different configurations. diff --git a/tools/llvm-exegesis/lib/BenchmarkRunner.cpp b/tools/llvm-exegesis/lib/BenchmarkRunner.cpp index 5cdaf777884..bed802d0b1e 100644 --- a/tools/llvm-exegesis/lib/BenchmarkRunner.cpp +++ b/tools/llvm-exegesis/lib/BenchmarkRunner.cpp @@ -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(); diff --git a/unittests/tools/llvm-exegesis/BenchmarkResultTest.cpp b/unittests/tools/llvm-exegesis/BenchmarkResultTest.cpp index a35ea05cb60..2b604dcdeb4 100644 --- a/unittests/tools/llvm-exegesis/BenchmarkResultTest.cpp +++ b/unittests/tools/llvm-exegesis/BenchmarkResultTest.cpp @@ -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);