CppBenchmark  1.0.4.0
C++ Benchmark Library
benchmark_pc.cpp
Go to the documentation of this file.
1 
10 
11 #include "benchmark/barrier.h"
13 
14 namespace CppBenchmark {
15 
16 int BenchmarkPC::CountLaunches() const
17 {
18  return _settings.attempts() * (_settings.pc().empty() ? 1 : (int)_settings.pc().size()) * (_settings.params().empty() ? 1 : (int)_settings.params().size());
19 }
20 
21 void BenchmarkPC::Launch(int& current, int total, LauncherHandler& handler)
22 {
23  // Make several attempts of execution...
24  for (int attempt = 1; attempt <= _settings.attempts(); ++attempt)
25  {
26  // Run benchmark at least for 1 producer and 1 consumer
27  if (_settings._pc.empty())
28  _settings._pc.emplace_back(1, 1);
29 
30  // Run benchmark at least once
31  if (_settings._params.empty())
32  _settings._params.emplace_back(-1, -1, -1);
33 
34  // Run benchmark for every producers/consumers pair
35  for (const auto& pc : _settings.pc())
36  {
37  int producers = std::get<0>(pc);
38  int consumers = std::get<1>(pc);
39 
40  // Run benchmark for every input parameter (single, pair, triple)
41  for (const auto& param : _settings.params())
42  {
43  // Prepare benchmark context
44  ContextPC context(producers, consumers, std::get<0>(param), std::get<1>(param), std::get<2>(param));
45 
46  // Initialize the current benchmark
47  InitBenchmarkContext(context);
48 
49  // Prepare latency histogram parameters
50  std::tuple<int64_t, int64_t, int> latency_params(_settings.latency());
51  bool latency_auto = _settings.latency_auto();
52 
53  // Call launching notification...
54  handler.onLaunching(++current, total, *this, context, attempt);
55 
56  // Call initialize benchmark methods...
57  Initialize(context);
58 
59  bool infinite = _settings.infinite();
60  int64_t duration = _settings.duration();
61  int64_t operations = _settings.operations();
62 
63  // Prepare barrier for producers & consumers threads
64  Barrier barrier(producers + consumers);
65 
66  // Start benchmark root phase operation
67  context._current->StartCollectingMetrics();
68  context._metrics->AddOperations(1);
69 
70  // Start benchmark producers
71  for (int i = 0; i < producers; ++i)
72  {
73  _threads.emplace_back([this, &barrier, &context, latency_params, latency_auto, producers, infinite, operations, duration, i]()
74  {
75  // Clone producer context
76  ContextPC producer_context(context);
77 
78  // Create and start thread safe phase
79  std::shared_ptr<Phase> producer_phase = context.StartPhaseThreadSafe("producer-" + std::to_string(i));
80  PhaseCore* producer_phase_core = dynamic_cast<PhaseCore*>(producer_phase.get());
81 
82  // Update producer context
83  producer_context._current = producer_phase_core;
84  producer_context._metrics = &producer_phase_core->current();
85  producer_context._metrics->AddOperations(-1);
86  producer_context._metrics->SetThreads(producers);
87 
88  // Initialize latency histogram of the current phase
89  producer_context._current->InitLatencyHistogram(latency_params);
90 
91  // Call initialize producer method...
92  InitializeProducer(producer_context);
93 
94  bool producer_infinite = infinite;
95  int64_t producer_duration = duration;
96  int64_t producer_operations = operations;
97 
98  uint64_t timestamp = 0;
99 
100  // Wait for other threads at the barrier
101  barrier.Wait();
102 
103  // Calculate the approximate count of operations which can be performed for the given duration
104  if (producer_duration > 0)
105  {
106  uint64_t count = 0;
107  uint64_t timespan = 0;
108 
109  // Collect data for one second...
110  for (; timespan < 1000000000; ++count)
111  {
112  timestamp = System::Timestamp();
113 
114  // Run producer method...
115  RunProducer(producer_context);
116 
117  timespan += System::Timestamp() - timestamp;
118  }
119 
120  // Approximate operations count
121  producer_operations = (1000000000ull * count * producer_duration) / timespan;
122  }
123 
124  producer_context._current->StartCollectingMetrics();
125  while (!producer_context.produce_stopped() && !producer_context.canceled() && (producer_infinite || (producer_operations > 0)))
126  {
127  // Add new metrics operation
128  producer_context._metrics->AddOperations(1);
129 
130  // Store the timestamp for the automatic latency update
131  if (latency_auto)
132  timestamp = System::Timestamp();
133 
134  // Run producer method...
135  RunProducer(producer_context);
136 
137  // Update latency metrics
138  if (latency_auto)
139  producer_context._metrics->AddLatency(System::Timestamp() - timestamp);
140 
141  // Decrement operation counters
142  producer_operations -= 1;
143  }
144  producer_context._current->StopCollectingMetrics();
145 
146  // Call cleanup producer method...
147  CleanupProducer(producer_context);
148 
149  // Update thread safe phase metrics
150  UpdateBenchmarkMetrics(*producer_context._current);
151  });
152  }
153 
154  // Start benchmark consumers
155  for (int i = 0; i < consumers; ++i)
156  {
157  _threads.emplace_back([this, &barrier, &context, latency_params, latency_auto, consumers, i]()
158  {
159  // Clone consumer context
160  ContextPC consumer_context(context);
161 
162  // Create and start thread safe phase
163  std::shared_ptr<Phase> consumer_phase = context.StartPhaseThreadSafe("consumer-" + std::to_string(i));
164  PhaseCore* consumer_phase_core = dynamic_cast<PhaseCore*>(consumer_phase.get());
165 
166  // Update consumer context
167  consumer_context._current = consumer_phase_core;
168  consumer_context._metrics = &consumer_phase_core->current();
169  consumer_context._metrics->AddOperations(-1);
170  consumer_context._metrics->SetThreads(consumers);
171 
172  // Initialize latency histogram of the current phase
173  consumer_context._current->InitLatencyHistogram(latency_params);
174 
175  // Call initialize consumer method...
176  InitializeConsumer(consumer_context);
177 
178  // Wait for other threads at the barrier
179  barrier.Wait();
180 
181  consumer_context._current->StartCollectingMetrics();
182  while (!consumer_context.consume_stopped() && !consumer_context.canceled())
183  {
184  // Add new metrics operation
185  consumer_context._metrics->AddOperations(1);
186 
187  // Store timestamp for automatic latency update
188  uint64_t timestamp = 0;
189  if (latency_auto)
190  timestamp = System::Timestamp();
191 
192  // Run consumer method...
193  RunConsumer(consumer_context);
194 
195  // Automatic latency update
196  if (latency_auto)
197  consumer_context._metrics->AddLatency(System::Timestamp() - timestamp);
198  }
199  consumer_context._current->StopCollectingMetrics();
200 
201  // Call cleanup consumer method...
202  CleanupConsumer(consumer_context);
203 
204  // Update thread safe phase metrics
205  UpdateBenchmarkMetrics(*consumer_context._current);
206  });
207  }
208 
209  // Wait for all threads
210  for (auto& thread : _threads)
211  thread.join();
212 
213  // Clear threads collection
214  _threads.clear();
215 
216  // Stop benchmark root phase operation
217  context._current->StopCollectingMetrics();
218 
219  // Call cleanup benchmark methods...
220  Cleanup(context);
221 
222  // Call launched notification...
223  handler.onLaunched(current, total, *this, context, attempt);
224 
225  // Update benchmark root metrics for the current attempt
226  context._current->MergeMetrics();
227  context._current->ResetMetrics();
228  }
229  }
230  }
231 
232  // Update benchmark threads
234 
235  // Update benchmark names
237 
238  // Update benchmark launched flag
239  _launched = true;
240 }
241 
242 } // namespace CppBenchmark
Barrier synchronization primitive definition.
Producers/Consumers 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 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 RunConsumer(ContextPC &context)=0
Consumer run method.
virtual void RunProducer(ContextPC &context)=0
Producer run method.
virtual void Initialize(ContextPC &context)
Initialize benchmark.
Definition: fixture_pc.h:38
virtual void Cleanup(ContextPC &context)
Cleanup benchmark.
Definition: fixture_pc.h:45
virtual void CleanupProducer(ContextPC &context)
Cleanup producer.
Definition: fixture_pc.h:67
virtual void InitializeProducer(ContextPC &context)
Initialize producer.
Definition: fixture_pc.h:53
virtual void InitializeConsumer(ContextPC &context)
Initialize consumer.
Definition: fixture_pc.h:60
virtual void CleanupConsumer(ContextPC &context)
Cleanup consumer.
Definition: fixture_pc.h:74
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
const std::vector< std::tuple< int, int > > & pc() const noexcept
Get collection of independent producers/consumers counts in a benchmark plan.
Definition: settings.h:63
bool latency_auto() const noexcept
Get automatic latency update flag.
Definition: settings.h:69
static uint64_t Timestamp()
Get the current timestamp in nanoseconds.
Definition: system.cpp:378
Launcher handler definition.
C++ Benchmark project definitions.
Definition: barrier.h:15