171 lines · cpp
1//===-- LatencyBenchmarkRunner.cpp ------------------------------*- C++ -*-===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8 9#include "LatencyBenchmarkRunner.h"10 11#include "BenchmarkRunner.h"12#include "Target.h"13#include "llvm/ADT/Twine.h"14#include "llvm/Support/Error.h"15#include <algorithm>16#include <cmath>17 18#define DEBUG_TYPE "exegesis-latency-benchmarkrunner"19 20namespace llvm {21namespace exegesis {22 23LatencyBenchmarkRunner::LatencyBenchmarkRunner(24 const LLVMState &State, Benchmark::ModeE Mode,25 BenchmarkPhaseSelectorE BenchmarkPhaseSelector,26 Benchmark::ResultAggregationModeE ResultAgg, ExecutionModeE ExecutionMode,27 ArrayRef<ValidationEvent> ValCounters, unsigned BenchmarkRepeatCount)28 : BenchmarkRunner(State, Mode, BenchmarkPhaseSelector, ExecutionMode,29 ValCounters) {30 assert((Mode == Benchmark::Latency || Mode == Benchmark::InverseThroughput) &&31 "invalid mode");32 ResultAggMode = ResultAgg;33 NumMeasurements = BenchmarkRepeatCount;34}35 36LatencyBenchmarkRunner::~LatencyBenchmarkRunner() = default;37 38static double computeVariance(const SmallVector<int64_t, 4> &Values) {39 if (Values.empty())40 return 0.0;41 double Sum = std::accumulate(Values.begin(), Values.end(), 0.0);42 43 const double Mean = Sum / Values.size();44 double Ret = 0;45 for (const auto &V : Values) {46 double Delta = V - Mean;47 Ret += Delta * Delta;48 }49 return Ret / Values.size();50}51 52static int64_t findMin(const SmallVector<int64_t, 4> &Values) {53 if (Values.empty())54 return 0;55 return *llvm::min_element(Values);56}57 58static int64_t findMax(const SmallVector<int64_t, 4> &Values) {59 if (Values.empty())60 return 0;61 return *llvm::max_element(Values);62}63 64static int64_t findMean(const SmallVector<int64_t, 4> &Values) {65 if (Values.empty())66 return 0;67 return std::accumulate(Values.begin(), Values.end(), 0.0) /68 static_cast<double>(Values.size());69}70 71Expected<std::vector<BenchmarkMeasure>> LatencyBenchmarkRunner::runMeasurements(72 const FunctionExecutor &Executor) const {73 // Cycle measurements include some overhead from the kernel. Repeat the74 // measure several times and return the aggregated value, as specified by75 // ResultAggMode.76 SmallVector<int64_t, 4> AccumulatedValues;77 double MinVariance = std::numeric_limits<double>::infinity();78 const PfmCountersInfo &PCI = State.getPfmCounters();79 const char *CounterName = PCI.CycleCounter;80 81 SmallVector<const char *> ValCountersToRun;82 Error ValCounterErr = getValidationCountersToRun(ValCountersToRun);83 if (ValCounterErr)84 return std::move(ValCounterErr);85 86 SmallVector<int64_t> ValCounterValues(ValCountersToRun.size(), 0);87 // Values count for each run.88 int ValuesCount = 0;89 for (size_t I = 0; I < NumMeasurements; ++I) {90 SmallVector<int64_t> IterationValCounterValues(ValCountersToRun.size(), -1);91 auto ExpectedCounterValues = Executor.runAndSample(92 CounterName, ValCountersToRun, IterationValCounterValues);93 if (!ExpectedCounterValues)94 return ExpectedCounterValues.takeError();95 ValuesCount = ExpectedCounterValues.get().size();96 if (ValuesCount == 1) {97 LLVM_DEBUG(dbgs() << "Latency value: " << ExpectedCounterValues.get()[0]98 << "\n");99 AccumulatedValues.push_back(ExpectedCounterValues.get()[0]);100 } else {101 // We'll keep the reading with lowest variance (ie., most stable)102 double Variance = computeVariance(*ExpectedCounterValues);103 if (MinVariance > Variance) {104 AccumulatedValues = std::move(ExpectedCounterValues.get());105 MinVariance = Variance;106 }107 }108 109 for (size_t I = 0; I < ValCounterValues.size(); ++I) {110 LLVM_DEBUG(dbgs() << getValidationEventName(ValidationCounters[I]) << ": "111 << IterationValCounterValues[I] << "\n");112 ValCounterValues[I] += IterationValCounterValues[I];113 }114 }115 116 std::map<ValidationEvent, int64_t> ValidationInfo;117 for (size_t I = 0; I < ValidationCounters.size(); ++I)118 ValidationInfo[ValidationCounters[I]] = ValCounterValues[I];119 120 std::string ModeName;121 switch (Mode) {122 case Benchmark::Latency:123 ModeName = "latency";124 break;125 case Benchmark::InverseThroughput:126 ModeName = "inverse_throughput";127 break;128 default:129 break;130 }131 132 switch (ResultAggMode) {133 case Benchmark::MinVariance: {134 if (ValuesCount == 1)135 errs() << "Each sample only has one value. result-aggregation-mode "136 "of min-variance is probably non-sensical\n";137 std::vector<BenchmarkMeasure> Result;138 Result.reserve(AccumulatedValues.size());139 for (const int64_t Value : AccumulatedValues)140 Result.push_back(141 BenchmarkMeasure::Create(ModeName, Value, ValidationInfo));142 return std::move(Result);143 }144 case Benchmark::Min: {145 std::vector<BenchmarkMeasure> Result;146 Result.push_back(BenchmarkMeasure::Create(147 ModeName, findMin(AccumulatedValues), ValidationInfo));148 return std::move(Result);149 }150 case Benchmark::Max: {151 std::vector<BenchmarkMeasure> Result;152 Result.push_back(BenchmarkMeasure::Create(153 ModeName, findMax(AccumulatedValues), ValidationInfo));154 return std::move(Result);155 }156 case Benchmark::Mean: {157 std::vector<BenchmarkMeasure> Result;158 Result.push_back(BenchmarkMeasure::Create(159 ModeName, findMean(AccumulatedValues), ValidationInfo));160 return std::move(Result);161 }162 }163 return make_error<Failure>(Twine("Unexpected benchmark mode(")164 .concat(std::to_string(Mode))165 .concat(" and unexpected ResultAggMode ")166 .concat(std::to_string(ResultAggMode)));167}168 169} // namespace exegesis170} // namespace llvm171