Skip to content

fix: report threads as 1 in State during single-threaded manager passes (fixes #1849) - #2324

Open
ReturnKartikey wants to merge 1 commit into
google:mainfrom
ReturnKartikey:fix-1849-multithread-memory-manager
Open

ReturnKartikey wants to merge 1 commit into
google:mainfrom
ReturnKartikey:fix-1849-multithread-memory-manager

Conversation

@ReturnKartikey

@ReturnKartikey ReturnKartikey commented Oct 7, 2026 •

Copy link
Copy Markdown
Contributor

Fixes #1849

Summary of Changes

In BenchmarkRunner::RunMemoryManager and BenchmarkRunner::RunProfilerManager, execution deliberately runs single-threaded with ThreadManager(1) and thread 0.

However, �enchmark::State was previously constructed using �.threads() (the benchmark's configured thread count), causing state.threads() to report multiple threads despite only 1 thread being executed.

For multithreaded benchmarks or fixtures that synchronize across all threads (e.g. waiting for state.threads() workers via barriers, latches, or custom setup/teardown coordination), thread 0 hung indefinitely waiting for worker threads that were never spawned.

This patch:

  1. Adds an optional hread_count override to BenchmarkInstance::Run, BenchmarkInstance::Setup, and BenchmarkInstance::Teardown.
  2. Passes hread_count = 1 in RunMemoryManager and RunProfilerManager so state.threads() accurately reports 1 during single-threaded execution passes.
  3. Adds a regression test in est/memory_manager_ordering_gtest.cc that synchronizes across state.threads() in SetUp/TearDown, verifying that:
    • During the memory manager pass, state.threads() is 1 and succeeds without hanging.
    • During normal iterations, state.threads() is 4 and executes across all 4 worker threads.

Verification

  • Added automated regression case in est/memory_manager_ordering_gtest.cc.
  • Verified 100% pass on all 87 test targets via ctest.
  • Formatted with clang-format.

@dmah42

dmah42 commented Oct 9, 2026

Copy link
Copy Markdown
Member

this was and remains a deliberate design choice. for profile and memory profiling we want to run a single thread only even if the benchmark is multithreaded. if you want to question the design choice let's have that discussion first.

@ReturnKartikey

Copy link
Copy Markdown
Contributor Author

@dmah42 The problem is that during this pass, state.threads() still returns the full thread count (e.g. 8) instead of 1. Any fixture or benchmark using a barrier to sync state.threads() hangs forever waiting for threads that never get spawned.

If we keep the single-thread design, would you prefer that state.threads() just reports 1 during profiler passes so fixtures don't deadlock?

@dmah42

dmah42 commented Oct 9, 2026

Copy link
Copy Markdown
Member

oh yeah, that sounds like a clear bug in the state that we should fix.

…es (fixes google#1849)

In BenchmarkRunner::RunMemoryManager and BenchmarkRunner::RunProfilerManager, execution deliberately runs single-threaded with ThreadManager(1) and thread 0. However, State was constructed with the benchmark's configured thread count (b.threads()), causing state.threads() to report multiple threads despite only a single thread running.

For multithreaded benchmarks and fixtures that synchronize or coordinate across state.threads() (such as barriers, latches, or SetUp/TearDown hooks), thread 0 hung waiting indefinitely for other threads that were never spawned.

This patch updates BenchmarkInstance::Run, Setup, and Teardown to accept an optional thread_count override and passes thread_count = 1 during RunMemoryManager and RunProfilerManager passes so state.threads() correctly reflects the active single-threaded execution. Also adds a regression test in memory_manager_ordering_gtest.
@ReturnKartikey
ReturnKartikey force-pushed the fix-1849-multithread-memory-manager branch from 3921bc2 to 2b36d89 Compare October 11, 2026 11:45
@ReturnKartikey ReturnKartikey changed the title fix: execute all benchmark threads in RunMemoryManager and RunProfilerManager (fixes #1849) fix: report threads as 1 in State during single-threaded manager passes (fixes #1849) Oct 11, 2026
@ReturnKartikey

Copy link
Copy Markdown
Contributor Author

Updated the PR as discussed!

RunMemoryManager and RunProfilerManager remain single-threaded (ThreadManager(1)), and we now pass hread_count = 1 into State and Setup/Teardown during those passes so state.threads() accurately reports 1. Multithreaded fixtures using state.threads() for barrier synchronization now execute and complete cleanly without deadlocks.

This branch has not been deployed

No deployments
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] CPU hang on multithreaded benchmarks overriding the memory manager

2 participants