1*58b9f456SAndroid Build Coastguard Worker // Copyright 2016 Ismael Jimenez Martinez. All rights reserved.
2*58b9f456SAndroid Build Coastguard Worker // Copyright 2017 Roman Lebedev. All rights reserved.
3*58b9f456SAndroid Build Coastguard Worker //
4*58b9f456SAndroid Build Coastguard Worker // Licensed under the Apache License, Version 2.0 (the "License");
5*58b9f456SAndroid Build Coastguard Worker // you may not use this file except in compliance with the License.
6*58b9f456SAndroid Build Coastguard Worker // You may obtain a copy of the License at
7*58b9f456SAndroid Build Coastguard Worker //
8*58b9f456SAndroid Build Coastguard Worker // http://www.apache.org/licenses/LICENSE-2.0
9*58b9f456SAndroid Build Coastguard Worker //
10*58b9f456SAndroid Build Coastguard Worker // Unless required by applicable law or agreed to in writing, software
11*58b9f456SAndroid Build Coastguard Worker // distributed under the License is distributed on an "AS IS" BASIS,
12*58b9f456SAndroid Build Coastguard Worker // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*58b9f456SAndroid Build Coastguard Worker // See the License for the specific language governing permissions and
14*58b9f456SAndroid Build Coastguard Worker // limitations under the License.
15*58b9f456SAndroid Build Coastguard Worker
16*58b9f456SAndroid Build Coastguard Worker #include "benchmark/benchmark.h"
17*58b9f456SAndroid Build Coastguard Worker
18*58b9f456SAndroid Build Coastguard Worker #include <algorithm>
19*58b9f456SAndroid Build Coastguard Worker #include <cmath>
20*58b9f456SAndroid Build Coastguard Worker #include <numeric>
21*58b9f456SAndroid Build Coastguard Worker #include <string>
22*58b9f456SAndroid Build Coastguard Worker #include <vector>
23*58b9f456SAndroid Build Coastguard Worker #include "check.h"
24*58b9f456SAndroid Build Coastguard Worker #include "statistics.h"
25*58b9f456SAndroid Build Coastguard Worker
26*58b9f456SAndroid Build Coastguard Worker namespace benchmark {
27*58b9f456SAndroid Build Coastguard Worker
__anonb450cb9a0102(const std::vector<double>& v) 28*58b9f456SAndroid Build Coastguard Worker auto StatisticsSum = [](const std::vector<double>& v) {
29*58b9f456SAndroid Build Coastguard Worker return std::accumulate(v.begin(), v.end(), 0.0);
30*58b9f456SAndroid Build Coastguard Worker };
31*58b9f456SAndroid Build Coastguard Worker
StatisticsMean(const std::vector<double> & v)32*58b9f456SAndroid Build Coastguard Worker double StatisticsMean(const std::vector<double>& v) {
33*58b9f456SAndroid Build Coastguard Worker if (v.empty()) return 0.0;
34*58b9f456SAndroid Build Coastguard Worker return StatisticsSum(v) * (1.0 / v.size());
35*58b9f456SAndroid Build Coastguard Worker }
36*58b9f456SAndroid Build Coastguard Worker
StatisticsMedian(const std::vector<double> & v)37*58b9f456SAndroid Build Coastguard Worker double StatisticsMedian(const std::vector<double>& v) {
38*58b9f456SAndroid Build Coastguard Worker if (v.size() < 3) return StatisticsMean(v);
39*58b9f456SAndroid Build Coastguard Worker std::vector<double> copy(v);
40*58b9f456SAndroid Build Coastguard Worker
41*58b9f456SAndroid Build Coastguard Worker auto center = copy.begin() + v.size() / 2;
42*58b9f456SAndroid Build Coastguard Worker std::nth_element(copy.begin(), center, copy.end());
43*58b9f456SAndroid Build Coastguard Worker
44*58b9f456SAndroid Build Coastguard Worker // did we have an odd number of samples?
45*58b9f456SAndroid Build Coastguard Worker // if yes, then center is the median
46*58b9f456SAndroid Build Coastguard Worker // it no, then we are looking for the average between center and the value
47*58b9f456SAndroid Build Coastguard Worker // before
48*58b9f456SAndroid Build Coastguard Worker if (v.size() % 2 == 1) return *center;
49*58b9f456SAndroid Build Coastguard Worker auto center2 = copy.begin() + v.size() / 2 - 1;
50*58b9f456SAndroid Build Coastguard Worker std::nth_element(copy.begin(), center2, copy.end());
51*58b9f456SAndroid Build Coastguard Worker return (*center + *center2) / 2.0;
52*58b9f456SAndroid Build Coastguard Worker }
53*58b9f456SAndroid Build Coastguard Worker
54*58b9f456SAndroid Build Coastguard Worker // Return the sum of the squares of this sample set
__anonb450cb9a0202(const std::vector<double>& v) 55*58b9f456SAndroid Build Coastguard Worker auto SumSquares = [](const std::vector<double>& v) {
56*58b9f456SAndroid Build Coastguard Worker return std::inner_product(v.begin(), v.end(), v.begin(), 0.0);
57*58b9f456SAndroid Build Coastguard Worker };
58*58b9f456SAndroid Build Coastguard Worker
__anonb450cb9a0302(const double dat) 59*58b9f456SAndroid Build Coastguard Worker auto Sqr = [](const double dat) { return dat * dat; };
__anonb450cb9a0402(const double dat) 60*58b9f456SAndroid Build Coastguard Worker auto Sqrt = [](const double dat) {
61*58b9f456SAndroid Build Coastguard Worker // Avoid NaN due to imprecision in the calculations
62*58b9f456SAndroid Build Coastguard Worker if (dat < 0.0) return 0.0;
63*58b9f456SAndroid Build Coastguard Worker return std::sqrt(dat);
64*58b9f456SAndroid Build Coastguard Worker };
65*58b9f456SAndroid Build Coastguard Worker
StatisticsStdDev(const std::vector<double> & v)66*58b9f456SAndroid Build Coastguard Worker double StatisticsStdDev(const std::vector<double>& v) {
67*58b9f456SAndroid Build Coastguard Worker const auto mean = StatisticsMean(v);
68*58b9f456SAndroid Build Coastguard Worker if (v.empty()) return mean;
69*58b9f456SAndroid Build Coastguard Worker
70*58b9f456SAndroid Build Coastguard Worker // Sample standard deviation is undefined for n = 1
71*58b9f456SAndroid Build Coastguard Worker if (v.size() == 1) return 0.0;
72*58b9f456SAndroid Build Coastguard Worker
73*58b9f456SAndroid Build Coastguard Worker const double avg_squares = SumSquares(v) * (1.0 / v.size());
74*58b9f456SAndroid Build Coastguard Worker return Sqrt(v.size() / (v.size() - 1.0) * (avg_squares - Sqr(mean)));
75*58b9f456SAndroid Build Coastguard Worker }
76*58b9f456SAndroid Build Coastguard Worker
ComputeStats(const std::vector<BenchmarkReporter::Run> & reports)77*58b9f456SAndroid Build Coastguard Worker std::vector<BenchmarkReporter::Run> ComputeStats(
78*58b9f456SAndroid Build Coastguard Worker const std::vector<BenchmarkReporter::Run>& reports) {
79*58b9f456SAndroid Build Coastguard Worker typedef BenchmarkReporter::Run Run;
80*58b9f456SAndroid Build Coastguard Worker std::vector<Run> results;
81*58b9f456SAndroid Build Coastguard Worker
82*58b9f456SAndroid Build Coastguard Worker auto error_count =
83*58b9f456SAndroid Build Coastguard Worker std::count_if(reports.begin(), reports.end(),
84*58b9f456SAndroid Build Coastguard Worker [](Run const& run) { return run.error_occurred; });
85*58b9f456SAndroid Build Coastguard Worker
86*58b9f456SAndroid Build Coastguard Worker if (reports.size() - error_count < 2) {
87*58b9f456SAndroid Build Coastguard Worker // We don't report aggregated data if there was a single run.
88*58b9f456SAndroid Build Coastguard Worker return results;
89*58b9f456SAndroid Build Coastguard Worker }
90*58b9f456SAndroid Build Coastguard Worker
91*58b9f456SAndroid Build Coastguard Worker // Accumulators.
92*58b9f456SAndroid Build Coastguard Worker std::vector<double> real_accumulated_time_stat;
93*58b9f456SAndroid Build Coastguard Worker std::vector<double> cpu_accumulated_time_stat;
94*58b9f456SAndroid Build Coastguard Worker
95*58b9f456SAndroid Build Coastguard Worker real_accumulated_time_stat.reserve(reports.size());
96*58b9f456SAndroid Build Coastguard Worker cpu_accumulated_time_stat.reserve(reports.size());
97*58b9f456SAndroid Build Coastguard Worker
98*58b9f456SAndroid Build Coastguard Worker // All repetitions should be run with the same number of iterations so we
99*58b9f456SAndroid Build Coastguard Worker // can take this information from the first benchmark.
100*58b9f456SAndroid Build Coastguard Worker int64_t const run_iterations = reports.front().iterations;
101*58b9f456SAndroid Build Coastguard Worker // create stats for user counters
102*58b9f456SAndroid Build Coastguard Worker struct CounterStat {
103*58b9f456SAndroid Build Coastguard Worker Counter c;
104*58b9f456SAndroid Build Coastguard Worker std::vector<double> s;
105*58b9f456SAndroid Build Coastguard Worker };
106*58b9f456SAndroid Build Coastguard Worker std::map<std::string, CounterStat> counter_stats;
107*58b9f456SAndroid Build Coastguard Worker for (Run const& r : reports) {
108*58b9f456SAndroid Build Coastguard Worker for (auto const& cnt : r.counters) {
109*58b9f456SAndroid Build Coastguard Worker auto it = counter_stats.find(cnt.first);
110*58b9f456SAndroid Build Coastguard Worker if (it == counter_stats.end()) {
111*58b9f456SAndroid Build Coastguard Worker counter_stats.insert({cnt.first, {cnt.second, std::vector<double>{}}});
112*58b9f456SAndroid Build Coastguard Worker it = counter_stats.find(cnt.first);
113*58b9f456SAndroid Build Coastguard Worker it->second.s.reserve(reports.size());
114*58b9f456SAndroid Build Coastguard Worker } else {
115*58b9f456SAndroid Build Coastguard Worker CHECK_EQ(counter_stats[cnt.first].c.flags, cnt.second.flags);
116*58b9f456SAndroid Build Coastguard Worker }
117*58b9f456SAndroid Build Coastguard Worker }
118*58b9f456SAndroid Build Coastguard Worker }
119*58b9f456SAndroid Build Coastguard Worker
120*58b9f456SAndroid Build Coastguard Worker // Populate the accumulators.
121*58b9f456SAndroid Build Coastguard Worker for (Run const& run : reports) {
122*58b9f456SAndroid Build Coastguard Worker CHECK_EQ(reports[0].benchmark_name(), run.benchmark_name());
123*58b9f456SAndroid Build Coastguard Worker CHECK_EQ(run_iterations, run.iterations);
124*58b9f456SAndroid Build Coastguard Worker if (run.error_occurred) continue;
125*58b9f456SAndroid Build Coastguard Worker real_accumulated_time_stat.emplace_back(run.real_accumulated_time);
126*58b9f456SAndroid Build Coastguard Worker cpu_accumulated_time_stat.emplace_back(run.cpu_accumulated_time);
127*58b9f456SAndroid Build Coastguard Worker // user counters
128*58b9f456SAndroid Build Coastguard Worker for (auto const& cnt : run.counters) {
129*58b9f456SAndroid Build Coastguard Worker auto it = counter_stats.find(cnt.first);
130*58b9f456SAndroid Build Coastguard Worker CHECK_NE(it, counter_stats.end());
131*58b9f456SAndroid Build Coastguard Worker it->second.s.emplace_back(cnt.second);
132*58b9f456SAndroid Build Coastguard Worker }
133*58b9f456SAndroid Build Coastguard Worker }
134*58b9f456SAndroid Build Coastguard Worker
135*58b9f456SAndroid Build Coastguard Worker // Only add label if it is same for all runs
136*58b9f456SAndroid Build Coastguard Worker std::string report_label = reports[0].report_label;
137*58b9f456SAndroid Build Coastguard Worker for (std::size_t i = 1; i < reports.size(); i++) {
138*58b9f456SAndroid Build Coastguard Worker if (reports[i].report_label != report_label) {
139*58b9f456SAndroid Build Coastguard Worker report_label = "";
140*58b9f456SAndroid Build Coastguard Worker break;
141*58b9f456SAndroid Build Coastguard Worker }
142*58b9f456SAndroid Build Coastguard Worker }
143*58b9f456SAndroid Build Coastguard Worker
144*58b9f456SAndroid Build Coastguard Worker const double iteration_rescale_factor =
145*58b9f456SAndroid Build Coastguard Worker double(reports.size()) / double(run_iterations);
146*58b9f456SAndroid Build Coastguard Worker
147*58b9f456SAndroid Build Coastguard Worker for (const auto& Stat : *reports[0].statistics) {
148*58b9f456SAndroid Build Coastguard Worker // Get the data from the accumulator to BenchmarkReporter::Run's.
149*58b9f456SAndroid Build Coastguard Worker Run data;
150*58b9f456SAndroid Build Coastguard Worker data.run_name = reports[0].benchmark_name();
151*58b9f456SAndroid Build Coastguard Worker data.run_type = BenchmarkReporter::Run::RT_Aggregate;
152*58b9f456SAndroid Build Coastguard Worker data.aggregate_name = Stat.name_;
153*58b9f456SAndroid Build Coastguard Worker data.report_label = report_label;
154*58b9f456SAndroid Build Coastguard Worker
155*58b9f456SAndroid Build Coastguard Worker // It is incorrect to say that an aggregate is computed over
156*58b9f456SAndroid Build Coastguard Worker // run's iterations, because those iterations already got averaged.
157*58b9f456SAndroid Build Coastguard Worker // Similarly, if there are N repetitions with 1 iterations each,
158*58b9f456SAndroid Build Coastguard Worker // an aggregate will be computed over N measurements, not 1.
159*58b9f456SAndroid Build Coastguard Worker // Thus it is best to simply use the count of separate reports.
160*58b9f456SAndroid Build Coastguard Worker data.iterations = reports.size();
161*58b9f456SAndroid Build Coastguard Worker
162*58b9f456SAndroid Build Coastguard Worker data.real_accumulated_time = Stat.compute_(real_accumulated_time_stat);
163*58b9f456SAndroid Build Coastguard Worker data.cpu_accumulated_time = Stat.compute_(cpu_accumulated_time_stat);
164*58b9f456SAndroid Build Coastguard Worker
165*58b9f456SAndroid Build Coastguard Worker // We will divide these times by data.iterations when reporting, but the
166*58b9f456SAndroid Build Coastguard Worker // data.iterations is not nessesairly the scale of these measurements,
167*58b9f456SAndroid Build Coastguard Worker // because in each repetition, these timers are sum over all the iterations.
168*58b9f456SAndroid Build Coastguard Worker // And if we want to say that the stats are over N repetitions and not
169*58b9f456SAndroid Build Coastguard Worker // M iterations, we need to multiply these by (N/M).
170*58b9f456SAndroid Build Coastguard Worker data.real_accumulated_time *= iteration_rescale_factor;
171*58b9f456SAndroid Build Coastguard Worker data.cpu_accumulated_time *= iteration_rescale_factor;
172*58b9f456SAndroid Build Coastguard Worker
173*58b9f456SAndroid Build Coastguard Worker data.time_unit = reports[0].time_unit;
174*58b9f456SAndroid Build Coastguard Worker
175*58b9f456SAndroid Build Coastguard Worker // user counters
176*58b9f456SAndroid Build Coastguard Worker for (auto const& kv : counter_stats) {
177*58b9f456SAndroid Build Coastguard Worker // Do *NOT* rescale the custom counters. They are already properly scaled.
178*58b9f456SAndroid Build Coastguard Worker const auto uc_stat = Stat.compute_(kv.second.s);
179*58b9f456SAndroid Build Coastguard Worker auto c = Counter(uc_stat, counter_stats[kv.first].c.flags,
180*58b9f456SAndroid Build Coastguard Worker counter_stats[kv.first].c.oneK);
181*58b9f456SAndroid Build Coastguard Worker data.counters[kv.first] = c;
182*58b9f456SAndroid Build Coastguard Worker }
183*58b9f456SAndroid Build Coastguard Worker
184*58b9f456SAndroid Build Coastguard Worker results.push_back(data);
185*58b9f456SAndroid Build Coastguard Worker }
186*58b9f456SAndroid Build Coastguard Worker
187*58b9f456SAndroid Build Coastguard Worker return results;
188*58b9f456SAndroid Build Coastguard Worker }
189*58b9f456SAndroid Build Coastguard Worker
190*58b9f456SAndroid Build Coastguard Worker } // end namespace benchmark
191