144 lines
		
	
	
		
			4.8 KiB
		
	
	
	
		
			C++
		
	
	
	
			
		
		
	
	
			144 lines
		
	
	
		
			4.8 KiB
		
	
	
	
		
			C++
		
	
	
	
//===-- 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,
 | 
						|
    InstructionBenchmark::ResultAggregationModeE ResultAgg)
 | 
						|
    : BenchmarkRunner(State, Mode) {
 | 
						|
  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
 |