CppBenchmark 1.0.5.0
C++ Benchmark Library
Loading...
Searching...
No Matches
benchmark_pc.cpp
Go to the documentation of this file.
1
10
11#include "benchmark/barrier.h"
13
14namespace CppBenchmark {
15
16int 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
21void 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.
static void UpdateBenchmarkThreads(std::vector< std::shared_ptr< PhaseCore > > &phases)
Update benchmark threads metrics for the given benchmark phases collection.
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 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
int attempts() const noexcept
Get count of independent benchmark attempts.
Definition settings.h:53
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
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
int64_t operations() const noexcept
Get count of operations.
Definition settings.h:59
const std::vector< std::tuple< int, int, int > > & params() const noexcept
Get collection of independent parameters in a benchmark plan.
Definition settings.h:65
const std::tuple< int64_t, int64_t, int > & latency() const noexcept
Get latency parameters.
Definition settings.h:67
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:399
Launcher handler definition.
C++ Benchmark project definitions.
Definition barrier.h:15