Index: tools/llvm-exegesis/lib/Analysis.h =================================================================== --- tools/llvm-exegesis/lib/Analysis.h +++ tools/llvm-exegesis/lib/Analysis.h @@ -79,6 +79,12 @@ // 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, Index: tools/llvm-exegesis/lib/Analysis.cpp =================================================================== --- tools/llvm-exegesis/lib/Analysis.cpp +++ tools/llvm-exegesis/lib/Analysis.cpp @@ -460,36 +460,30 @@ 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 (int I = 0, E = NumMeasurements; I < E; ++I) { + StringRef Key = Representative[I].key(); uint16_t ProcResIdx = findProcResIdx(STI, Key); if (ProcResIdx > 0) { // Find the pressure on ProcResIdx `Key`. @@ -509,20 +503,41 @@ 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()); + + assert(ClusterCenterPoint.size() == SchedClassPoint.size() && + "Expected measured/sched data dimensions to match."); + return Clustering.isNeighbour(ClusterCenterPoint, SchedClassPoint, AnalysisInconsistencyEpsilonSquared_); } Index: tools/llvm-exegesis/lib/Clustering.h =================================================================== --- tools/llvm-exegesis/lib/Clustering.h +++ tools/llvm-exegesis/lib/Clustering.h @@ -156,6 +156,8 @@ void addPoint(ArrayRef Point); + bool validate(InstructionBenchmark::ModeE Mode) const; + private: // Measurement stats for the points in the SchedClassCluster. std::vector Representative; Index: tools/llvm-exegesis/lib/Clustering.cpp =================================================================== --- tools/llvm-exegesis/lib/Clustering.cpp +++ tools/llvm-exegesis/lib/Clustering.cpp @@ -363,5 +363,36 @@ 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