1 // Copyright 2015 Google Inc. All rights reserved.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 #include "benchmark/benchmark.h"
16 #include "internal_macros.h"
17
18 #ifndef BENCHMARK_OS_WINDOWS
19 #include <sys/time.h>
20 #include <sys/resource.h>
21 #include <unistd.h>
22 #endif
23
24 #include <cstdlib>
25 #include <cstring>
26 #include <cstdio>
27 #include <algorithm>
28 #include <atomic>
29 #include <condition_variable>
30 #include <iostream>
31 #include <memory>
32 #include <thread>
33
34 #include "check.h"
35 #include "commandlineflags.h"
36 #include "log.h"
37 #include "mutex.h"
38 #include "re.h"
39 #include "stat.h"
40 #include "string_util.h"
41 #include "sysinfo.h"
42 #include "walltime.h"
43
44 DEFINE_bool(benchmark_list_tests, false,
45 "Print a list of benchmarks. This option overrides all other "
46 "options.");
47
48 DEFINE_string(benchmark_filter, ".",
49 "A regular expression that specifies the set of benchmarks "
50 "to execute. If this flag is empty, no benchmarks are run. "
51 "If this flag is the string \"all\", all benchmarks linked "
52 "into the process are run.");
53
54 DEFINE_double(benchmark_min_time, 0.5,
55 "Minimum number of seconds we should run benchmark before "
56 "results are considered significant. For cpu-time based "
57 "tests, this is the lower bound on the total cpu time "
58 "used by all threads that make up the test. For real-time "
59 "based tests, this is the lower bound on the elapsed time "
60 "of the benchmark execution, regardless of number of "
61 "threads.");
62
63 DEFINE_int32(benchmark_repetitions, 1,
64 "The number of runs of each benchmark. If greater than 1, the "
65 "mean and standard deviation of the runs will be reported.");
66
67 DEFINE_string(benchmark_format, "tabular",
68 "The format to use for console output. Valid values are "
69 "'tabular', 'json', or 'csv'.");
70
71 DEFINE_bool(color_print, true, "Enables colorized logging.");
72
73 DEFINE_int32(v, 0, "The level of verbose logging to output");
74
75
76 namespace benchmark {
77
78 namespace internal {
79
UseCharPointer(char const volatile *)80 void UseCharPointer(char const volatile*) {}
81
82 // NOTE: This is a dummy "mutex" type used to denote the actual mutex
83 // returned by GetBenchmarkLock(). This is only used to placate the thread
84 // safety warnings by giving the return of GetBenchmarkLock() a name.
85 struct CAPABILITY("mutex") BenchmarkLockType {};
86 BenchmarkLockType BenchmarkLockVar;
87
88 } // end namespace internal
89
RETURN_CAPABILITY(::benchmark::internal::BenchmarkLockVar)90 inline Mutex& RETURN_CAPABILITY(::benchmark::internal::BenchmarkLockVar)
91 GetBenchmarkLock()
92 {
93 static Mutex lock;
94 return lock;
95 }
96
97 namespace {
98
IsZero(double n)99 bool IsZero(double n) {
100 return std::abs(n) < std::numeric_limits<double>::epsilon();
101 }
102
103 // For non-dense Range, intermediate values are powers of kRangeMultiplier.
104 static const int kRangeMultiplier = 8;
105 static const size_t kMaxIterations = 1000000000;
106
107 bool running_benchmark = false;
108
109 // Global variable so that a benchmark can cause a little extra printing
GetReportLabel()110 std::string* GetReportLabel() {
111 static std::string label GUARDED_BY(GetBenchmarkLock());
112 return &label;
113 }
114
115 // TODO(ericwf): support MallocCounter.
116 //static benchmark::MallocCounter *benchmark_mc;
117
118 struct ThreadStats {
ThreadStatsbenchmark::__anonc646188b0111::ThreadStats119 ThreadStats() : bytes_processed(0), items_processed(0) {}
120 int64_t bytes_processed;
121 int64_t items_processed;
122 };
123
124 // Timer management class
125 class TimerManager {
126 public:
TimerManager(int num_threads,Notification * done)127 TimerManager(int num_threads, Notification* done)
128 : num_threads_(num_threads),
129 done_(done),
130 running_(false),
131 real_time_used_(0),
132 cpu_time_used_(0),
133 num_finalized_(0),
134 phase_number_(0),
135 entered_(0) {
136 }
137
138 // Called by each thread
StartTimer()139 void StartTimer() EXCLUDES(lock_) {
140 bool last_thread = false;
141 {
142 MutexLock ml(lock_);
143 last_thread = Barrier(ml);
144 if (last_thread) {
145 CHECK(!running_) << "Called StartTimer when timer is already running";
146 running_ = true;
147 start_real_time_ = walltime::Now();
148 start_cpu_time_ = MyCPUUsage() + ChildrenCPUUsage();
149 }
150 }
151 if (last_thread) {
152 phase_condition_.notify_all();
153 }
154 }
155
156 // Called by each thread
StopTimer()157 void StopTimer() EXCLUDES(lock_) {
158 bool last_thread = false;
159 {
160 MutexLock ml(lock_);
161 last_thread = Barrier(ml);
162 if (last_thread) {
163 CHECK(running_) << "Called StopTimer when timer is already stopped";
164 InternalStop();
165 }
166 }
167 if (last_thread) {
168 phase_condition_.notify_all();
169 }
170 }
171
172 // Called by each thread
Finalize()173 void Finalize() EXCLUDES(lock_) {
174 MutexLock l(lock_);
175 num_finalized_++;
176 if (num_finalized_ == num_threads_) {
177 CHECK(!running_) <<
178 "The timer should be stopped before the timer is finalized";
179 done_->Notify();
180 }
181 }
182
183 // REQUIRES: timer is not running
real_time_used()184 double real_time_used() EXCLUDES(lock_) {
185 MutexLock l(lock_);
186 CHECK(!running_);
187 return real_time_used_;
188 }
189
190 // REQUIRES: timer is not running
cpu_time_used()191 double cpu_time_used() EXCLUDES(lock_) {
192 MutexLock l(lock_);
193 CHECK(!running_);
194 return cpu_time_used_;
195 }
196
197 private:
198 Mutex lock_;
199 Condition phase_condition_;
200 int num_threads_;
201 Notification* done_;
202
203 bool running_; // Is the timer running
204 double start_real_time_; // If running_
205 double start_cpu_time_; // If running_
206
207 // Accumulated time so far (does not contain current slice if running_)
208 double real_time_used_;
209 double cpu_time_used_;
210
211 // How many threads have called Finalize()
212 int num_finalized_;
213
214 // State for barrier management
215 int phase_number_;
216 int entered_; // Number of threads that have entered this barrier
217
InternalStop()218 void InternalStop() REQUIRES(lock_) {
219 CHECK(running_);
220 running_ = false;
221 real_time_used_ += walltime::Now() - start_real_time_;
222 cpu_time_used_ += ((MyCPUUsage() + ChildrenCPUUsage())
223 - start_cpu_time_);
224 }
225
226 // Enter the barrier and wait until all other threads have also
227 // entered the barrier. Returns iff this is the last thread to
228 // enter the barrier.
Barrier(MutexLock & ml)229 bool Barrier(MutexLock& ml) REQUIRES(lock_) {
230 CHECK_LT(entered_, num_threads_);
231 entered_++;
232 if (entered_ < num_threads_) {
233 // Wait for all threads to enter
234 int phase_number_cp = phase_number_;
235 auto cb = [this, phase_number_cp]() {
236 return this->phase_number_ > phase_number_cp;
237 };
238 phase_condition_.wait(ml.native_handle(), cb);
239 return false; // I was not the last one
240 } else {
241 // Last thread has reached the barrier
242 phase_number_++;
243 entered_ = 0;
244 return true;
245 }
246 }
247 };
248
249 // TimerManager for current run.
250 static std::unique_ptr<TimerManager> timer_manager = nullptr;
251
252 } // end namespace
253
254 namespace internal {
255
256 // Information kept per benchmark we may want to run
257 struct Benchmark::Instance {
258 std::string name;
259 Benchmark* benchmark;
260 bool has_arg1;
261 int arg1;
262 bool has_arg2;
263 int arg2;
264 bool use_real_time;
265 double min_time;
266 int threads; // Number of concurrent threads to use
267 bool multithreaded; // Is benchmark multi-threaded?
268 };
269
270 // Class for managing registered benchmarks. Note that each registered
271 // benchmark identifies a family of related benchmarks to run.
272 class BenchmarkFamilies {
273 public:
274 static BenchmarkFamilies* GetInstance();
275
276 // Registers a benchmark family and returns the index assigned to it.
277 size_t AddBenchmark(std::unique_ptr<Benchmark> family);
278
279 // Extract the list of benchmark instances that match the specified
280 // regular expression.
281 bool FindBenchmarks(const std::string& re,
282 std::vector<Benchmark::Instance>* benchmarks);
283 private:
BenchmarkFamilies()284 BenchmarkFamilies() {}
285
286 std::vector<std::unique_ptr<Benchmark>> families_;
287 Mutex mutex_;
288 };
289
290
291 class BenchmarkImp {
292 public:
293 explicit BenchmarkImp(const char* name);
294 ~BenchmarkImp();
295
296 void Arg(int x);
297 void Range(int start, int limit);
298 void DenseRange(int start, int limit);
299 void ArgPair(int start, int limit);
300 void RangePair(int lo1, int hi1, int lo2, int hi2);
301 void MinTime(double n);
302 void UseRealTime();
303 void Threads(int t);
304 void ThreadRange(int min_threads, int max_threads);
305 void ThreadPerCpu();
306 void SetName(const char* name);
307
308 static void AddRange(std::vector<int>* dst, int lo, int hi, int mult);
309
310 private:
311 friend class BenchmarkFamilies;
312
313 std::string name_;
314 int arg_count_;
315 std::vector< std::pair<int, int> > args_; // Args for all benchmark runs
316 double min_time_;
317 bool use_real_time_;
318 std::vector<int> thread_counts_;
319
320 BenchmarkImp& operator=(BenchmarkImp const&);
321 };
322
GetInstance()323 BenchmarkFamilies* BenchmarkFamilies::GetInstance() {
324 static BenchmarkFamilies instance;
325 return &instance;
326 }
327
328
AddBenchmark(std::unique_ptr<Benchmark> family)329 size_t BenchmarkFamilies::AddBenchmark(std::unique_ptr<Benchmark> family) {
330 MutexLock l(mutex_);
331 size_t index = families_.size();
332 families_.push_back(std::move(family));
333 return index;
334 }
335
FindBenchmarks(const std::string & spec,std::vector<Benchmark::Instance> * benchmarks)336 bool BenchmarkFamilies::FindBenchmarks(
337 const std::string& spec,
338 std::vector<Benchmark::Instance>* benchmarks) {
339 // Make regular expression out of command-line flag
340 std::string error_msg;
341 Regex re;
342 if (!re.Init(spec, &error_msg)) {
343 std::cerr << "Could not compile benchmark re: " << error_msg << std::endl;
344 return false;
345 }
346
347 // Special list of thread counts to use when none are specified
348 std::vector<int> one_thread;
349 one_thread.push_back(1);
350
351 MutexLock l(mutex_);
352 for (std::unique_ptr<Benchmark>& bench_family : families_) {
353 // Family was deleted or benchmark doesn't match
354 if (!bench_family) continue;
355 BenchmarkImp* family = bench_family->imp_;
356
357 if (family->arg_count_ == -1) {
358 family->arg_count_ = 0;
359 family->args_.emplace_back(-1, -1);
360 }
361 for (auto const& args : family->args_) {
362 const std::vector<int>* thread_counts =
363 (family->thread_counts_.empty()
364 ? &one_thread
365 : &family->thread_counts_);
366 for (int num_threads : *thread_counts) {
367
368 Benchmark::Instance instance;
369 instance.name = family->name_;
370 instance.benchmark = bench_family.get();
371 instance.has_arg1 = family->arg_count_ >= 1;
372 instance.arg1 = args.first;
373 instance.has_arg2 = family->arg_count_ == 2;
374 instance.arg2 = args.second;
375 instance.min_time = family->min_time_;
376 instance.use_real_time = family->use_real_time_;
377 instance.threads = num_threads;
378 instance.multithreaded = !(family->thread_counts_.empty());
379
380 // Add arguments to instance name
381 if (family->arg_count_ >= 1) {
382 AppendHumanReadable(instance.arg1, &instance.name);
383 }
384 if (family->arg_count_ >= 2) {
385 AppendHumanReadable(instance.arg2, &instance.name);
386 }
387 if (!IsZero(family->min_time_)) {
388 instance.name += StringPrintF("/min_time:%0.3f", family->min_time_);
389 }
390 if (family->use_real_time_) {
391 instance.name += "/real_time";
392 }
393
394 // Add the number of threads used to the name
395 if (!family->thread_counts_.empty()) {
396 instance.name += StringPrintF("/threads:%d", instance.threads);
397 }
398
399 if (re.Match(instance.name)) {
400 benchmarks->push_back(instance);
401 }
402 }
403 }
404 }
405 return true;
406 }
407
BenchmarkImp(const char * name)408 BenchmarkImp::BenchmarkImp(const char* name)
409 : name_(name), arg_count_(-1),
410 min_time_(0.0), use_real_time_(false) {
411 }
412
~BenchmarkImp()413 BenchmarkImp::~BenchmarkImp() {
414 }
415
Arg(int x)416 void BenchmarkImp::Arg(int x) {
417 CHECK(arg_count_ == -1 || arg_count_ == 1);
418 arg_count_ = 1;
419 args_.emplace_back(x, -1);
420 }
421
Range(int start,int limit)422 void BenchmarkImp::Range(int start, int limit) {
423 CHECK(arg_count_ == -1 || arg_count_ == 1);
424 arg_count_ = 1;
425 std::vector<int> arglist;
426 AddRange(&arglist, start, limit, kRangeMultiplier);
427
428 for (int i : arglist) {
429 args_.emplace_back(i, -1);
430 }
431 }
432
DenseRange(int start,int limit)433 void BenchmarkImp::DenseRange(int start, int limit) {
434 CHECK(arg_count_ == -1 || arg_count_ == 1);
435 arg_count_ = 1;
436 CHECK_GE(start, 0);
437 CHECK_LE(start, limit);
438 for (int arg = start; arg <= limit; arg++) {
439 args_.emplace_back(arg, -1);
440 }
441 }
442
ArgPair(int x,int y)443 void BenchmarkImp::ArgPair(int x, int y) {
444 CHECK(arg_count_ == -1 || arg_count_ == 2);
445 arg_count_ = 2;
446 args_.emplace_back(x, y);
447 }
448
RangePair(int lo1,int hi1,int lo2,int hi2)449 void BenchmarkImp::RangePair(int lo1, int hi1, int lo2, int hi2) {
450 CHECK(arg_count_ == -1 || arg_count_ == 2);
451 arg_count_ = 2;
452 std::vector<int> arglist1, arglist2;
453 AddRange(&arglist1, lo1, hi1, kRangeMultiplier);
454 AddRange(&arglist2, lo2, hi2, kRangeMultiplier);
455
456 for (int i : arglist1) {
457 for (int j : arglist2) {
458 args_.emplace_back(i, j);
459 }
460 }
461 }
462
MinTime(double t)463 void BenchmarkImp::MinTime(double t) {
464 CHECK(t > 0.0);
465 min_time_ = t;
466 }
467
UseRealTime()468 void BenchmarkImp::UseRealTime() {
469 use_real_time_ = true;
470 }
471
Threads(int t)472 void BenchmarkImp::Threads(int t) {
473 CHECK_GT(t, 0);
474 thread_counts_.push_back(t);
475 }
476
ThreadRange(int min_threads,int max_threads)477 void BenchmarkImp::ThreadRange(int min_threads, int max_threads) {
478 CHECK_GT(min_threads, 0);
479 CHECK_GE(max_threads, min_threads);
480
481 AddRange(&thread_counts_, min_threads, max_threads, 2);
482 }
483
ThreadPerCpu()484 void BenchmarkImp::ThreadPerCpu() {
485 static int num_cpus = NumCPUs();
486 thread_counts_.push_back(num_cpus);
487 }
488
SetName(const char * name)489 void BenchmarkImp::SetName(const char* name) {
490 name_ = name;
491 }
492
AddRange(std::vector<int> * dst,int lo,int hi,int mult)493 void BenchmarkImp::AddRange(std::vector<int>* dst, int lo, int hi, int mult) {
494 CHECK_GE(lo, 0);
495 CHECK_GE(hi, lo);
496
497 // Add "lo"
498 dst->push_back(lo);
499
500 static const int kint32max = std::numeric_limits<int32_t>::max();
501
502 // Now space out the benchmarks in multiples of "mult"
503 for (int32_t i = 1; i < kint32max/mult; i *= mult) {
504 if (i >= hi) break;
505 if (i > lo) {
506 dst->push_back(i);
507 }
508 }
509 // Add "hi" (if different from "lo")
510 if (hi != lo) {
511 dst->push_back(hi);
512 }
513 }
514
Benchmark(const char * name)515 Benchmark::Benchmark(const char* name)
516 : imp_(new BenchmarkImp(name))
517 {
518 }
519
~Benchmark()520 Benchmark::~Benchmark() {
521 delete imp_;
522 }
523
Benchmark(Benchmark const & other)524 Benchmark::Benchmark(Benchmark const& other)
525 : imp_(new BenchmarkImp(*other.imp_))
526 {
527 }
528
Arg(int x)529 Benchmark* Benchmark::Arg(int x) {
530 imp_->Arg(x);
531 return this;
532 }
533
Range(int start,int limit)534 Benchmark* Benchmark::Range(int start, int limit) {
535 imp_->Range(start, limit);
536 return this;
537 }
538
DenseRange(int start,int limit)539 Benchmark* Benchmark::DenseRange(int start, int limit) {
540 imp_->DenseRange(start, limit);
541 return this;
542 }
543
ArgPair(int x,int y)544 Benchmark* Benchmark::ArgPair(int x, int y) {
545 imp_->ArgPair(x, y);
546 return this;
547 }
548
RangePair(int lo1,int hi1,int lo2,int hi2)549 Benchmark* Benchmark::RangePair(int lo1, int hi1, int lo2, int hi2) {
550 imp_->RangePair(lo1, hi1, lo2, hi2);
551 return this;
552 }
553
Apply(void (* custom_arguments)(Benchmark * benchmark))554 Benchmark* Benchmark::Apply(void (*custom_arguments)(Benchmark* benchmark)) {
555 custom_arguments(this);
556 return this;
557 }
558
MinTime(double t)559 Benchmark* Benchmark::MinTime(double t) {
560 imp_->MinTime(t);
561 return this;
562 }
563
UseRealTime()564 Benchmark* Benchmark::UseRealTime() {
565 imp_->UseRealTime();
566 return this;
567 }
568
Threads(int t)569 Benchmark* Benchmark::Threads(int t) {
570 imp_->Threads(t);
571 return this;
572 }
573
ThreadRange(int min_threads,int max_threads)574 Benchmark* Benchmark::ThreadRange(int min_threads, int max_threads) {
575 imp_->ThreadRange(min_threads, max_threads);
576 return this;
577 }
578
ThreadPerCpu()579 Benchmark* Benchmark::ThreadPerCpu() {
580 imp_->ThreadPerCpu();
581 return this;
582 }
583
SetName(const char * name)584 void Benchmark::SetName(const char* name) {
585 imp_->SetName(name);
586 }
587
Run(State & st)588 void FunctionBenchmark::Run(State& st) {
589 func_(st);
590 }
591
592 } // end namespace internal
593
594 namespace {
595
596
597 // Execute one thread of benchmark b for the specified number of iterations.
598 // Adds the stats collected for the thread into *total.
RunInThread(const benchmark::internal::Benchmark::Instance * b,size_t iters,int thread_id,ThreadStats * total)599 void RunInThread(const benchmark::internal::Benchmark::Instance* b,
600 size_t iters, int thread_id,
601 ThreadStats* total) EXCLUDES(GetBenchmarkLock()) {
602 State st(iters, b->has_arg1, b->arg1, b->has_arg2, b->arg2, thread_id, b->threads);
603 b->benchmark->Run(st);
604 CHECK(st.iterations() == st.max_iterations) <<
605 "Benchmark returned before State::KeepRunning() returned false!";
606 {
607 MutexLock l(GetBenchmarkLock());
608 total->bytes_processed += st.bytes_processed();
609 total->items_processed += st.items_processed();
610 }
611
612 timer_manager->Finalize();
613 }
614
RunBenchmark(const benchmark::internal::Benchmark::Instance & b,BenchmarkReporter * br)615 void RunBenchmark(const benchmark::internal::Benchmark::Instance& b,
616 BenchmarkReporter* br) EXCLUDES(GetBenchmarkLock()) {
617 size_t iters = 1;
618
619 std::vector<BenchmarkReporter::Run> reports;
620
621 std::vector<std::thread> pool;
622 if (b.multithreaded)
623 pool.resize(b.threads);
624
625 for (int i = 0; i < FLAGS_benchmark_repetitions; i++) {
626 std::string mem;
627 for (;;) {
628 // Try benchmark
629 VLOG(2) << "Running " << b.name << " for " << iters << "\n";
630
631 {
632 MutexLock l(GetBenchmarkLock());
633 GetReportLabel()->clear();
634 }
635
636 Notification done;
637 timer_manager = std::unique_ptr<TimerManager>(new TimerManager(b.threads, &done));
638
639 ThreadStats total;
640 running_benchmark = true;
641 if (b.multithreaded) {
642 // If this is out first iteration of the while(true) loop then the
643 // threads haven't been started and can't be joined. Otherwise we need
644 // to join the thread before replacing them.
645 for (std::thread& thread : pool) {
646 if (thread.joinable())
647 thread.join();
648 }
649 for (std::size_t ti = 0; ti < pool.size(); ++ti) {
650 pool[ti] = std::thread(&RunInThread, &b, iters, ti, &total);
651 }
652 } else {
653 // Run directly in this thread
654 RunInThread(&b, iters, 0, &total);
655 }
656 done.WaitForNotification();
657 running_benchmark = false;
658
659 const double cpu_accumulated_time = timer_manager->cpu_time_used();
660 const double real_accumulated_time = timer_manager->real_time_used();
661 timer_manager.reset();
662
663 VLOG(2) << "Ran in " << cpu_accumulated_time << "/"
664 << real_accumulated_time << "\n";
665
666 // Base decisions off of real time if requested by this benchmark.
667 double seconds = cpu_accumulated_time;
668 if (b.use_real_time) {
669 seconds = real_accumulated_time;
670 }
671
672 std::string label;
673 {
674 MutexLock l(GetBenchmarkLock());
675 label = *GetReportLabel();
676 }
677
678 const double min_time = !IsZero(b.min_time) ? b.min_time
679 : FLAGS_benchmark_min_time;
680
681 // If this was the first run, was elapsed time or cpu time large enough?
682 // If this is not the first run, go with the current value of iter.
683 if ((i > 0) ||
684 (iters >= kMaxIterations) ||
685 (seconds >= min_time) ||
686 (real_accumulated_time >= 5*min_time)) {
687 double bytes_per_second = 0;
688 if (total.bytes_processed > 0 && seconds > 0.0) {
689 bytes_per_second = (total.bytes_processed / seconds);
690 }
691 double items_per_second = 0;
692 if (total.items_processed > 0 && seconds > 0.0) {
693 items_per_second = (total.items_processed / seconds);
694 }
695
696 // Create report about this benchmark run.
697 BenchmarkReporter::Run report;
698 report.benchmark_name = b.name;
699 report.report_label = label;
700 // Report the total iterations across all threads.
701 report.iterations = static_cast<int64_t>(iters) * b.threads;
702 report.real_accumulated_time = real_accumulated_time;
703 report.cpu_accumulated_time = cpu_accumulated_time;
704 report.bytes_per_second = bytes_per_second;
705 report.items_per_second = items_per_second;
706 reports.push_back(report);
707 break;
708 }
709
710 // See how much iterations should be increased by
711 // Note: Avoid division by zero with max(seconds, 1ns).
712 double multiplier = min_time * 1.4 / std::max(seconds, 1e-9);
713 // If our last run was at least 10% of FLAGS_benchmark_min_time then we
714 // use the multiplier directly. Otherwise we use at most 10 times
715 // expansion.
716 // NOTE: When the last run was at least 10% of the min time the max
717 // expansion should be 14x.
718 bool is_significant = (seconds / min_time) > 0.1;
719 multiplier = is_significant ? multiplier : std::min(10.0, multiplier);
720 if (multiplier <= 1.0) multiplier = 2.0;
721 double next_iters = std::max(multiplier * iters, iters + 1.0);
722 if (next_iters > kMaxIterations) {
723 next_iters = kMaxIterations;
724 }
725 VLOG(3) << "Next iters: " << next_iters << ", " << multiplier << "\n";
726 iters = static_cast<int>(next_iters + 0.5);
727 }
728 }
729 br->ReportRuns(reports);
730 if (b.multithreaded) {
731 for (std::thread& thread : pool)
732 thread.join();
733 }
734 }
735
736 } // namespace
737
State(size_t max_iters,bool has_x,int x,bool has_y,int y,int thread_i,int n_threads)738 State::State(size_t max_iters, bool has_x, int x, bool has_y, int y,
739 int thread_i, int n_threads)
740 : started_(false), total_iterations_(0),
741 has_range_x_(has_x), range_x_(x),
742 has_range_y_(has_y), range_y_(y),
743 bytes_processed_(0), items_processed_(0),
744 thread_index(thread_i),
745 threads(n_threads),
746 max_iterations(max_iters)
747 {
748 CHECK(max_iterations != 0) << "At least one iteration must be run";
749 CHECK_LT(thread_index, threads) << "thread_index must be less than threads";
750 }
751
PauseTiming()752 void State::PauseTiming() {
753 // Add in time accumulated so far
754 CHECK(running_benchmark);
755 timer_manager->StopTimer();
756 }
757
ResumeTiming()758 void State::ResumeTiming() {
759 CHECK(running_benchmark);
760 timer_manager->StartTimer();
761 }
762
SetLabel(const char * label)763 void State::SetLabel(const char* label) {
764 CHECK(running_benchmark);
765 MutexLock l(GetBenchmarkLock());
766 *GetReportLabel() = label;
767 }
768
769 namespace internal {
770 namespace {
771
PrintBenchmarkList()772 void PrintBenchmarkList() {
773 std::vector<Benchmark::Instance> benchmarks;
774 auto families = BenchmarkFamilies::GetInstance();
775 if (!families->FindBenchmarks(".", &benchmarks)) return;
776
777 for (const internal::Benchmark::Instance& benchmark : benchmarks) {
778 std::cout << benchmark.name << "\n";
779 }
780 }
781
RunMatchingBenchmarks(const std::string & spec,BenchmarkReporter * reporter)782 void RunMatchingBenchmarks(const std::string& spec,
783 BenchmarkReporter* reporter) {
784 CHECK(reporter != nullptr);
785 if (spec.empty()) return;
786
787 std::vector<Benchmark::Instance> benchmarks;
788 auto families = BenchmarkFamilies::GetInstance();
789 if (!families->FindBenchmarks(spec, &benchmarks)) return;
790
791 // Determine the width of the name field using a minimum width of 10.
792 size_t name_field_width = 10;
793 for (const Benchmark::Instance& benchmark : benchmarks) {
794 name_field_width =
795 std::max<size_t>(name_field_width, benchmark.name.size());
796 }
797 if (FLAGS_benchmark_repetitions > 1)
798 name_field_width += std::strlen("_stddev");
799
800 // Print header here
801 BenchmarkReporter::Context context;
802 context.num_cpus = NumCPUs();
803 context.mhz_per_cpu = CyclesPerSecond() / 1000000.0f;
804
805 context.cpu_scaling_enabled = CpuScalingEnabled();
806 context.name_field_width = name_field_width;
807
808 if (reporter->ReportContext(context)) {
809 for (const auto& benchmark : benchmarks) {
810 RunBenchmark(benchmark, reporter);
811 }
812 }
813 }
814
GetDefaultReporter()815 std::unique_ptr<BenchmarkReporter> GetDefaultReporter() {
816 typedef std::unique_ptr<BenchmarkReporter> PtrType;
817 if (FLAGS_benchmark_format == "tabular") {
818 return PtrType(new ConsoleReporter);
819 } else if (FLAGS_benchmark_format == "json") {
820 return PtrType(new JSONReporter);
821 } else if (FLAGS_benchmark_format == "csv") {
822 return PtrType(new CSVReporter);
823 } else {
824 std::cerr << "Unexpected format: '" << FLAGS_benchmark_format << "'\n";
825 std::exit(1);
826 }
827 }
828
829 } // end namespace
830 } // end namespace internal
831
RunSpecifiedBenchmarks()832 void RunSpecifiedBenchmarks() {
833 RunSpecifiedBenchmarks(nullptr);
834 }
835
RunSpecifiedBenchmarks(BenchmarkReporter * reporter)836 void RunSpecifiedBenchmarks(BenchmarkReporter* reporter) {
837 if (FLAGS_benchmark_list_tests) {
838 internal::PrintBenchmarkList();
839 return;
840 }
841 std::string spec = FLAGS_benchmark_filter;
842 if (spec.empty() || spec == "all")
843 spec = "."; // Regexp that matches all benchmarks
844
845 std::unique_ptr<BenchmarkReporter> default_reporter;
846 if (!reporter) {
847 default_reporter = internal::GetDefaultReporter();
848 reporter = default_reporter.get();
849 }
850 internal::RunMatchingBenchmarks(spec, reporter);
851 reporter->Finalize();
852 }
853
854 namespace internal {
855
PrintUsageAndExit()856 void PrintUsageAndExit() {
857 fprintf(stdout,
858 "benchmark"
859 " [--benchmark_list_tests={true|false}]\n"
860 " [--benchmark_filter=<regex>]\n"
861 " [--benchmark_min_time=<min_time>]\n"
862 " [--benchmark_repetitions=<num_repetitions>]\n"
863 " [--benchmark_format=<tabular|json|csv>]\n"
864 " [--color_print={true|false}]\n"
865 " [--v=<verbosity>]\n");
866 exit(0);
867 }
868
ParseCommandLineFlags(int * argc,char ** argv)869 void ParseCommandLineFlags(int* argc, char** argv) {
870 using namespace benchmark;
871 for (int i = 1; i < *argc; ++i) {
872 if (
873 ParseBoolFlag(argv[i], "benchmark_list_tests",
874 &FLAGS_benchmark_list_tests) ||
875 ParseStringFlag(argv[i], "benchmark_filter",
876 &FLAGS_benchmark_filter) ||
877 ParseDoubleFlag(argv[i], "benchmark_min_time",
878 &FLAGS_benchmark_min_time) ||
879 ParseInt32Flag(argv[i], "benchmark_repetitions",
880 &FLAGS_benchmark_repetitions) ||
881 ParseStringFlag(argv[i], "benchmark_format",
882 &FLAGS_benchmark_format) ||
883 ParseBoolFlag(argv[i], "color_print",
884 &FLAGS_color_print) ||
885 ParseInt32Flag(argv[i], "v", &FLAGS_v)) {
886 for (int j = i; j != *argc; ++j) argv[j] = argv[j + 1];
887
888 --(*argc);
889 --i;
890 } else if (IsFlag(argv[i], "help")) {
891 PrintUsageAndExit();
892 }
893 }
894 if (FLAGS_benchmark_format != "tabular" &&
895 FLAGS_benchmark_format != "json" &&
896 FLAGS_benchmark_format != "csv") {
897 PrintUsageAndExit();
898 }
899 }
900
RegisterBenchmarkInternal(Benchmark * bench)901 Benchmark* RegisterBenchmarkInternal(Benchmark* bench) {
902 std::unique_ptr<Benchmark> bench_ptr(bench);
903 BenchmarkFamilies* families = BenchmarkFamilies::GetInstance();
904 families->AddBenchmark(std::move(bench_ptr));
905 return bench;
906 }
907
908 } // end namespace internal
909
Initialize(int * argc,char ** argv)910 void Initialize(int* argc, char** argv) {
911 internal::ParseCommandLineFlags(argc, argv);
912 internal::SetLogLevel(FLAGS_v);
913 // TODO remove this. It prints some output the first time it is called.
914 // We don't want to have this ouput printed during benchmarking.
915 MyCPUUsage();
916 // The first call to walltime::Now initialized it. Call it once to
917 // prevent the initialization from happening in a benchmark.
918 walltime::Now();
919 }
920
921 } // end namespace benchmark
922