@@ -131,15 +131,18 @@ class ThreadManager {
131
131
}
132
132
133
133
public:
134
- GUARDED_BY (GetBenchmarkMutex()) double real_time_used = 0 ;
135
- GUARDED_BY (GetBenchmarkMutex()) double cpu_time_used = 0 ;
136
- GUARDED_BY (GetBenchmarkMutex()) double manual_time_used = 0 ;
137
- GUARDED_BY (GetBenchmarkMutex()) int64_t bytes_processed = 0 ;
138
- GUARDED_BY (GetBenchmarkMutex()) int64_t items_processed = 0 ;
139
- GUARDED_BY (GetBenchmarkMutex()) int complexity_n = 0 ;
140
- GUARDED_BY (GetBenchmarkMutex()) std::string report_label_;
141
- GUARDED_BY (GetBenchmarkMutex()) std::string error_message_;
142
- GUARDED_BY (GetBenchmarkMutex()) bool has_error_ = false ;
134
+ struct Result {
135
+ double real_time_used = 0 ;
136
+ double cpu_time_used = 0 ;
137
+ double manual_time_used = 0 ;
138
+ int64_t bytes_processed = 0 ;
139
+ int64_t items_processed = 0 ;
140
+ int complexity_n = 0 ;
141
+ std::string report_label_;
142
+ std::string error_message_;
143
+ bool has_error_ = false ;
144
+ };
145
+ GUARDED_BY (GetBenchmarkMutex()) Result results;
143
146
144
147
private:
145
148
mutable Mutex benchmark_mutex_;
@@ -211,6 +214,47 @@ class ThreadTimer {
211
214
212
215
namespace {
213
216
217
+ BenchmarkReporter::Run
218
+ CreateRunReport (const benchmark::internal::Benchmark::Instance& b,
219
+ const internal::ThreadManager::Result& results,
220
+ size_t iters, double seconds)
221
+ {
222
+ // Create report about this benchmark run.
223
+ BenchmarkReporter::Run report;
224
+
225
+ report.benchmark_name = b.name ;
226
+ report.error_occurred = results.has_error_ ;
227
+ report.error_message = results.error_message_ ;
228
+ report.report_label = results.report_label_ ;
229
+ // Report the total iterations across all threads.
230
+ report.iterations = static_cast <int64_t >(iters) * b.threads ;
231
+ report.time_unit = b.time_unit ;
232
+
233
+ if (!report.error_occurred ) {
234
+ double bytes_per_second = 0 ;
235
+ if (results.bytes_processed > 0 && seconds > 0.0 ) {
236
+ bytes_per_second = (results.bytes_processed / seconds);
237
+ }
238
+ double items_per_second = 0 ;
239
+ if (results.items_processed > 0 && seconds > 0.0 ) {
240
+ items_per_second = (results.items_processed / seconds);
241
+ }
242
+
243
+ if (b.use_manual_time ) {
244
+ report.real_accumulated_time = results.manual_time_used ;
245
+ } else {
246
+ report.real_accumulated_time = results.real_time_used ;
247
+ }
248
+ report.cpu_accumulated_time = results.cpu_time_used ;
249
+ report.bytes_per_second = bytes_per_second;
250
+ report.items_per_second = items_per_second;
251
+ report.complexity_n = results.complexity_n ;
252
+ report.complexity = b.complexity ;
253
+ report.complexity_lambda = b.complexity_lambda ;
254
+ }
255
+ return report;
256
+ }
257
+
214
258
// Execute one thread of benchmark b for the specified number of iterations.
215
259
// Adds the stats collected for the thread into *total.
216
260
void RunInThread (const benchmark::internal::Benchmark::Instance* b,
@@ -223,12 +267,13 @@ void RunInThread(const benchmark::internal::Benchmark::Instance* b,
223
267
" Benchmark returned before State::KeepRunning() returned false!" ;
224
268
{
225
269
MutexLock l (manager->GetBenchmarkMutex ());
226
- manager->cpu_time_used += timer.cpu_time_used ();
227
- manager->real_time_used += timer.real_time_used ();
228
- manager->manual_time_used += timer.manual_time_used ();
229
- manager->bytes_processed += st.bytes_processed ();
230
- manager->items_processed += st.items_processed ();
231
- manager->complexity_n += st.complexity_length_n ();
270
+ internal::ThreadManager::Result& results = manager->results ;
271
+ results.cpu_time_used += timer.cpu_time_used ();
272
+ results.real_time_used += timer.real_time_used ();
273
+ results.manual_time_used += timer.manual_time_used ();
274
+ results.bytes_processed += st.bytes_processed ();
275
+ results.items_processed += st.items_processed ();
276
+ results.complexity_n += st.complexity_length_n ();
232
277
}
233
278
manager->NotifyThreadComplete ();
234
279
}
@@ -239,96 +284,58 @@ std::vector<BenchmarkReporter::Run> RunBenchmark(
239
284
std::vector<BenchmarkReporter::Run> reports; // return value
240
285
241
286
size_t iters = 1 ;
242
- const int num_threads = b.multithreaded ? b.threads : 1 ;
243
- std::vector<std::thread> pool;
244
- if (num_threads > 1 ) pool.resize (num_threads -1 );
245
-
287
+ std::unique_ptr<internal::ThreadManager> manager;
288
+ std::vector<std::thread> pool (b.threads - 1 );
246
289
const int repeats = b.repetitions != 0 ? b.repetitions
247
290
: FLAGS_benchmark_repetitions;
248
291
const bool report_aggregates_only = repeats != 1 &&
249
292
(b.report_mode == internal::RM_Unspecified
250
293
? FLAGS_benchmark_report_aggregates_only
251
294
: b.report_mode == internal::RM_ReportAggregatesOnly);
252
295
for (int i = 0 ; i < repeats; i++) {
253
- std::string mem;
254
296
for (;;) {
255
297
// Try benchmark
256
298
VLOG (2 ) << " Running " << b.name << " for " << iters << " \n " ;
257
299
258
- internal::ThreadManager manager (num_threads);
259
- if (b.multithreaded ) {
260
- // If this is out first iteration of the while(true) loop then the
261
- // threads haven't been started and can't be joined. Otherwise we need
262
- // to join the thread before replacing them.
263
- for (std::thread& thread : pool) {
264
- if (thread.joinable ())
265
- thread.join ();
266
- }
267
- for (std::size_t ti = 0 ; ti < pool.size (); ++ti) {
268
- pool[ti] = std::thread (&RunInThread, &b, iters,
269
- static_cast <int >(ti + 1 ), &manager);
270
- }
300
+ manager.reset (new internal::ThreadManager (b.threads ));
301
+ for (std::size_t ti = 0 ; ti < pool.size (); ++ti) {
302
+ pool[ti] = std::thread (&RunInThread, &b, iters,
303
+ static_cast <int >(ti + 1 ), manager.get ());
271
304
}
272
- RunInThread (&b, iters, 0 , &manager);
273
- manager.WaitForAllThreads ();
274
- MutexLock l (manager.GetBenchmarkMutex ());
275
-
276
- const double cpu_accumulated_time = manager.cpu_time_used ;
277
- const double real_accumulated_time = manager.real_time_used / num_threads;
278
- const double manual_accumulated_time = manager.manual_time_used / num_threads;
305
+ RunInThread (&b, iters, 0 , manager.get ());
306
+ manager->WaitForAllThreads ();
307
+ for (std::thread& thread : pool)
308
+ thread.join ();
309
+ internal::ThreadManager::Result results;
310
+ {
311
+ MutexLock l (manager->GetBenchmarkMutex ());
312
+ results = manager->results ;
313
+ }
314
+ manager.reset ();
315
+ // Adjust real/manual time stats since they were reported per thread.
316
+ results.real_time_used /= b.threads ;
317
+ results.manual_time_used /= b.threads ;
279
318
280
- VLOG (2 ) << " Ran in " << cpu_accumulated_time << " /"
281
- << real_accumulated_time << " \n " ;
319
+ VLOG (2 ) << " Ran in " << results. cpu_time_used << " /"
320
+ << results. real_time_used << " \n " ;
282
321
283
322
// Base decisions off of real time if requested by this benchmark.
284
- double seconds = cpu_accumulated_time ;
323
+ double seconds = results. cpu_time_used ;
285
324
if (b.use_manual_time ) {
286
- seconds = manual_accumulated_time ;
325
+ seconds = results. manual_time_used ;
287
326
} else if (b.use_real_time ) {
288
- seconds = real_accumulated_time ;
327
+ seconds = results. real_time_used ;
289
328
}
290
329
291
330
const double min_time = !IsZero (b.min_time ) ? b.min_time
292
331
: FLAGS_benchmark_min_time;
293
332
// If this was the first run, was elapsed time or cpu time large enough?
294
333
// If this is not the first run, go with the current value of iter.
295
- if ((i > 0 ) || manager.has_error_ || (iters >= kMaxIterations ) ||
296
- (seconds >= min_time) || (real_accumulated_time >= 5 * min_time)) {
297
- // Create report about this benchmark run.
298
- BenchmarkReporter::Run report;
299
- report.benchmark_name = b.name ;
300
- report.error_occurred = manager.has_error_ ;
301
- report.error_message = manager.error_message_ ;
302
- report.report_label = manager.report_label_ ;
303
- // Report the total iterations across all threads.
304
- report.iterations = static_cast <int64_t >(iters) * b.threads ;
305
- report.time_unit = b.time_unit ;
306
-
307
- if (!report.error_occurred ) {
308
- double bytes_per_second = 0 ;
309
- if (manager.bytes_processed > 0 && seconds > 0.0 ) {
310
- bytes_per_second = (manager.bytes_processed / seconds);
311
- }
312
- double items_per_second = 0 ;
313
- if (manager.items_processed > 0 && seconds > 0.0 ) {
314
- items_per_second = (manager.items_processed / seconds);
315
- }
316
-
317
- if (b.use_manual_time ) {
318
- report.real_accumulated_time = manual_accumulated_time;
319
- } else {
320
- report.real_accumulated_time = real_accumulated_time;
321
- }
322
- report.cpu_accumulated_time = cpu_accumulated_time;
323
- report.bytes_per_second = bytes_per_second;
324
- report.items_per_second = items_per_second;
325
- report.complexity_n = manager.complexity_n ;
326
- report.complexity = b.complexity ;
327
- report.complexity_lambda = b.complexity_lambda ;
328
- if (report.complexity != oNone)
329
- complexity_reports->push_back (report);
330
- }
331
-
334
+ if ((i > 0 ) || results.has_error_ || (iters >= kMaxIterations ) ||
335
+ (seconds >= min_time) || (results.real_time_used >= 5 * min_time)) {
336
+ BenchmarkReporter::Run report = CreateRunReport (b, results, iters, seconds);
337
+ if (!report.error_occurred && b.complexity != oNone)
338
+ complexity_reports->push_back (report);
332
339
reports.push_back (report);
333
340
break ;
334
341
}
@@ -352,10 +359,6 @@ std::vector<BenchmarkReporter::Run> RunBenchmark(
352
359
iters = static_cast <int >(next_iters + 0.5 );
353
360
}
354
361
}
355
- if (b.multithreaded ) {
356
- for (std::thread& thread : pool)
357
- thread.join ();
358
- }
359
362
// Calculate additional statistics
360
363
auto stat_reports = ComputeStats (reports);
361
364
if ((b.complexity != oNone) && b.last_benchmark_instance ) {
@@ -409,9 +412,9 @@ void State::SkipWithError(const char* msg) {
409
412
error_occurred_ = true ;
410
413
{
411
414
MutexLock l (manager_->GetBenchmarkMutex ());
412
- if (manager_->has_error_ == false ) {
413
- manager_->error_message_ = msg;
414
- manager_->has_error_ = true ;
415
+ if (manager_->results . has_error_ == false ) {
416
+ manager_->results . error_message_ = msg;
417
+ manager_->results . has_error_ = true ;
415
418
}
416
419
}
417
420
total_iterations_ = max_iterations;
@@ -425,7 +428,7 @@ void State::SetIterationTime(double seconds)
425
428
426
429
void State::SetLabel (const char * label) {
427
430
MutexLock l (manager_->GetBenchmarkMutex ());
428
- manager_->report_label_ = label;
431
+ manager_->results . report_label_ = label;
429
432
}
430
433
431
434
void State::StartKeepRunning () {
0 commit comments