1 //===-- LatencyBenchmarkRunner.cpp ------------------------------*- C++ -*-===//
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-exception
7 //===----------------------------------------------------------------------===//
9 #include "LatencyBenchmarkRunner.h"
11 #include "BenchmarkRunner.h"
13 #include "llvm/ADT/Twine.h"
14 #include "llvm/Support/Error.h"
21 LatencyBenchmarkRunner::LatencyBenchmarkRunner(
22 const LLVMState
&State
, Benchmark::ModeE Mode
,
23 BenchmarkPhaseSelectorE BenchmarkPhaseSelector
,
24 Benchmark::ResultAggregationModeE ResultAgg
, ExecutionModeE ExecutionMode
,
25 unsigned BenchmarkRepeatCount
)
26 : BenchmarkRunner(State
, Mode
, BenchmarkPhaseSelector
, ExecutionMode
) {
27 assert((Mode
== Benchmark::Latency
|| Mode
== Benchmark::InverseThroughput
) &&
29 ResultAggMode
= ResultAgg
;
30 NumMeasurements
= BenchmarkRepeatCount
;
33 LatencyBenchmarkRunner::~LatencyBenchmarkRunner() = default;
35 static double computeVariance(const llvm::SmallVector
<int64_t, 4> &Values
) {
38 double Sum
= std::accumulate(Values
.begin(), Values
.end(), 0.0);
40 const double Mean
= Sum
/ Values
.size();
42 for (const auto &V
: Values
) {
43 double Delta
= V
- Mean
;
46 return Ret
/ Values
.size();
49 static int64_t findMin(const llvm::SmallVector
<int64_t, 4> &Values
) {
52 return *std::min_element(Values
.begin(), Values
.end());
55 static int64_t findMax(const llvm::SmallVector
<int64_t, 4> &Values
) {
58 return *std::max_element(Values
.begin(), Values
.end());
61 static int64_t findMean(const llvm::SmallVector
<int64_t, 4> &Values
) {
64 return std::accumulate(Values
.begin(), Values
.end(), 0.0) /
65 static_cast<double>(Values
.size());
68 Expected
<std::vector
<BenchmarkMeasure
>> LatencyBenchmarkRunner::runMeasurements(
69 const FunctionExecutor
&Executor
) const {
70 // Cycle measurements include some overhead from the kernel. Repeat the
71 // measure several times and return the aggregated value, as specified by
73 llvm::SmallVector
<int64_t, 4> AccumulatedValues
;
74 double MinVariance
= std::numeric_limits
<double>::infinity();
75 const char *CounterName
= State
.getPfmCounters().CycleCounter
;
76 // Values count for each run.
78 for (size_t I
= 0; I
< NumMeasurements
; ++I
) {
79 auto ExpectedCounterValues
= Executor
.runAndSample(CounterName
);
80 if (!ExpectedCounterValues
)
81 return ExpectedCounterValues
.takeError();
82 ValuesCount
= ExpectedCounterValues
.get().size();
84 AccumulatedValues
.push_back(ExpectedCounterValues
.get()[0]);
86 // We'll keep the reading with lowest variance (ie., most stable)
87 double Variance
= computeVariance(*ExpectedCounterValues
);
88 if (MinVariance
> Variance
) {
89 AccumulatedValues
= std::move(ExpectedCounterValues
.get());
90 MinVariance
= Variance
;
97 case Benchmark::Latency
:
100 case Benchmark::InverseThroughput
:
101 ModeName
= "inverse_throughput";
107 switch (ResultAggMode
) {
108 case Benchmark::MinVariance
: {
109 if (ValuesCount
== 1)
110 llvm::errs() << "Each sample only has one value. result-aggregation-mode "
111 "of min-variance is probably non-sensical\n";
112 std::vector
<BenchmarkMeasure
> Result
;
113 Result
.reserve(AccumulatedValues
.size());
114 for (const int64_t Value
: AccumulatedValues
)
115 Result
.push_back(BenchmarkMeasure::Create(ModeName
, Value
));
116 return std::move(Result
);
118 case Benchmark::Min
: {
119 std::vector
<BenchmarkMeasure
> Result
;
121 BenchmarkMeasure::Create(ModeName
, findMin(AccumulatedValues
)));
122 return std::move(Result
);
124 case Benchmark::Max
: {
125 std::vector
<BenchmarkMeasure
> Result
;
127 BenchmarkMeasure::Create(ModeName
, findMax(AccumulatedValues
)));
128 return std::move(Result
);
130 case Benchmark::Mean
: {
131 std::vector
<BenchmarkMeasure
> Result
;
133 BenchmarkMeasure::Create(ModeName
, findMean(AccumulatedValues
)));
134 return std::move(Result
);
137 return llvm::make_error
<Failure
>(llvm::Twine("Unexpected benchmark mode(")
138 .concat(std::to_string(Mode
))
139 .concat(" and unexpected ResultAggMode ")
140 .concat(std::to_string(ResultAggMode
)));
143 } // namespace exegesis