CppBenchmark  1.0.4.0
C++ Benchmark Library
benchmark_threads.cpp
Go to the documentation of this file.
1 
10 
11 #include "benchmark/barrier.h"
13 #include "benchmark/system.h"
14 
15 namespace CppBenchmark {
16 
17 int BenchmarkThreads::CountLaunches() const
18 {
19  return _settings.attempts() * (_settings.threads().empty() ? 1 : (int)_settings.threads().size()) * (_settings.params().empty() ? 1 : (int)_settings.params().size());
20 }
21 
22 void BenchmarkThreads::Launch(int& current, int total, LauncherHandler& handler)
23 {
24  // Make several attempts of execution...
25  for (int attempt = 1; attempt <= _settings.attempts(); ++attempt)
26  {
27  // Run benchmark at least for N threads where N is hardware core count
28  if (_settings._threads.empty())
29  _settings._threads.emplace_back(System::CpuPhysicalCores());
30 
31  // Run benchmark at least once
32  if (_settings._params.empty())
33  _settings._params.emplace_back(-1, -1, -1);
34 
35  // Run benchmark for every threads count
36  for (const auto& threads : _settings.threads())
37  {
38  // Run benchmark for every input parameter (single, pair, triple)
39  for (const auto& param : _settings.params())
40  {
41  // Prepare benchmark context
42  ContextThreads context(threads, std::get<0>(param), std::get<1>(param), std::get<2>(param));
43 
44  // Initialize the current benchmark
45  InitBenchmarkContext(context);
46 
47  // Prepare latency histogram parameters
48  std::tuple<int64_t, int64_t, int> latency_params(_settings.latency());
49  bool latency_auto = _settings.latency_auto();
50 
51  // Call launching notification...
52  handler.onLaunching(++current, total, *this, context, attempt);
53 
54  // Call initialize benchmark methods...
55  Initialize(context);
56 
57  bool infinite = _settings.infinite();
58  int64_t duration = _settings.duration();
59  int64_t operations = _settings.operations();
60 
61  // Prepare barrier for benchmark threads
62  Barrier barrier(threads);
63 
64  // Start benchmark root phase operation
65  context._current->StartCollectingMetrics();
66  context._metrics->AddOperations(1);
67 
68  // Start benchmark threads
69  for (int i = 0; i < threads; ++i)
70  {
71  _threads.emplace_back([this, &barrier, &context, latency_params, latency_auto, threads, infinite, operations, duration, i]()
72  {
73  // Clone thread context
74  ContextThreads thread_context(context);
75 
76  // Create and start thread safe phase
77  std::shared_ptr<Phase> thread_phase = context.StartPhaseThreadSafe("thread-" + std::to_string(i));
78  PhaseCore* thread_phase_core = dynamic_cast<PhaseCore*>(thread_phase.get());
79 
80  // Update thread context
81  thread_context._current = thread_phase_core;
82  thread_context._metrics = &thread_phase_core->current();
83  thread_context._metrics->AddOperations(-1);
84  thread_context._metrics->SetThreads(threads);
85 
86  // Initialize latency histogram of the current phase
87  thread_context._current->InitLatencyHistogram(latency_params);
88 
89  // Call initialize thread method...
90  InitializeThread(thread_context);
91 
92  bool thread_infinite = infinite;
93  int64_t thread_duration = duration;
94  int64_t thread_operations = operations;
95 
96  uint64_t timestamp = 0;
97 
98  // Wait for other threads at the barrier
99  barrier.Wait();
100 
101  // Calculate the approximate count of operations which can be performed for the given duration
102  if (thread_duration > 0)
103  {
104  uint64_t count = 0;
105  uint64_t timespan = 0;
106 
107  // Collect data for one second...
108  for (; timespan < 1000000000; ++count)
109  {
110  timestamp = System::Timestamp();
111 
112  // Run thread method...
113  RunThread(thread_context);
114 
115  timespan += System::Timestamp() - timestamp;
116  }
117 
118  // Approximate operations count
119  thread_operations = (1000000000ull * count * thread_duration) / timespan;
120  }
121 
122  thread_context._current->StartCollectingMetrics();
123  while (!thread_context.canceled() && (thread_infinite || (thread_operations > 0)))
124  {
125  // Add new metrics operation
126  thread_context._metrics->AddOperations(1);
127 
128  // Store the timestamp for the automatic latency update
129  if (latency_auto)
130  timestamp = System::Timestamp();
131 
132  // Run thread method...
133  RunThread(thread_context);
134 
135  // Update latency metrics
136  if (latency_auto)
137  thread_context._metrics->AddLatency(System::Timestamp() - timestamp);
138 
139  // Decrement operation counters
140  thread_operations -= 1;
141  }
142  thread_context._current->StopCollectingMetrics();
143 
144  // Call cleanup thread method...
145  CleanupThread(thread_context);
146 
147  // Update thread safe phase metrics
148  UpdateBenchmarkMetrics(*thread_context._current);
149  });
150  }
151 
152  // Wait for all threads
153  for (auto& thread : _threads)
154  thread.join();
155 
156  // Clear threads collection
157  _threads.clear();
158 
159  // Stop benchmark root phase operation
160  context._current->StopCollectingMetrics();
161 
162  // Call cleanup benchmark method...
163  Cleanup(context);
164 
165  // Call launched notification...
166  handler.onLaunched(current, total, *this, context, attempt);
167 
168  // Update benchmark root metrics for the current attempt
169  context._current->MergeMetrics();
170  context._current->ResetMetrics();
171  }
172  }
173  }
174 
175  // Update benchmark threads
177 
178  // Update benchmark names
180 
181  // Update benchmark operations
183 
184  // Update benchmark launched flag
185  _launched = true;
186 }
187 
188 } // namespace CppBenchmark
Barrier synchronization primitive definition.
Threads benchmark base definition.
bool _launched
Benchmark launched flag.
Settings _settings
Benchmark settings.
static void UpdateBenchmarkNames(std::vector< std::shared_ptr< PhaseCore >> &phases)
Update benchmark names for the given benchmark phases collection.
void InitBenchmarkContext(Context &context)
Initialize benchmark context.
static void UpdateBenchmarkThreads(std::vector< std::shared_ptr< PhaseCore >> &phases)
Update benchmark threads metrics for the given benchmark phases collection.
static void UpdateBenchmarkOperations(std::vector< std::shared_ptr< PhaseCore >> &phases)
Update benchmark operations for the given benchmark phases collection.
static void UpdateBenchmarkMetrics(std::vector< std::shared_ptr< PhaseCore >> &phases)
Update benchmark metrics for the given benchmark phases collection.
std::vector< std::shared_ptr< PhaseCore > > _phases
Benchmark phases.
virtual void RunThread(ContextThreads &context)=0
Thread run method.
virtual void Cleanup(ContextThreads &context)
Cleanup benchmark.
virtual void Initialize(ContextThreads &context)
Initialize benchmark.
virtual void InitializeThread(ContextThreads &context)
Initialize thread.
virtual void CleanupThread(ContextThreads &context)
Cleanup thread.
const std::vector< std::tuple< int, int, int > > & params() const noexcept
Get collection of independent parameters in a benchmark plan.
Definition: settings.h:65
int attempts() const noexcept
Get count of independent benchmark attempts.
Definition: settings.h:53
int64_t duration() const noexcept
Get benchmark duration in milliseconds.
Definition: settings.h:57
bool infinite() const noexcept
Is benchmark running with infinite count of operations (until cancel)?
Definition: settings.h:55
const std::tuple< int64_t, int64_t, int > & latency() const noexcept
Get latency parameters.
Definition: settings.h:67
int64_t operations() const noexcept
Get count of operations.
Definition: settings.h:59
bool latency_auto() const noexcept
Get automatic latency update flag.
Definition: settings.h:69
const std::vector< int > & threads() const noexcept
Get collection of independent threads counts in a benchmark plan.
Definition: settings.h:61
static uint64_t Timestamp()
Get the current timestamp in nanoseconds.
Definition: system.cpp:378
static int CpuPhysicalCores()
CPU physical cores count.
Definition: system.cpp:177
Launcher handler definition.
C++ Benchmark project definitions.
Definition: barrier.h:15
System management definition.