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