123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144 |
- //===-- LatencyBenchmarkRunner.cpp ------------------------------*- C++ -*-===//
- //
- // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
- // See https://llvm.org/LICENSE.txt for license information.
- // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
- //
- //===----------------------------------------------------------------------===//
- #include "LatencyBenchmarkRunner.h"
- #include "BenchmarkRunner.h"
- #include "Target.h"
- #include "llvm/ADT/Twine.h"
- #include "llvm/Support/Error.h"
- #include <algorithm>
- #include <cmath>
- namespace llvm {
- namespace exegesis {
- LatencyBenchmarkRunner::LatencyBenchmarkRunner(
- const LLVMState &State, InstructionBenchmark::ModeE Mode,
- BenchmarkPhaseSelectorE BenchmarkPhaseSelector,
- InstructionBenchmark::ResultAggregationModeE ResultAgg)
- : BenchmarkRunner(State, Mode, BenchmarkPhaseSelector) {
- assert((Mode == InstructionBenchmark::Latency ||
- Mode == InstructionBenchmark::InverseThroughput) &&
- "invalid mode");
- ResultAggMode = ResultAgg;
- }
- LatencyBenchmarkRunner::~LatencyBenchmarkRunner() = default;
- static double computeVariance(const llvm::SmallVector<int64_t, 4> &Values) {
- if (Values.empty())
- return 0.0;
- double Sum = std::accumulate(Values.begin(), Values.end(), 0.0);
- const double Mean = Sum / Values.size();
- double Ret = 0;
- for (const auto &V : Values) {
- double Delta = V - Mean;
- Ret += Delta * Delta;
- }
- return Ret / Values.size();
- }
- static int64_t findMin(const llvm::SmallVector<int64_t, 4> &Values) {
- if (Values.empty())
- return 0;
- return *std::min_element(Values.begin(), Values.end());
- }
- static int64_t findMax(const llvm::SmallVector<int64_t, 4> &Values) {
- if (Values.empty())
- return 0;
- return *std::max_element(Values.begin(), Values.end());
- }
- static int64_t findMean(const llvm::SmallVector<int64_t, 4> &Values) {
- if (Values.empty())
- return 0;
- return std::accumulate(Values.begin(), Values.end(), 0.0) /
- static_cast<double>(Values.size());
- }
- Expected<std::vector<BenchmarkMeasure>> LatencyBenchmarkRunner::runMeasurements(
- const FunctionExecutor &Executor) const {
- // Cycle measurements include some overhead from the kernel. Repeat the
- // measure several times and return the aggregated value, as specified by
- // ResultAggMode.
- constexpr const int NumMeasurements = 30;
- llvm::SmallVector<int64_t, 4> AccumulatedValues;
- double MinVariance = std::numeric_limits<double>::infinity();
- const char *CounterName = State.getPfmCounters().CycleCounter;
- // Values count for each run.
- int ValuesCount = 0;
- for (size_t I = 0; I < NumMeasurements; ++I) {
- auto ExpectedCounterValues = Executor.runAndSample(CounterName);
- if (!ExpectedCounterValues)
- return ExpectedCounterValues.takeError();
- ValuesCount = ExpectedCounterValues.get().size();
- if (ValuesCount == 1)
- AccumulatedValues.push_back(ExpectedCounterValues.get()[0]);
- else {
- // We'll keep the reading with lowest variance (ie., most stable)
- double Variance = computeVariance(*ExpectedCounterValues);
- if (MinVariance > Variance) {
- AccumulatedValues = std::move(ExpectedCounterValues.get());
- MinVariance = Variance;
- }
- }
- }
- std::string ModeName;
- switch (Mode) {
- case InstructionBenchmark::Latency:
- ModeName = "latency";
- break;
- case InstructionBenchmark::InverseThroughput:
- ModeName = "inverse_throughput";
- break;
- default:
- break;
- }
- switch (ResultAggMode) {
- case InstructionBenchmark::MinVariance: {
- if (ValuesCount == 1)
- llvm::errs() << "Each sample only has one value. result-aggregation-mode "
- "of min-variance is probably non-sensical\n";
- std::vector<BenchmarkMeasure> Result;
- Result.reserve(AccumulatedValues.size());
- for (const int64_t Value : AccumulatedValues)
- Result.push_back(BenchmarkMeasure::Create(ModeName, Value));
- return std::move(Result);
- }
- case InstructionBenchmark::Min: {
- std::vector<BenchmarkMeasure> Result;
- Result.push_back(
- BenchmarkMeasure::Create(ModeName, findMin(AccumulatedValues)));
- return std::move(Result);
- }
- case InstructionBenchmark::Max: {
- std::vector<BenchmarkMeasure> Result;
- Result.push_back(
- BenchmarkMeasure::Create(ModeName, findMax(AccumulatedValues)));
- return std::move(Result);
- }
- case InstructionBenchmark::Mean: {
- std::vector<BenchmarkMeasure> Result;
- Result.push_back(
- BenchmarkMeasure::Create(ModeName, findMean(AccumulatedValues)));
- return std::move(Result);
- }
- }
- return llvm::make_error<Failure>(llvm::Twine("Unexpected benchmark mode(")
- .concat(std::to_string(Mode))
- .concat(" and unexpected ResultAggMode ")
- .concat(std::to_string(ResultAggMode)));
- }
- } // namespace exegesis
- } // namespace llvm
|