1a8c51b3fSopenharmony_ci// Copyright 2015 Google Inc. All rights reserved.
2a8c51b3fSopenharmony_ci//
3a8c51b3fSopenharmony_ci// Licensed under the Apache License, Version 2.0 (the "License");
4a8c51b3fSopenharmony_ci// you may not use this file except in compliance with the License.
5a8c51b3fSopenharmony_ci// You may obtain a copy of the License at
6a8c51b3fSopenharmony_ci//
7a8c51b3fSopenharmony_ci//     http://www.apache.org/licenses/LICENSE-2.0
8a8c51b3fSopenharmony_ci//
9a8c51b3fSopenharmony_ci// Unless required by applicable law or agreed to in writing, software
10a8c51b3fSopenharmony_ci// distributed under the License is distributed on an "AS IS" BASIS,
11a8c51b3fSopenharmony_ci// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12a8c51b3fSopenharmony_ci// See the License for the specific language governing permissions and
13a8c51b3fSopenharmony_ci// limitations under the License.
14a8c51b3fSopenharmony_ci
15a8c51b3fSopenharmony_ci#include "benchmark_runner.h"
16a8c51b3fSopenharmony_ci
17a8c51b3fSopenharmony_ci#include "benchmark/benchmark.h"
18a8c51b3fSopenharmony_ci#include "benchmark_api_internal.h"
19a8c51b3fSopenharmony_ci#include "internal_macros.h"
20a8c51b3fSopenharmony_ci
21a8c51b3fSopenharmony_ci#ifndef BENCHMARK_OS_WINDOWS
22a8c51b3fSopenharmony_ci#if !defined(BENCHMARK_OS_FUCHSIA) && !defined(BENCHMARK_OS_QURT)
23a8c51b3fSopenharmony_ci#include <sys/resource.h>
24a8c51b3fSopenharmony_ci#endif
25a8c51b3fSopenharmony_ci#include <sys/time.h>
26a8c51b3fSopenharmony_ci#include <unistd.h>
27a8c51b3fSopenharmony_ci#endif
28a8c51b3fSopenharmony_ci
29a8c51b3fSopenharmony_ci#include <algorithm>
30a8c51b3fSopenharmony_ci#include <atomic>
31a8c51b3fSopenharmony_ci#include <climits>
32a8c51b3fSopenharmony_ci#include <cmath>
33a8c51b3fSopenharmony_ci#include <condition_variable>
34a8c51b3fSopenharmony_ci#include <cstdio>
35a8c51b3fSopenharmony_ci#include <cstdlib>
36a8c51b3fSopenharmony_ci#include <fstream>
37a8c51b3fSopenharmony_ci#include <iostream>
38a8c51b3fSopenharmony_ci#include <limits>
39a8c51b3fSopenharmony_ci#include <memory>
40a8c51b3fSopenharmony_ci#include <string>
41a8c51b3fSopenharmony_ci#include <thread>
42a8c51b3fSopenharmony_ci#include <utility>
43a8c51b3fSopenharmony_ci
44a8c51b3fSopenharmony_ci#include "check.h"
45a8c51b3fSopenharmony_ci#include "colorprint.h"
46a8c51b3fSopenharmony_ci#include "commandlineflags.h"
47a8c51b3fSopenharmony_ci#include "complexity.h"
48a8c51b3fSopenharmony_ci#include "counter.h"
49a8c51b3fSopenharmony_ci#include "internal_macros.h"
50a8c51b3fSopenharmony_ci#include "log.h"
51a8c51b3fSopenharmony_ci#include "mutex.h"
52a8c51b3fSopenharmony_ci#include "perf_counters.h"
53a8c51b3fSopenharmony_ci#include "re.h"
54a8c51b3fSopenharmony_ci#include "statistics.h"
55a8c51b3fSopenharmony_ci#include "string_util.h"
56a8c51b3fSopenharmony_ci#include "thread_manager.h"
57a8c51b3fSopenharmony_ci#include "thread_timer.h"
58a8c51b3fSopenharmony_ci
59a8c51b3fSopenharmony_cinamespace benchmark {
60a8c51b3fSopenharmony_ci
61a8c51b3fSopenharmony_cinamespace internal {
62a8c51b3fSopenharmony_ci
63a8c51b3fSopenharmony_ciMemoryManager* memory_manager = nullptr;
64a8c51b3fSopenharmony_ci
65a8c51b3fSopenharmony_cinamespace {
66a8c51b3fSopenharmony_ci
67a8c51b3fSopenharmony_cistatic constexpr IterationCount kMaxIterations = 1000000000;
68a8c51b3fSopenharmony_ciconst double kDefaultMinTime =
69a8c51b3fSopenharmony_ci    std::strtod(::benchmark::kDefaultMinTimeStr, /*p_end*/ nullptr);
70a8c51b3fSopenharmony_ci
71a8c51b3fSopenharmony_ciBenchmarkReporter::Run CreateRunReport(
72a8c51b3fSopenharmony_ci    const benchmark::internal::BenchmarkInstance& b,
73a8c51b3fSopenharmony_ci    const internal::ThreadManager::Result& results,
74a8c51b3fSopenharmony_ci    IterationCount memory_iterations,
75a8c51b3fSopenharmony_ci    const MemoryManager::Result* memory_result, double seconds,
76a8c51b3fSopenharmony_ci    int64_t repetition_index, int64_t repeats) {
77a8c51b3fSopenharmony_ci  // Create report about this benchmark run.
78a8c51b3fSopenharmony_ci  BenchmarkReporter::Run report;
79a8c51b3fSopenharmony_ci
80a8c51b3fSopenharmony_ci  report.run_name = b.name();
81a8c51b3fSopenharmony_ci  report.family_index = b.family_index();
82a8c51b3fSopenharmony_ci  report.per_family_instance_index = b.per_family_instance_index();
83a8c51b3fSopenharmony_ci  report.skipped = results.skipped_;
84a8c51b3fSopenharmony_ci  report.skip_message = results.skip_message_;
85a8c51b3fSopenharmony_ci  report.report_label = results.report_label_;
86a8c51b3fSopenharmony_ci  // This is the total iterations across all threads.
87a8c51b3fSopenharmony_ci  report.iterations = results.iterations;
88a8c51b3fSopenharmony_ci  report.time_unit = b.time_unit();
89a8c51b3fSopenharmony_ci  report.threads = b.threads();
90a8c51b3fSopenharmony_ci  report.repetition_index = repetition_index;
91a8c51b3fSopenharmony_ci  report.repetitions = repeats;
92a8c51b3fSopenharmony_ci
93a8c51b3fSopenharmony_ci  if (!report.skipped) {
94a8c51b3fSopenharmony_ci    if (b.use_manual_time()) {
95a8c51b3fSopenharmony_ci      report.real_accumulated_time = results.manual_time_used;
96a8c51b3fSopenharmony_ci    } else {
97a8c51b3fSopenharmony_ci      report.real_accumulated_time = results.real_time_used;
98a8c51b3fSopenharmony_ci    }
99a8c51b3fSopenharmony_ci    report.cpu_accumulated_time = results.cpu_time_used;
100a8c51b3fSopenharmony_ci    report.complexity_n = results.complexity_n;
101a8c51b3fSopenharmony_ci    report.complexity = b.complexity();
102a8c51b3fSopenharmony_ci    report.complexity_lambda = b.complexity_lambda();
103a8c51b3fSopenharmony_ci    report.statistics = &b.statistics();
104a8c51b3fSopenharmony_ci    report.counters = results.counters;
105a8c51b3fSopenharmony_ci
106a8c51b3fSopenharmony_ci    if (memory_iterations > 0) {
107a8c51b3fSopenharmony_ci      assert(memory_result != nullptr);
108a8c51b3fSopenharmony_ci      report.memory_result = memory_result;
109a8c51b3fSopenharmony_ci      report.allocs_per_iter =
110a8c51b3fSopenharmony_ci          memory_iterations ? static_cast<double>(memory_result->num_allocs) /
111a8c51b3fSopenharmony_ci                                  memory_iterations
112a8c51b3fSopenharmony_ci                            : 0;
113a8c51b3fSopenharmony_ci    }
114a8c51b3fSopenharmony_ci
115a8c51b3fSopenharmony_ci    internal::Finish(&report.counters, results.iterations, seconds,
116a8c51b3fSopenharmony_ci                     b.threads());
117a8c51b3fSopenharmony_ci  }
118a8c51b3fSopenharmony_ci  return report;
119a8c51b3fSopenharmony_ci}
120a8c51b3fSopenharmony_ci
121a8c51b3fSopenharmony_ci// Execute one thread of benchmark b for the specified number of iterations.
122a8c51b3fSopenharmony_ci// Adds the stats collected for the thread into manager->results.
123a8c51b3fSopenharmony_civoid RunInThread(const BenchmarkInstance* b, IterationCount iters,
124a8c51b3fSopenharmony_ci                 int thread_id, ThreadManager* manager,
125a8c51b3fSopenharmony_ci                 PerfCountersMeasurement* perf_counters_measurement) {
126a8c51b3fSopenharmony_ci  internal::ThreadTimer timer(
127a8c51b3fSopenharmony_ci      b->measure_process_cpu_time()
128a8c51b3fSopenharmony_ci          ? internal::ThreadTimer::CreateProcessCpuTime()
129a8c51b3fSopenharmony_ci          : internal::ThreadTimer::Create());
130a8c51b3fSopenharmony_ci
131a8c51b3fSopenharmony_ci  State st =
132a8c51b3fSopenharmony_ci      b->Run(iters, thread_id, &timer, manager, perf_counters_measurement);
133a8c51b3fSopenharmony_ci  BM_CHECK(st.skipped() || st.iterations() >= st.max_iterations)
134a8c51b3fSopenharmony_ci      << "Benchmark returned before State::KeepRunning() returned false!";
135a8c51b3fSopenharmony_ci  {
136a8c51b3fSopenharmony_ci    MutexLock l(manager->GetBenchmarkMutex());
137a8c51b3fSopenharmony_ci    internal::ThreadManager::Result& results = manager->results;
138a8c51b3fSopenharmony_ci    results.iterations += st.iterations();
139a8c51b3fSopenharmony_ci    results.cpu_time_used += timer.cpu_time_used();
140a8c51b3fSopenharmony_ci    results.real_time_used += timer.real_time_used();
141a8c51b3fSopenharmony_ci    results.manual_time_used += timer.manual_time_used();
142a8c51b3fSopenharmony_ci    results.complexity_n += st.complexity_length_n();
143a8c51b3fSopenharmony_ci    internal::Increment(&results.counters, st.counters);
144a8c51b3fSopenharmony_ci  }
145a8c51b3fSopenharmony_ci  manager->NotifyThreadComplete();
146a8c51b3fSopenharmony_ci}
147a8c51b3fSopenharmony_ci
148a8c51b3fSopenharmony_cidouble ComputeMinTime(const benchmark::internal::BenchmarkInstance& b,
149a8c51b3fSopenharmony_ci                      const BenchTimeType& iters_or_time) {
150a8c51b3fSopenharmony_ci  if (!IsZero(b.min_time())) return b.min_time();
151a8c51b3fSopenharmony_ci  // If the flag was used to specify number of iters, then return the default
152a8c51b3fSopenharmony_ci  // min_time.
153a8c51b3fSopenharmony_ci  if (iters_or_time.tag == BenchTimeType::ITERS) return kDefaultMinTime;
154a8c51b3fSopenharmony_ci
155a8c51b3fSopenharmony_ci  return iters_or_time.time;
156a8c51b3fSopenharmony_ci}
157a8c51b3fSopenharmony_ci
158a8c51b3fSopenharmony_ciIterationCount ComputeIters(const benchmark::internal::BenchmarkInstance& b,
159a8c51b3fSopenharmony_ci                            const BenchTimeType& iters_or_time) {
160a8c51b3fSopenharmony_ci  if (b.iterations() != 0) return b.iterations();
161a8c51b3fSopenharmony_ci
162a8c51b3fSopenharmony_ci  // We've already concluded that this flag is currently used to pass
163a8c51b3fSopenharmony_ci  // iters but do a check here again anyway.
164a8c51b3fSopenharmony_ci  BM_CHECK(iters_or_time.tag == BenchTimeType::ITERS);
165a8c51b3fSopenharmony_ci  return iters_or_time.iters;
166a8c51b3fSopenharmony_ci}
167a8c51b3fSopenharmony_ci
168a8c51b3fSopenharmony_ci}  // end namespace
169a8c51b3fSopenharmony_ci
170a8c51b3fSopenharmony_ciBenchTimeType ParseBenchMinTime(const std::string& value) {
171a8c51b3fSopenharmony_ci  BenchTimeType ret;
172a8c51b3fSopenharmony_ci
173a8c51b3fSopenharmony_ci  if (value.empty()) {
174a8c51b3fSopenharmony_ci    ret.tag = BenchTimeType::TIME;
175a8c51b3fSopenharmony_ci    ret.time = 0.0;
176a8c51b3fSopenharmony_ci    return ret;
177a8c51b3fSopenharmony_ci  }
178a8c51b3fSopenharmony_ci
179a8c51b3fSopenharmony_ci  if (value.back() == 'x') {
180a8c51b3fSopenharmony_ci    char* p_end;
181a8c51b3fSopenharmony_ci    // Reset errno before it's changed by strtol.
182a8c51b3fSopenharmony_ci    errno = 0;
183a8c51b3fSopenharmony_ci    IterationCount num_iters = std::strtol(value.c_str(), &p_end, 10);
184a8c51b3fSopenharmony_ci
185a8c51b3fSopenharmony_ci    // After a valid parse, p_end should have been set to
186a8c51b3fSopenharmony_ci    // point to the 'x' suffix.
187a8c51b3fSopenharmony_ci    BM_CHECK(errno == 0 && p_end != nullptr && *p_end == 'x')
188a8c51b3fSopenharmony_ci        << "Malformed iters value passed to --benchmark_min_time: `" << value
189a8c51b3fSopenharmony_ci        << "`. Expected --benchmark_min_time=<integer>x.";
190a8c51b3fSopenharmony_ci
191a8c51b3fSopenharmony_ci    ret.tag = BenchTimeType::ITERS;
192a8c51b3fSopenharmony_ci    ret.iters = num_iters;
193a8c51b3fSopenharmony_ci    return ret;
194a8c51b3fSopenharmony_ci  }
195a8c51b3fSopenharmony_ci
196a8c51b3fSopenharmony_ci  bool has_suffix = value.back() == 's';
197a8c51b3fSopenharmony_ci  if (!has_suffix) {
198a8c51b3fSopenharmony_ci    BM_VLOG(0) << "Value passed to --benchmark_min_time should have a suffix. "
199a8c51b3fSopenharmony_ci                  "Eg., `30s` for 30-seconds.";
200a8c51b3fSopenharmony_ci  }
201a8c51b3fSopenharmony_ci
202a8c51b3fSopenharmony_ci  char* p_end;
203a8c51b3fSopenharmony_ci  // Reset errno before it's changed by strtod.
204a8c51b3fSopenharmony_ci  errno = 0;
205a8c51b3fSopenharmony_ci  double min_time = std::strtod(value.c_str(), &p_end);
206a8c51b3fSopenharmony_ci
207a8c51b3fSopenharmony_ci  // After a successful parse, p_end should point to the suffix 's',
208a8c51b3fSopenharmony_ci  // or the end of the string if the suffix was omitted.
209a8c51b3fSopenharmony_ci  BM_CHECK(errno == 0 && p_end != nullptr &&
210a8c51b3fSopenharmony_ci           ((has_suffix && *p_end == 's') || *p_end == '\0'))
211a8c51b3fSopenharmony_ci      << "Malformed seconds value passed to --benchmark_min_time: `" << value
212a8c51b3fSopenharmony_ci      << "`. Expected --benchmark_min_time=<float>x.";
213a8c51b3fSopenharmony_ci
214a8c51b3fSopenharmony_ci  ret.tag = BenchTimeType::TIME;
215a8c51b3fSopenharmony_ci  ret.time = min_time;
216a8c51b3fSopenharmony_ci
217a8c51b3fSopenharmony_ci  return ret;
218a8c51b3fSopenharmony_ci}
219a8c51b3fSopenharmony_ci
220a8c51b3fSopenharmony_ciBenchmarkRunner::BenchmarkRunner(
221a8c51b3fSopenharmony_ci    const benchmark::internal::BenchmarkInstance& b_,
222a8c51b3fSopenharmony_ci    PerfCountersMeasurement* pcm_,
223a8c51b3fSopenharmony_ci    BenchmarkReporter::PerFamilyRunReports* reports_for_family_)
224a8c51b3fSopenharmony_ci    : b(b_),
225a8c51b3fSopenharmony_ci      reports_for_family(reports_for_family_),
226a8c51b3fSopenharmony_ci      parsed_benchtime_flag(ParseBenchMinTime(FLAGS_benchmark_min_time)),
227a8c51b3fSopenharmony_ci      min_time(ComputeMinTime(b_, parsed_benchtime_flag)),
228a8c51b3fSopenharmony_ci      min_warmup_time((!IsZero(b.min_time()) && b.min_warmup_time() > 0.0)
229a8c51b3fSopenharmony_ci                          ? b.min_warmup_time()
230a8c51b3fSopenharmony_ci                          : FLAGS_benchmark_min_warmup_time),
231a8c51b3fSopenharmony_ci      warmup_done(!(min_warmup_time > 0.0)),
232a8c51b3fSopenharmony_ci      repeats(b.repetitions() != 0 ? b.repetitions()
233a8c51b3fSopenharmony_ci                                   : FLAGS_benchmark_repetitions),
234a8c51b3fSopenharmony_ci      has_explicit_iteration_count(b.iterations() != 0 ||
235a8c51b3fSopenharmony_ci                                   parsed_benchtime_flag.tag ==
236a8c51b3fSopenharmony_ci                                       BenchTimeType::ITERS),
237a8c51b3fSopenharmony_ci      pool(b.threads() - 1),
238a8c51b3fSopenharmony_ci      iters(has_explicit_iteration_count
239a8c51b3fSopenharmony_ci                ? ComputeIters(b_, parsed_benchtime_flag)
240a8c51b3fSopenharmony_ci                : 1),
241a8c51b3fSopenharmony_ci      perf_counters_measurement_ptr(pcm_) {
242a8c51b3fSopenharmony_ci  run_results.display_report_aggregates_only =
243a8c51b3fSopenharmony_ci      (FLAGS_benchmark_report_aggregates_only ||
244a8c51b3fSopenharmony_ci       FLAGS_benchmark_display_aggregates_only);
245a8c51b3fSopenharmony_ci  run_results.file_report_aggregates_only =
246a8c51b3fSopenharmony_ci      FLAGS_benchmark_report_aggregates_only;
247a8c51b3fSopenharmony_ci  if (b.aggregation_report_mode() != internal::ARM_Unspecified) {
248a8c51b3fSopenharmony_ci    run_results.display_report_aggregates_only =
249a8c51b3fSopenharmony_ci        (b.aggregation_report_mode() &
250a8c51b3fSopenharmony_ci         internal::ARM_DisplayReportAggregatesOnly);
251a8c51b3fSopenharmony_ci    run_results.file_report_aggregates_only =
252a8c51b3fSopenharmony_ci        (b.aggregation_report_mode() & internal::ARM_FileReportAggregatesOnly);
253a8c51b3fSopenharmony_ci    BM_CHECK(FLAGS_benchmark_perf_counters.empty() ||
254a8c51b3fSopenharmony_ci             (perf_counters_measurement_ptr->num_counters() == 0))
255a8c51b3fSopenharmony_ci        << "Perf counters were requested but could not be set up.";
256a8c51b3fSopenharmony_ci  }
257a8c51b3fSopenharmony_ci}
258a8c51b3fSopenharmony_ci
259a8c51b3fSopenharmony_ciBenchmarkRunner::IterationResults BenchmarkRunner::DoNIterations() {
260a8c51b3fSopenharmony_ci  BM_VLOG(2) << "Running " << b.name().str() << " for " << iters << "\n";
261a8c51b3fSopenharmony_ci
262a8c51b3fSopenharmony_ci  std::unique_ptr<internal::ThreadManager> manager;
263a8c51b3fSopenharmony_ci  manager.reset(new internal::ThreadManager(b.threads()));
264a8c51b3fSopenharmony_ci
265a8c51b3fSopenharmony_ci  // Run all but one thread in separate threads
266a8c51b3fSopenharmony_ci  for (std::size_t ti = 0; ti < pool.size(); ++ti) {
267a8c51b3fSopenharmony_ci    pool[ti] = std::thread(&RunInThread, &b, iters, static_cast<int>(ti + 1),
268a8c51b3fSopenharmony_ci                           manager.get(), perf_counters_measurement_ptr);
269a8c51b3fSopenharmony_ci  }
270a8c51b3fSopenharmony_ci  // And run one thread here directly.
271a8c51b3fSopenharmony_ci  // (If we were asked to run just one thread, we don't create new threads.)
272a8c51b3fSopenharmony_ci  // Yes, we need to do this here *after* we start the separate threads.
273a8c51b3fSopenharmony_ci  RunInThread(&b, iters, 0, manager.get(), perf_counters_measurement_ptr);
274a8c51b3fSopenharmony_ci
275a8c51b3fSopenharmony_ci  // The main thread has finished. Now let's wait for the other threads.
276a8c51b3fSopenharmony_ci  manager->WaitForAllThreads();
277a8c51b3fSopenharmony_ci  for (std::thread& thread : pool) thread.join();
278a8c51b3fSopenharmony_ci
279a8c51b3fSopenharmony_ci  IterationResults i;
280a8c51b3fSopenharmony_ci  // Acquire the measurements/counters from the manager, UNDER THE LOCK!
281a8c51b3fSopenharmony_ci  {
282a8c51b3fSopenharmony_ci    MutexLock l(manager->GetBenchmarkMutex());
283a8c51b3fSopenharmony_ci    i.results = manager->results;
284a8c51b3fSopenharmony_ci  }
285a8c51b3fSopenharmony_ci
286a8c51b3fSopenharmony_ci  // And get rid of the manager.
287a8c51b3fSopenharmony_ci  manager.reset();
288a8c51b3fSopenharmony_ci
289a8c51b3fSopenharmony_ci  // Adjust real/manual time stats since they were reported per thread.
290a8c51b3fSopenharmony_ci  i.results.real_time_used /= b.threads();
291a8c51b3fSopenharmony_ci  i.results.manual_time_used /= b.threads();
292a8c51b3fSopenharmony_ci  // If we were measuring whole-process CPU usage, adjust the CPU time too.
293a8c51b3fSopenharmony_ci  if (b.measure_process_cpu_time()) i.results.cpu_time_used /= b.threads();
294a8c51b3fSopenharmony_ci
295a8c51b3fSopenharmony_ci  BM_VLOG(2) << "Ran in " << i.results.cpu_time_used << "/"
296a8c51b3fSopenharmony_ci             << i.results.real_time_used << "\n";
297a8c51b3fSopenharmony_ci
298a8c51b3fSopenharmony_ci  // By using KeepRunningBatch a benchmark can iterate more times than
299a8c51b3fSopenharmony_ci  // requested, so take the iteration count from i.results.
300a8c51b3fSopenharmony_ci  i.iters = i.results.iterations / b.threads();
301a8c51b3fSopenharmony_ci
302a8c51b3fSopenharmony_ci  // Base decisions off of real time if requested by this benchmark.
303a8c51b3fSopenharmony_ci  i.seconds = i.results.cpu_time_used;
304a8c51b3fSopenharmony_ci  if (b.use_manual_time()) {
305a8c51b3fSopenharmony_ci    i.seconds = i.results.manual_time_used;
306a8c51b3fSopenharmony_ci  } else if (b.use_real_time()) {
307a8c51b3fSopenharmony_ci    i.seconds = i.results.real_time_used;
308a8c51b3fSopenharmony_ci  }
309a8c51b3fSopenharmony_ci
310a8c51b3fSopenharmony_ci  return i;
311a8c51b3fSopenharmony_ci}
312a8c51b3fSopenharmony_ci
313a8c51b3fSopenharmony_ciIterationCount BenchmarkRunner::PredictNumItersNeeded(
314a8c51b3fSopenharmony_ci    const IterationResults& i) const {
315a8c51b3fSopenharmony_ci  // See how much iterations should be increased by.
316a8c51b3fSopenharmony_ci  // Note: Avoid division by zero with max(seconds, 1ns).
317a8c51b3fSopenharmony_ci  double multiplier = GetMinTimeToApply() * 1.4 / std::max(i.seconds, 1e-9);
318a8c51b3fSopenharmony_ci  // If our last run was at least 10% of FLAGS_benchmark_min_time then we
319a8c51b3fSopenharmony_ci  // use the multiplier directly.
320a8c51b3fSopenharmony_ci  // Otherwise we use at most 10 times expansion.
321a8c51b3fSopenharmony_ci  // NOTE: When the last run was at least 10% of the min time the max
322a8c51b3fSopenharmony_ci  // expansion should be 14x.
323a8c51b3fSopenharmony_ci  const bool is_significant = (i.seconds / GetMinTimeToApply()) > 0.1;
324a8c51b3fSopenharmony_ci  multiplier = is_significant ? multiplier : 10.0;
325a8c51b3fSopenharmony_ci
326a8c51b3fSopenharmony_ci  // So what seems to be the sufficiently-large iteration count? Round up.
327a8c51b3fSopenharmony_ci  const IterationCount max_next_iters = static_cast<IterationCount>(
328a8c51b3fSopenharmony_ci      std::lround(std::max(multiplier * static_cast<double>(i.iters),
329a8c51b3fSopenharmony_ci                           static_cast<double>(i.iters) + 1.0)));
330a8c51b3fSopenharmony_ci  // But we do have *some* limits though..
331a8c51b3fSopenharmony_ci  const IterationCount next_iters = std::min(max_next_iters, kMaxIterations);
332a8c51b3fSopenharmony_ci
333a8c51b3fSopenharmony_ci  BM_VLOG(3) << "Next iters: " << next_iters << ", " << multiplier << "\n";
334a8c51b3fSopenharmony_ci  return next_iters;  // round up before conversion to integer.
335a8c51b3fSopenharmony_ci}
336a8c51b3fSopenharmony_ci
337a8c51b3fSopenharmony_cibool BenchmarkRunner::ShouldReportIterationResults(
338a8c51b3fSopenharmony_ci    const IterationResults& i) const {
339a8c51b3fSopenharmony_ci  // Determine if this run should be reported;
340a8c51b3fSopenharmony_ci  // Either it has run for a sufficient amount of time
341a8c51b3fSopenharmony_ci  // or because an error was reported.
342a8c51b3fSopenharmony_ci  return i.results.skipped_ ||
343a8c51b3fSopenharmony_ci         i.iters >= kMaxIterations ||  // Too many iterations already.
344a8c51b3fSopenharmony_ci         i.seconds >=
345a8c51b3fSopenharmony_ci             GetMinTimeToApply() ||  // The elapsed time is large enough.
346a8c51b3fSopenharmony_ci         // CPU time is specified but the elapsed real time greatly exceeds
347a8c51b3fSopenharmony_ci         // the minimum time.
348a8c51b3fSopenharmony_ci         // Note that user provided timers are except from this test.
349a8c51b3fSopenharmony_ci         ((i.results.real_time_used >= 5 * GetMinTimeToApply()) &&
350a8c51b3fSopenharmony_ci          !b.use_manual_time());
351a8c51b3fSopenharmony_ci}
352a8c51b3fSopenharmony_ci
353a8c51b3fSopenharmony_cidouble BenchmarkRunner::GetMinTimeToApply() const {
354a8c51b3fSopenharmony_ci  // In order to re-use functionality to run and measure benchmarks for running
355a8c51b3fSopenharmony_ci  // a warmup phase of the benchmark, we need a way of telling whether to apply
356a8c51b3fSopenharmony_ci  // min_time or min_warmup_time. This function will figure out if we are in the
357a8c51b3fSopenharmony_ci  // warmup phase and therefore need to apply min_warmup_time or if we already
358a8c51b3fSopenharmony_ci  // in the benchmarking phase and min_time needs to be applied.
359a8c51b3fSopenharmony_ci  return warmup_done ? min_time : min_warmup_time;
360a8c51b3fSopenharmony_ci}
361a8c51b3fSopenharmony_ci
362a8c51b3fSopenharmony_civoid BenchmarkRunner::FinishWarmUp(const IterationCount& i) {
363a8c51b3fSopenharmony_ci  warmup_done = true;
364a8c51b3fSopenharmony_ci  iters = i;
365a8c51b3fSopenharmony_ci}
366a8c51b3fSopenharmony_ci
367a8c51b3fSopenharmony_civoid BenchmarkRunner::RunWarmUp() {
368a8c51b3fSopenharmony_ci  // Use the same mechanisms for warming up the benchmark as used for actually
369a8c51b3fSopenharmony_ci  // running and measuring the benchmark.
370a8c51b3fSopenharmony_ci  IterationResults i_warmup;
371a8c51b3fSopenharmony_ci  // Dont use the iterations determined in the warmup phase for the actual
372a8c51b3fSopenharmony_ci  // measured benchmark phase. While this may be a good starting point for the
373a8c51b3fSopenharmony_ci  // benchmark and it would therefore get rid of the need to figure out how many
374a8c51b3fSopenharmony_ci  // iterations are needed if min_time is set again, this may also be a complete
375a8c51b3fSopenharmony_ci  // wrong guess since the warmup loops might be considerably slower (e.g
376a8c51b3fSopenharmony_ci  // because of caching effects).
377a8c51b3fSopenharmony_ci  const IterationCount i_backup = iters;
378a8c51b3fSopenharmony_ci
379a8c51b3fSopenharmony_ci  for (;;) {
380a8c51b3fSopenharmony_ci    b.Setup();
381a8c51b3fSopenharmony_ci    i_warmup = DoNIterations();
382a8c51b3fSopenharmony_ci    b.Teardown();
383a8c51b3fSopenharmony_ci
384a8c51b3fSopenharmony_ci    const bool finish = ShouldReportIterationResults(i_warmup);
385a8c51b3fSopenharmony_ci
386a8c51b3fSopenharmony_ci    if (finish) {
387a8c51b3fSopenharmony_ci      FinishWarmUp(i_backup);
388a8c51b3fSopenharmony_ci      break;
389a8c51b3fSopenharmony_ci    }
390a8c51b3fSopenharmony_ci
391a8c51b3fSopenharmony_ci    // Although we are running "only" a warmup phase where running enough
392a8c51b3fSopenharmony_ci    // iterations at once without measuring time isn't as important as it is for
393a8c51b3fSopenharmony_ci    // the benchmarking phase, we still do it the same way as otherwise it is
394a8c51b3fSopenharmony_ci    // very confusing for the user to know how to choose a proper value for
395a8c51b3fSopenharmony_ci    // min_warmup_time if a different approach on running it is used.
396a8c51b3fSopenharmony_ci    iters = PredictNumItersNeeded(i_warmup);
397a8c51b3fSopenharmony_ci    assert(iters > i_warmup.iters &&
398a8c51b3fSopenharmony_ci           "if we did more iterations than we want to do the next time, "
399a8c51b3fSopenharmony_ci           "then we should have accepted the current iteration run.");
400a8c51b3fSopenharmony_ci  }
401a8c51b3fSopenharmony_ci}
402a8c51b3fSopenharmony_ci
403a8c51b3fSopenharmony_civoid BenchmarkRunner::DoOneRepetition() {
404a8c51b3fSopenharmony_ci  assert(HasRepeatsRemaining() && "Already done all repetitions?");
405a8c51b3fSopenharmony_ci
406a8c51b3fSopenharmony_ci  const bool is_the_first_repetition = num_repetitions_done == 0;
407a8c51b3fSopenharmony_ci
408a8c51b3fSopenharmony_ci  // In case a warmup phase is requested by the benchmark, run it now.
409a8c51b3fSopenharmony_ci  // After running the warmup phase the BenchmarkRunner should be in a state as
410a8c51b3fSopenharmony_ci  // this warmup never happened except the fact that warmup_done is set. Every
411a8c51b3fSopenharmony_ci  // other manipulation of the BenchmarkRunner instance would be a bug! Please
412a8c51b3fSopenharmony_ci  // fix it.
413a8c51b3fSopenharmony_ci  if (!warmup_done) RunWarmUp();
414a8c51b3fSopenharmony_ci
415a8c51b3fSopenharmony_ci  IterationResults i;
416a8c51b3fSopenharmony_ci  // We *may* be gradually increasing the length (iteration count)
417a8c51b3fSopenharmony_ci  // of the benchmark until we decide the results are significant.
418a8c51b3fSopenharmony_ci  // And once we do, we report those last results and exit.
419a8c51b3fSopenharmony_ci  // Please do note that the if there are repetitions, the iteration count
420a8c51b3fSopenharmony_ci  // is *only* calculated for the *first* repetition, and other repetitions
421a8c51b3fSopenharmony_ci  // simply use that precomputed iteration count.
422a8c51b3fSopenharmony_ci  for (;;) {
423a8c51b3fSopenharmony_ci    b.Setup();
424a8c51b3fSopenharmony_ci    i = DoNIterations();
425a8c51b3fSopenharmony_ci    b.Teardown();
426a8c51b3fSopenharmony_ci
427a8c51b3fSopenharmony_ci    // Do we consider the results to be significant?
428a8c51b3fSopenharmony_ci    // If we are doing repetitions, and the first repetition was already done,
429a8c51b3fSopenharmony_ci    // it has calculated the correct iteration time, so we have run that very
430a8c51b3fSopenharmony_ci    // iteration count just now. No need to calculate anything. Just report.
431a8c51b3fSopenharmony_ci    // Else, the normal rules apply.
432a8c51b3fSopenharmony_ci    const bool results_are_significant = !is_the_first_repetition ||
433a8c51b3fSopenharmony_ci                                         has_explicit_iteration_count ||
434a8c51b3fSopenharmony_ci                                         ShouldReportIterationResults(i);
435a8c51b3fSopenharmony_ci
436a8c51b3fSopenharmony_ci    if (results_are_significant) break;  // Good, let's report them!
437a8c51b3fSopenharmony_ci
438a8c51b3fSopenharmony_ci    // Nope, bad iteration. Let's re-estimate the hopefully-sufficient
439a8c51b3fSopenharmony_ci    // iteration count, and run the benchmark again...
440a8c51b3fSopenharmony_ci
441a8c51b3fSopenharmony_ci    iters = PredictNumItersNeeded(i);
442a8c51b3fSopenharmony_ci    assert(iters > i.iters &&
443a8c51b3fSopenharmony_ci           "if we did more iterations than we want to do the next time, "
444a8c51b3fSopenharmony_ci           "then we should have accepted the current iteration run.");
445a8c51b3fSopenharmony_ci  }
446a8c51b3fSopenharmony_ci
447a8c51b3fSopenharmony_ci  // Oh, one last thing, we need to also produce the 'memory measurements'..
448a8c51b3fSopenharmony_ci  MemoryManager::Result* memory_result = nullptr;
449a8c51b3fSopenharmony_ci  IterationCount memory_iterations = 0;
450a8c51b3fSopenharmony_ci  if (memory_manager != nullptr) {
451a8c51b3fSopenharmony_ci    // TODO(vyng): Consider making BenchmarkReporter::Run::memory_result an
452a8c51b3fSopenharmony_ci    // optional so we don't have to own the Result here.
453a8c51b3fSopenharmony_ci    // Can't do it now due to cxx03.
454a8c51b3fSopenharmony_ci    memory_results.push_back(MemoryManager::Result());
455a8c51b3fSopenharmony_ci    memory_result = &memory_results.back();
456a8c51b3fSopenharmony_ci    // Only run a few iterations to reduce the impact of one-time
457a8c51b3fSopenharmony_ci    // allocations in benchmarks that are not properly managed.
458a8c51b3fSopenharmony_ci    memory_iterations = std::min<IterationCount>(16, iters);
459a8c51b3fSopenharmony_ci    memory_manager->Start();
460a8c51b3fSopenharmony_ci    std::unique_ptr<internal::ThreadManager> manager;
461a8c51b3fSopenharmony_ci    manager.reset(new internal::ThreadManager(1));
462a8c51b3fSopenharmony_ci    b.Setup();
463a8c51b3fSopenharmony_ci    RunInThread(&b, memory_iterations, 0, manager.get(),
464a8c51b3fSopenharmony_ci                perf_counters_measurement_ptr);
465a8c51b3fSopenharmony_ci    manager->WaitForAllThreads();
466a8c51b3fSopenharmony_ci    manager.reset();
467a8c51b3fSopenharmony_ci    b.Teardown();
468a8c51b3fSopenharmony_ci    memory_manager->Stop(*memory_result);
469a8c51b3fSopenharmony_ci  }
470a8c51b3fSopenharmony_ci
471a8c51b3fSopenharmony_ci  // Ok, now actually report.
472a8c51b3fSopenharmony_ci  BenchmarkReporter::Run report =
473a8c51b3fSopenharmony_ci      CreateRunReport(b, i.results, memory_iterations, memory_result, i.seconds,
474a8c51b3fSopenharmony_ci                      num_repetitions_done, repeats);
475a8c51b3fSopenharmony_ci
476a8c51b3fSopenharmony_ci  if (reports_for_family) {
477a8c51b3fSopenharmony_ci    ++reports_for_family->num_runs_done;
478a8c51b3fSopenharmony_ci    if (!report.skipped) reports_for_family->Runs.push_back(report);
479a8c51b3fSopenharmony_ci  }
480a8c51b3fSopenharmony_ci
481a8c51b3fSopenharmony_ci  run_results.non_aggregates.push_back(report);
482a8c51b3fSopenharmony_ci
483a8c51b3fSopenharmony_ci  ++num_repetitions_done;
484a8c51b3fSopenharmony_ci}
485a8c51b3fSopenharmony_ci
486a8c51b3fSopenharmony_ciRunResults&& BenchmarkRunner::GetResults() {
487a8c51b3fSopenharmony_ci  assert(!HasRepeatsRemaining() && "Did not run all repetitions yet?");
488a8c51b3fSopenharmony_ci
489a8c51b3fSopenharmony_ci  // Calculate additional statistics over the repetitions of this instance.
490a8c51b3fSopenharmony_ci  run_results.aggregates_only = ComputeStats(run_results.non_aggregates);
491a8c51b3fSopenharmony_ci
492a8c51b3fSopenharmony_ci  return std::move(run_results);
493a8c51b3fSopenharmony_ci}
494a8c51b3fSopenharmony_ci
495a8c51b3fSopenharmony_ci}  // end namespace internal
496a8c51b3fSopenharmony_ci
497a8c51b3fSopenharmony_ci}  // end namespace benchmark
498