Skip to content

Respect min_time per thread in multi-threaded benchmarks (#2117)#2256

Open
devtejasx wants to merge 2 commits into
google:mainfrom
devtejasx:work-2117-min-time-threads
Open

Respect min_time per thread in multi-threaded benchmarks (#2117)#2256
devtejasx wants to merge 2 commits into
google:mainfrom
devtejasx:work-2117-min-time-threads

Conversation

@devtejasx

Copy link
Copy Markdown
Contributor

Fixes #2117.

Problem

real_time and manual_time (and whole-process CPU time) are accumulated across all threads in RunInThread (they are summed under the manager lock). #1836 removed the per-thread scaling of those values so that the reported Time is correct wall-clock time. However, the very same values also feed the min-time stopping decision via IterationResults::seconds.

The consequence: a benchmark running N threads stops as soon as the summed time across threads reaches min_time, i.e. after only min_time / N of wall-clock time per thread. This is exactly what #2117 reports — the iteration count doesn't grow with more threads, --benchmark_min_time isn't honored, and UseRealTime() no longer fixes it (it did before #1836).

BM_MultiThreaded/threads:1   ... 2585850
BM_MultiThreaded/threads:8   ... 2148808   # should be ~8x, wall time ~min_time/8

Fix

Add BenchmarkRunner::GetTimeForDecision(), which returns the per-thread duration by dividing the accumulated real/manual/process-CPU time by the thread count — but only for the stopping decision (PredictNumItersNeeded and ShouldReportIterationResults). The summed values stored in IterationResults::results are left untouched, so reported times and global counter rates are unaffected. The real_time_used >= 5 * min_time runaway guard is scaled the same way.

This restores the pre-#1836 decision behavior without reintroducing #1834.

Test

test/min_time_threads_gtest.cc runs the same benchmark at 1 and 4 threads with UseRealTime() and asserts that the per-thread wall-clock time does not collapse as the thread count grows. It fails before this change (4-thread ≈ ¼ of 1-thread) and passes after.

real_time and manual_time (and whole-process CPU time) are accumulated
across all threads in RunInThread. google#1836 removed the per-thread scaling
of these values so that the reported Time is correct wall-clock time, but
the same values also drive the min-time stopping decision. As a result a
benchmark running N threads stopped after only min_time/N of wall-clock
time per thread, and UseRealTime() no longer had any effect.

Introduce GetTimeForDecision(), which divides the accumulated real/manual/
process-CPU time by the thread count for the stopping decision only. The
values stored in IterationResults::results stay summed so reporting and
counter rates are unaffected. Also scale the real_time runaway guard in
ShouldReportIterationResults the same way.

Add min_time_threads_gtest, which checks that the per-thread wall-clock
time does not collapse as the thread count grows.
@LebedevRI

Copy link
Copy Markdown
Collaborator

Duplicate of #2118.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[BUG] Minimum benchmark time with multiple threads

2 participants