Skip to content

Improve multi-threaded performance of TGeoNavigator - #24

Open
sawenzel wants to merge 3 commits into
alisw:alice/v6-36-10from
trwenz:alice/v6-36-10-geom-mt
Open

Improve multi-threaded performance of TGeoNavigator#24
sawenzel wants to merge 3 commits into
alisw:alice/v6-36-10from
trwenz:alice/v6-36-10-geom-mt

Conversation

@sawenzel

Copy link
Copy Markdown
Collaborator

Tristan Wenzel added 3 commits July 28, 2026 10:13
This commit improves multithreaded TGeo navigation. The changes come from profiling
a parallel geometry scan in ALICE.

AddNavigator() inserts into fNavigators under fgMutex, but GetCurrentNavigator(),
GetListOfNavigators() and SetCurrentNavigator() called find() on the same std::map with
no lock. A thread booking its navigator rebalances the tree underneath a concurrent
reader, returning a garbage TGeoNavigatorArray* or crashing outright.

The lookup is factored into FindNavigatorArray(), which takes fgMutex in MT mode and
skips it otherwise, matching what AddNavigator() already does. The TLS cache in
GetCurrentNavigator() is untouched, so steady-state navigation stays lock-free.

Assisted-by: Claude Code (review, hardening and benchmarking)
Supervised-by: Sandro Wenzel <sandro.wenzel@cern.ch>
This commit improves multithreaded TGeo navigation. The changes come from profiling
a parallel geometry scan in ALICE: filling the material budget LUT on 28 cores goes
from 12x to 23x speedup (139 s -> 72 s).

Two costs dominate. Every per-thread scratch lookup went through TGeoManager::ThreadId(),
a non-inlined cross-library __tls_get_addr call, paid on every boolean, section or
division query. And the per-object ThreadData_t blocks are small allocations made back to
back, so slots of different threads share a cache line and invalidate each other on every
write -- false sharing, worst across sockets.

Each object now gets a dense index and the per-thread state lives in one thread_local
vector indexed by it. GetThreadData() becomes a header-inline TLS read plus an indexed
load, and each thread owns its whole vector.

  TGeoBoolNode, TGeoVolumeAssembly, TGeoPatternFinder, TGeoPgon, TGeoXtru
  TGeoPgon/TGeoXtru: noexcept move ctor on ThreadData_t (owns heap buffers, and for Xtru
    a TGeoPolygon aliasing them) so a slot survives vector growth
  TGeoPatternFinder: matrix reused across generations -- it is owned by the geometry
    manager and never released, so a fresh one would leak per (thread, finder)

Provisioning goes away: ClearThreadData() bumps a generation counter and each thread
rebuilds its slot lazily, so CreateThreadData()/SetMaxThreads() are no longer needed to
make a given thread count work -- any thread count works out of the box. The counters are
atomic because ClearThreadData() is const and can run concurrently.

Assisted-by: Claude Code (review, hardening and benchmarking)
Supervised-by: Sandro Wenzel <sandro.wenzel@cern.ch>
This commit improves multithreaded TGeo navigation. The changes come from profiling
a parallel geometry scan in ALICE.

Eight threads navigating the same geometry must give exactly the single-threaded answer.
Covers TGeoXtru, TGeoPgon, TGeoVolumeAssembly, TGeoBoolNode (composite shape) and
TGeoPatternFinder (divided volume). The threads book their navigators lazily, so it also
exercises AddNavigator() against the navigator-map readers.

Assisted-by: Claude Code (review, hardening and benchmarking)
Supervised-by: Sandro Wenzel <sandro.wenzel@cern.ch>
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.

1 participant