diff options
| author | Clement Courbet <courbet@google.com> | 2018-10-03 11:50:25 +0000 |
|---|---|---|
| committer | Clement Courbet <courbet@google.com> | 2018-10-03 11:50:25 +0000 |
| commit | d5a39553ff3eafaab675e581d973f700a4d7a6b5 (patch) | |
| tree | 8ca841ccd22b9b3fe08efcb98bc6e300e7a85a20 /llvm/tools/llvm-exegesis/lib/Analysis.cpp | |
| parent | d934032e48cad89d506880fce22e9df6cb66487a (diff) | |
| download | bcm5719-llvm-d5a39553ff3eafaab675e581d973f700a4d7a6b5.tar.gz bcm5719-llvm-d5a39553ff3eafaab675e581d973f700a4d7a6b5.zip | |
[llvm-exegesis] Resolve variant classes in analysis.
Summary: See PR38884.
Reviewers: gchatelet
Subscribers: tschuett, RKSimon, llvm-commits
Differential Revision: https://reviews.llvm.org/D52825
llvm-svn: 343680
Diffstat (limited to 'llvm/tools/llvm-exegesis/lib/Analysis.cpp')
| -rw-r--r-- | llvm/tools/llvm-exegesis/lib/Analysis.cpp | 134 |
1 files changed, 82 insertions, 52 deletions
diff --git a/llvm/tools/llvm-exegesis/lib/Analysis.cpp b/llvm/tools/llvm-exegesis/lib/Analysis.cpp index d852f24be33..eca4a354c6c 100644 --- a/llvm/tools/llvm-exegesis/lib/Analysis.cpp +++ b/llvm/tools/llvm-exegesis/lib/Analysis.cpp @@ -19,6 +19,16 @@ namespace exegesis { static const char kCsvSep = ','; +static unsigned resolveSchedClassId(const llvm::MCSubtargetInfo &STI, + unsigned SchedClassId, + const llvm::MCInst &MCI) { + const auto &SM = STI.getSchedModel(); + while (SchedClassId && SM.getSchedClassDesc(SchedClassId)->isVariant()) + SchedClassId = + STI.resolveVariantSchedClass(SchedClassId, &MCI, SM.getProcessorID()); + return SchedClassId; +} + namespace { enum EscapeTag { kEscapeCsv, kEscapeHtml, kEscapeHtmlString }; @@ -126,11 +136,12 @@ void Analysis::printInstructionRowCsv(const size_t PointId, writeEscaped<kEscapeCsv>(OS, Point.Key.Config); OS << kCsvSep; 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::MCInst &MCI = Point.Key.Instructions[0]; + const unsigned SchedClassId = resolveSchedClassId( + *SubtargetInfo_, InstrInfo_->get(MCI.getOpcode()).getSchedClass(), MCI); + +#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) const llvm::MCSchedClassDesc *const SCDesc = SchedModel.getSchedClassDesc(SchedClassId); writeEscaped<kEscapeCsv>(OS, SCDesc->Name); @@ -193,21 +204,43 @@ Analysis::run<Analysis::PrintClusters>(llvm::raw_ostream &OS) const { return llvm::Error::success(); } -std::unordered_map<unsigned, std::vector<size_t>> +Analysis::ResolvedSchedClassAndPoints::ResolvedSchedClassAndPoints( + ResolvedSchedClass &&RSC) + : RSC(std::move(RSC)) {} + +std::vector<Analysis::ResolvedSchedClassAndPoints> Analysis::makePointsPerSchedClass() const { - std::unordered_map<unsigned, std::vector<size_t>> PointsPerSchedClass; + std::vector<ResolvedSchedClassAndPoints> Entries; + // Maps SchedClassIds to index in result. + std::unordered_map<unsigned, size_t> SchedClassIdToIndex; 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; 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); + // FIXME: we should be using the tuple of classes for instructions in the + // snippet as key. + const llvm::MCInst &MCI = Point.Key.Instructions[0]; + unsigned SchedClassId = InstrInfo_->get(MCI.getOpcode()).getSchedClass(); + const bool WasVariant = SchedClassId && SubtargetInfo_->getSchedModel() + .getSchedClassDesc(SchedClassId) + ->isVariant(); + SchedClassId = resolveSchedClassId(*SubtargetInfo_, SchedClassId, MCI); + const auto IndexIt = SchedClassIdToIndex.find(SchedClassId); + if (IndexIt == SchedClassIdToIndex.end()) { + // Create a new entry. + SchedClassIdToIndex.emplace(SchedClassId, Entries.size()); + ResolvedSchedClassAndPoints Entry( + ResolvedSchedClass(*SubtargetInfo_, SchedClassId, WasVariant)); + Entry.PointIds.push_back(PointId); + Entries.push_back(std::move(Entry)); + } else { + // Append to the existing entry. + Entries[IndexIt->second].PointIds.push_back(PointId); + } } - return PointsPerSchedClass; + return Entries; } // Uops repeat the same opcode over again. Just show this opcode and show the @@ -239,8 +272,8 @@ writeLatencySnippetHtml(llvm::raw_ostream &OS, } void Analysis::printSchedClassClustersHtml( - const std::vector<SchedClassCluster> &Clusters, const SchedClass &SC, - llvm::raw_ostream &OS) const { + const std::vector<SchedClassCluster> &Clusters, + const ResolvedSchedClass &RSC, llvm::raw_ostream &OS) const { const auto &Points = Clustering_.getPoints(); OS << "<table class=\"sched-class-clusters\">"; OS << "<tr><th>ClusterId</th><th>Opcode/Config</th>"; @@ -254,7 +287,7 @@ void Analysis::printSchedClassClustersHtml( OS << "</tr>"; for (const SchedClassCluster &Cluster : Clusters) { OS << "<tr class=\"" - << (Cluster.measurementsMatch(*SubtargetInfo_, SC, Clustering_) + << (Cluster.measurementsMatch(*SubtargetInfo_, RSC, Clustering_) ? "good-cluster" : "bad-cluster") << "\"><td>"; @@ -369,12 +402,17 @@ getNonRedundantWriteProcRes(const llvm::MCSchedClassDesc &SCDesc, return Result; } -Analysis::SchedClass::SchedClass(const llvm::MCSchedClassDesc &SD, - const llvm::MCSubtargetInfo &STI) - : SCDesc(&SD), - NonRedundantWriteProcRes(getNonRedundantWriteProcRes(SD, STI)), +Analysis::ResolvedSchedClass::ResolvedSchedClass( + const llvm::MCSubtargetInfo &STI, unsigned ResolvedSchedClassId, + bool WasVariant) + : SCDesc(STI.getSchedModel().getSchedClassDesc(ResolvedSchedClassId)), + WasVariant(WasVariant), + NonRedundantWriteProcRes(getNonRedundantWriteProcRes(*SCDesc, STI)), IdealizedProcResPressure(computeIdealizedProcResPressure( - STI.getSchedModel(), NonRedundantWriteProcRes)) {} + STI.getSchedModel(), NonRedundantWriteProcRes)) { + assert((SCDesc == nullptr || !SCDesc->isVariant()) && + "ResolvedSchedClass should never be variant"); +} void Analysis::SchedClassCluster::addPoint( size_t PointId, const InstructionBenchmarkClustering &Clustering) { @@ -407,7 +445,7 @@ static unsigned findProcResIdx(const llvm::MCSubtargetInfo &STI, } bool Analysis::SchedClassCluster::measurementsMatch( - const llvm::MCSubtargetInfo &STI, const SchedClass &SC, + const llvm::MCSubtargetInfo &STI, const ResolvedSchedClass &RSC, const InstructionBenchmarkClustering &Clustering) const { const size_t NumMeasurements = Representative.size(); std::vector<BenchmarkMeasure> ClusterCenterPoint(NumMeasurements); @@ -424,9 +462,9 @@ bool Analysis::SchedClassCluster::measurementsMatch( } // Find the latency. SchedClassPoint[0].PerInstructionValue = 0.0; - for (unsigned I = 0; I < SC.SCDesc->NumWriteLatencyEntries; ++I) { + for (unsigned I = 0; I < RSC.SCDesc->NumWriteLatencyEntries; ++I) { const llvm::MCWriteLatencyEntry *const WLE = - STI.getWriteLatencyEntry(SC.SCDesc, I); + STI.getWriteLatencyEntry(RSC.SCDesc, I); SchedClassPoint[0].PerInstructionValue = std::max<double>(SchedClassPoint[0].PerInstructionValue, WLE->Cycles); } @@ -438,17 +476,17 @@ bool Analysis::SchedClassCluster::measurementsMatch( if (ProcResIdx > 0) { // Find the pressure on ProcResIdx `Key`. const auto ProcResPressureIt = - std::find_if(SC.IdealizedProcResPressure.begin(), - SC.IdealizedProcResPressure.end(), + std::find_if(RSC.IdealizedProcResPressure.begin(), + RSC.IdealizedProcResPressure.end(), [ProcResIdx](const std::pair<uint16_t, float> &WPR) { return WPR.first == ProcResIdx; }); SchedClassPoint[I].PerInstructionValue = - ProcResPressureIt == SC.IdealizedProcResPressure.end() + ProcResPressureIt == RSC.IdealizedProcResPressure.end() ? 0.0 : ProcResPressureIt->second; } else if (Key == "NumMicroOps") { - SchedClassPoint[I].PerInstructionValue = SC.SCDesc->NumMicroOps; + SchedClassPoint[I].PerInstructionValue = RSC.SCDesc->NumMicroOps; } else { llvm::errs() << "expected `key` to be either a ProcResIdx or a ProcRes " "name, got " @@ -465,26 +503,25 @@ bool Analysis::SchedClassCluster::measurementsMatch( return Clustering.isNeighbour(ClusterCenterPoint, SchedClassPoint); } -void Analysis::printSchedClassDescHtml(const SchedClass &SC, +void Analysis::printSchedClassDescHtml(const ResolvedSchedClass &RSC, llvm::raw_ostream &OS) const { OS << "<table class=\"sched-class-desc\">"; OS << "<tr><th>Valid</th><th>Variant</th><th>NumMicroOps</th><th>Latency</" "th><th>WriteProcRes</th><th title=\"This is the idealized unit " "resource (port) pressure assuming ideal distribution\">Idealized " "Resource Pressure</th></tr>"; - if (SC.SCDesc->isValid()) { + if (RSC.SCDesc->isValid()) { const auto &SM = SubtargetInfo_->getSchedModel(); OS << "<tr><td>✔</td>"; - OS << "<td>" << (SC.SCDesc->isVariant() ? "✔" : "✕") - << "</td>"; - OS << "<td>" << SC.SCDesc->NumMicroOps << "</td>"; + OS << "<td>" << (RSC.WasVariant ? "✔" : "✕") << "</td>"; + OS << "<td>" << RSC.SCDesc->NumMicroOps << "</td>"; // Latencies. OS << "<td><ul>"; - for (int I = 0, E = SC.SCDesc->NumWriteLatencyEntries; I < E; ++I) { + for (int I = 0, E = RSC.SCDesc->NumWriteLatencyEntries; I < E; ++I) { const auto *const Entry = - SubtargetInfo_->getWriteLatencyEntry(SC.SCDesc, I); + SubtargetInfo_->getWriteLatencyEntry(RSC.SCDesc, I); OS << "<li>" << Entry->Cycles; - if (SC.SCDesc->NumWriteLatencyEntries > 1) { + if (RSC.SCDesc->NumWriteLatencyEntries > 1) { // Dismabiguate if more than 1 latency. OS << " (WriteResourceID " << Entry->WriteResourceID << ")"; } @@ -493,7 +530,7 @@ void Analysis::printSchedClassDescHtml(const SchedClass &SC, OS << "</ul></td>"; // WriteProcRes. OS << "<td><ul>"; - for (const auto &WPR : SC.NonRedundantWriteProcRes) { + for (const auto &WPR : RSC.NonRedundantWriteProcRes) { OS << "<li><span class=\"mono\">"; writeEscaped<kEscapeHtml>(OS, SM.getProcResource(WPR.ProcResourceIdx)->Name); @@ -502,7 +539,7 @@ void Analysis::printSchedClassDescHtml(const SchedClass &SC, OS << "</ul></td>"; // Idealized port pressure. OS << "<td><ul>"; - for (const auto &Pressure : SC.IdealizedProcResPressure) { + for (const auto &Pressure : RSC.IdealizedProcResPressure) { OS << "<li><span class=\"mono\">"; writeEscaped<kEscapeHtml>(OS, SubtargetInfo_->getSchedModel() .getProcResource(Pressure.first) @@ -598,19 +635,12 @@ llvm::Error Analysis::run<Analysis::PrintSchedClassInconsistencies>( writeEscaped<kEscapeHtml>(OS, FirstPoint.CpuName); OS << "</span></h3>"; - for (const auto &SchedClassAndPoints : makePointsPerSchedClass()) { - const auto SchedClassId = SchedClassAndPoints.first; - const std::vector<size_t> &SchedClassPoints = SchedClassAndPoints.second; - const auto &SchedModel = SubtargetInfo_->getSchedModel(); - const llvm::MCSchedClassDesc *const SCDesc = - SchedModel.getSchedClassDesc(SchedClassId); - if (!SCDesc) + for (const auto &RSCAndPoints : makePointsPerSchedClass()) { + if (!RSCAndPoints.RSC.SCDesc) continue; - const SchedClass SC(*SCDesc, *SubtargetInfo_); - // Bucket sched class points into sched class clusters. std::vector<SchedClassCluster> SchedClassClusters; - for (const size_t PointId : SchedClassPoints) { + for (const size_t PointId : RSCAndPoints.PointIds) { const auto &ClusterId = Clustering_.getClusterIdForPoint(PointId); if (!ClusterId.isValid()) continue; // Ignore noise and errors. FIXME: take noise into account ? @@ -629,24 +659,24 @@ llvm::Error Analysis::run<Analysis::PrintSchedClassInconsistencies>( // Print any scheduling class that has at least one cluster that does not // match the checked-in data. if (std::all_of(SchedClassClusters.begin(), SchedClassClusters.end(), - [this, &SC](const SchedClassCluster &C) { - return C.measurementsMatch(*SubtargetInfo_, SC, - Clustering_); + [this, &RSCAndPoints](const SchedClassCluster &C) { + return C.measurementsMatch(*SubtargetInfo_, + RSCAndPoints.RSC, Clustering_); })) continue; // Nothing weird. OS << "<div class=\"inconsistency\"><p>Sched Class <span " "class=\"sched-class-name\">"; #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) - writeEscaped<kEscapeHtml>(OS, SCDesc->Name); + writeEscaped<kEscapeHtml>(OS, RSCAndPoints.RSC.SCDesc->Name); #else OS << SchedClassId; #endif OS << "</span> contains instructions whose performance characteristics do" " not match that of LLVM:</p>"; - printSchedClassClustersHtml(SchedClassClusters, SC, OS); + printSchedClassClustersHtml(SchedClassClusters, RSCAndPoints.RSC, OS); OS << "<p>llvm SchedModel data:</p>"; - printSchedClassDescHtml(SC, OS); + printSchedClassDescHtml(RSCAndPoints.RSC, OS); OS << "</div>"; } |

