From b8fb15d4122b04d620c1d4a89449b6eba2f4b0c0 Mon Sep 17 00:00:00 2001 From: Roman Lebedev Date: Fri, 29 Mar 2019 11:36:08 +0000 Subject: [PATCH] [NFC][llvm-exegesis] Refactor Analysis::SchedClassCluster::measurementsMatch() Summary: The diff looks scary but it really isn't: 1. I moved the check for the number of measurements into `SchedClassClusterCentroid::validate()` 2. While there, added a check that we can only have a single inverse throughput measurement. I missed that when adding it initially. 3. In `Analysis::SchedClassCluster::measurementsMatch()` is called with the current LLVM values from schedule class and the values from Centroid. 3.1. The values from centroid we can already get from `SchedClassClusterCentroid::getAsPoint()`. This isn't 100% a NFC, because previously for inverse throughput we used `min()`. I have asked whether i have done that correctly in https://reviews.llvm.org/D57647?id=184939#inline-510384 but did not hear back. I think `avg()` should be used too, thus it is a fix. 3.2. Finally, refactor the computation of the LLVM-specified values into `Analysis::SchedClassCluster::getSchedClassPoint()` I will need that function for [[ https://bugs.llvm.org/show_bug.cgi?id=41275 | PR41275 ]] Reviewers: courbet, gchatelet Reviewed By: courbet Subscribers: tschuett, jdoerfert, llvm-commits Tags: #llvm Differential Revision: https://reviews.llvm.org/D59951 llvm-svn: 357245 --- llvm/tools/llvm-exegesis/lib/Analysis.cpp | 82 ++++++++++++++++++----------- llvm/tools/llvm-exegesis/lib/Analysis.h | 6 +++ llvm/tools/llvm-exegesis/lib/Clustering.cpp | 31 +++++++++++ llvm/tools/llvm-exegesis/lib/Clustering.h | 2 + 4 files changed, 90 insertions(+), 31 deletions(-) diff --git a/llvm/tools/llvm-exegesis/lib/Analysis.cpp b/llvm/tools/llvm-exegesis/lib/Analysis.cpp index 9281744..632ba81 100644 --- a/llvm/tools/llvm-exegesis/lib/Analysis.cpp +++ b/llvm/tools/llvm-exegesis/lib/Analysis.cpp @@ -460,36 +460,33 @@ static unsigned findProcResIdx(const llvm::MCSubtargetInfo &STI, return 0; } -bool Analysis::SchedClassCluster::measurementsMatch( - const llvm::MCSubtargetInfo &STI, const ResolvedSchedClass &RSC, - const InstructionBenchmarkClustering &Clustering, - const double AnalysisInconsistencyEpsilonSquared_) const { - ArrayRef Representative = Centroid.getStats(); +std::vector Analysis::SchedClassCluster::getSchedClassPoint( + InstructionBenchmark::ModeE Mode, const llvm::MCSubtargetInfo &STI, + const ResolvedSchedClass &RSC, + ArrayRef Representative) const { const size_t NumMeasurements = Representative.size(); - std::vector ClusterCenterPoint(NumMeasurements); + std::vector SchedClassPoint(NumMeasurements); - // Latency case. - assert(!Clustering.getPoints().empty()); - const InstructionBenchmark::ModeE Mode = Clustering.getPoints()[0].Mode; + if (Mode == InstructionBenchmark::Latency) { - if (NumMeasurements != 1) { - llvm::errs() - << "invalid number of measurements in latency mode: expected 1, got " - << NumMeasurements << "\n"; - return false; - } + assert(NumMeasurements == 1 && "Latency is a single measure."); + BenchmarkMeasure &LatencyMeasure = SchedClassPoint[0]; + // Find the latency. - SchedClassPoint[0].PerInstructionValue = 0.0; + LatencyMeasure.PerInstructionValue = 0.0; + for (unsigned I = 0; I < RSC.SCDesc->NumWriteLatencyEntries; ++I) { const llvm::MCWriteLatencyEntry *const WLE = STI.getWriteLatencyEntry(RSC.SCDesc, I); - SchedClassPoint[0].PerInstructionValue = - std::max(SchedClassPoint[0].PerInstructionValue, WLE->Cycles); + LatencyMeasure.PerInstructionValue = + std::max(LatencyMeasure.PerInstructionValue, WLE->Cycles); } - ClusterCenterPoint[0].PerInstructionValue = Representative[0].avg(); } else if (Mode == InstructionBenchmark::Uops) { - for (int I = 0, E = Representative.size(); I < E; ++I) { - const auto Key = Representative[I].key(); + for (const auto &I : llvm::zip(SchedClassPoint, Representative)) { + BenchmarkMeasure &Measure = std::get<0>(I); + const PerInstructionStats &Stats = std::get<1>(I); + + StringRef Key = Stats.key(); uint16_t ProcResIdx = findProcResIdx(STI, Key); if (ProcResIdx > 0) { // Find the pressure on ProcResIdx `Key`. @@ -499,30 +496,53 @@ bool Analysis::SchedClassCluster::measurementsMatch( [ProcResIdx](const std::pair &WPR) { return WPR.first == ProcResIdx; }); - SchedClassPoint[I].PerInstructionValue = + Measure.PerInstructionValue = ProcResPressureIt == RSC.IdealizedProcResPressure.end() ? 0.0 : ProcResPressureIt->second; } else if (Key == "NumMicroOps") { - SchedClassPoint[I].PerInstructionValue = RSC.SCDesc->NumMicroOps; + Measure.PerInstructionValue = RSC.SCDesc->NumMicroOps; } else { llvm::errs() << "expected `key` to be either a ProcResIdx or a ProcRes " "name, got " << Key << "\n"; - return false; + return {}; } - ClusterCenterPoint[I].PerInstructionValue = Representative[I].avg(); } } else if (Mode == InstructionBenchmark::InverseThroughput) { - for (int I = 0, E = Representative.size(); I < E; ++I) { - SchedClassPoint[I].PerInstructionValue = - MCSchedModel::getReciprocalThroughput(STI, *RSC.SCDesc); - ClusterCenterPoint[I].PerInstructionValue = Representative[I].min(); - } + assert(NumMeasurements == 1 && "Inverse Throughput is a single measure."); + BenchmarkMeasure &RThroughputMeasure = SchedClassPoint[0]; + + RThroughputMeasure.PerInstructionValue = + MCSchedModel::getReciprocalThroughput(STI, *RSC.SCDesc); } else { llvm_unreachable("unimplemented measurement matching mode"); - return false; } + + return SchedClassPoint; +} + +bool Analysis::SchedClassCluster::measurementsMatch( + const llvm::MCSubtargetInfo &STI, const ResolvedSchedClass &RSC, + const InstructionBenchmarkClustering &Clustering, + const double AnalysisInconsistencyEpsilonSquared_) const { + assert(!Clustering.getPoints().empty()); + const InstructionBenchmark::ModeE Mode = Clustering.getPoints()[0].Mode; + + if (!Centroid.validate(Mode)) + return false; + + const std::vector ClusterCenterPoint = + Centroid.getAsPoint(); + + const std::vector SchedClassPoint = + getSchedClassPoint(Mode, STI, RSC, Centroid.getStats()); + if (SchedClassPoint.empty()) + return false; // In Uops mode validate() may not be enough. + + assert(ClusterCenterPoint.size() == SchedClassPoint.size() && + "Expected measured/sched data dimensions to match."); + return Clustering.isNeighbour(ClusterCenterPoint, SchedClassPoint, AnalysisInconsistencyEpsilonSquared_); } diff --git a/llvm/tools/llvm-exegesis/lib/Analysis.h b/llvm/tools/llvm-exegesis/lib/Analysis.h index e38f460..36a3479 100644 --- a/llvm/tools/llvm-exegesis/lib/Analysis.h +++ b/llvm/tools/llvm-exegesis/lib/Analysis.h @@ -79,6 +79,12 @@ private: // Return the cluster centroid. const SchedClassClusterCentroid &getCentroid() const { return Centroid; } + std::vector + getSchedClassPoint(InstructionBenchmark::ModeE Mode, + const llvm::MCSubtargetInfo &STI, + const ResolvedSchedClass &SC, + ArrayRef Representative) const; + // Returns true if the cluster representative measurements match that of SC. bool measurementsMatch(const llvm::MCSubtargetInfo &STI, diff --git a/llvm/tools/llvm-exegesis/lib/Clustering.cpp b/llvm/tools/llvm-exegesis/lib/Clustering.cpp index 2a8cc45..398bbf7 100644 --- a/llvm/tools/llvm-exegesis/lib/Clustering.cpp +++ b/llvm/tools/llvm-exegesis/lib/Clustering.cpp @@ -363,5 +363,36 @@ std::vector SchedClassClusterCentroid::getAsPoint() const { return ClusterCenterPoint; } +bool SchedClassClusterCentroid::validate( + InstructionBenchmark::ModeE Mode) const { + size_t NumMeasurements = Representative.size(); + switch (Mode) { + case InstructionBenchmark::Latency: + if (NumMeasurements != 1) { + llvm::errs() + << "invalid number of measurements in latency mode: expected 1, got " + << NumMeasurements << "\n"; + return false; + } + break; + case InstructionBenchmark::Uops: + // Can have many measurements. + break; + case InstructionBenchmark::InverseThroughput: + if (NumMeasurements != 1) { + llvm::errs() << "invalid number of measurements in inverse throughput " + "mode: expected 1, got " + << NumMeasurements << "\n"; + return false; + } + break; + default: + llvm_unreachable("unimplemented measurement matching mode"); + return false; + } + + return true; // All good. +} + } // namespace exegesis } // namespace llvm diff --git a/llvm/tools/llvm-exegesis/lib/Clustering.h b/llvm/tools/llvm-exegesis/lib/Clustering.h index e57a46d..18ef30f 100644 --- a/llvm/tools/llvm-exegesis/lib/Clustering.h +++ b/llvm/tools/llvm-exegesis/lib/Clustering.h @@ -156,6 +156,8 @@ public: void addPoint(ArrayRef Point); + bool validate(InstructionBenchmark::ModeE Mode) const; + private: // Measurement stats for the points in the SchedClassCluster. std::vector Representative; -- 2.7.4