Skip to content

Add a multithreaded TPC digitizer device - #16090

Open
sawenzel wants to merge 11 commits into
AliceO2Group:devfrom
sawenzel:tpc-digi-mt-v2
Open

sawenzel wants to merge 11 commits into
AliceO2Group:devfrom
sawenzel:tpc-digi-mt-v2

Conversation

@sawenzel

@sawenzel sawenzel commented Nov 9, 2026

Copy link
Copy Markdown
Collaborator

This PR adds an optional TPC digitizer device that digitizes all sectors in one process with several threads, instead of one process per lane.

With lanes, every process loads and recalculates its own copy of the space-charge distortion maps, which in PbPb costs about 1 GB of memory and several minutes of CPU per lane. In the new device the maps are prepared once and shared by all threads, while each thread owns a digitizer with its own random rings, hit chains and output file. It is enabled with --tpc-digi-threads N together with --tpc-chunked-writer; the chunked merger and everything downstream are unchanged.

The effect on one anchored PbPb timeframe (run 572106, distortion type 2) is substantial:

8 lanes 8 threads
peak PSS 15.05 GiB 7.95 GiB
wall time 216 s 69 s

The lanes run with --n-threads-distortions 1, as in O2DPG, and the threaded device with 8.

Note that nothing changes by default. The digits of the threaded device are identical to those of the lane spec with --tpc-sector-seeding for 1, 4 and 8 lanes and threads, with and without distortions, also when run through the O2DPG workflow up to the TPC clusterization.

This builds on #16082, #16083 and #16085. Only the last three commits are new: moving the per-sector loop into a shared function, preparing the digitizer for concurrent use, and the device itself.

Overall, this halves the memory of the TPC digitization and makes it about three times faster.

https://its.cern.ch/jira/browse/O2-7309

Assisted by Claude Code.

@sawenzel

sawenzel commented Nov 9, 2026

Copy link
Copy Markdown
Collaborator Author

Added commits after internal review.

sawenzel and others added 10 commits November 9, 2026 18:21
This replaces two shared static workspaces of the TPC digitizer by members, in preparation for a multithreaded digitizer.

- The shaped-signal buffer of Digitizer::process and the label sorting buffer of DigitGlobalPad::fillOutputContainer are now members.
- The SAMPAProcessing used for the output is passed down from DigitContainer, which uses the singleton unless one is set.

https://its.cern.ch/jira/browse/O2-7309

Co-Authored-By: Claude Opus 5.5 <[email protected]>
This adds an option that makes the TPC digits independent of the lane assignment, as a preparation for MT digitization.

- The random rings of ElectronTransport, GEMAmplification and SAMPAProcessing kept their positions from one sector to the next, so the digits depended on the number of TPC lanes.
- With --tpc-sector-seeding, each Digitizer owns these three objects, fills their rings once from DigiParams.seed, and moves the rings to positions derived from the seed, the sector and the timeframe.
- RandomRing can now be filled from a given generator and moved to a random position.
- Without the option, the output is unchanged.

https://its.cern.ch/jira/browse/O2-7309

Co-Authored-By: Claude Opus 5.5 <[email protected]>
This moves the per-sector loop of the TPC digitizer spec into a free function, as a preparation for MT digitization.

- digitizeSector runs the collision loop and the flushes of one sector and returns the digit groups.
- The output of each flush is handed to a callback, so the function makes no DPL calls.
- The lane spec now calls it; the chunked writer and the DPL outputs stay in the spec.
- The output is unchanged.

https://its.cern.ch/jira/browse/O2-7309

Co-Authored-By: Claude Opus 5.5 <[email protected]>
This fixes a double ownership of the TPC space-charge maps and prepares sharing them between digitizers.

- setUseSCDistortions(SC*) and setSCDistortionsDerivative(SC*) took ownership of objects that the DPL CCDB cache owns and deletes itself when a newer object replaces them.
- The Digitizer now owns only the maps it creates itself.
- The map members are transient for ROOT I/O.

https://its.cern.ch/jira/browse/O2-7309

Co-Authored-By: Claude Opus 5.5 <[email protected]>
This makes several TPC digitizers usable side by side in one process, as a preparation for MT digitization.

- Each DigitContainer keeps its own copy of the dead channel map, because CDBInterface::getDeadChannelMap() rebuilds the shared map on every call.
- The one-time settings report moves from the flush path into updateCalibrations().
- Digitizer::setSCDistortionsFrom() shares the distortion maps and their scaling with another digitizer.
- digitizeSector() takes an optional mutex for the calls that read calibrations through the CDBInterface.
- The output is unchanged.

https://its.cern.ch/jira/browse/O2-7309

Co-Authored-By: Claude Opus 5.5 <[email protected]>
This adds an optional single TPC digitizer device that digitizes the sectors with several threads instead of lanes.

- --tpc-digi-threads N replaces the TPC lanes by one device; it requires --tpc-chunked-writer.
- Each thread owns a digitizer with sector seeding, its own hit chains and its own tpc_driftime_digits_lane file, so the existing merger is unchanged.
- The CCDB objects are handled once on the device thread, and the distortion maps are recalculated once and shared.
- The digits are identical to the lane spec with --tpc-sector-seeding.

https://its.cern.ch/jira/browse/O2-7309

Co-Authored-By: Claude Opus 5.5 <[email protected]>
This addresses a review comment on the random ring repositioning.

- setRandomPosition() can place the ring at any index.
- getNextValueVc() now wraps to the start when a vector would run past the end.

https://its.cern.ch/jira/browse/O2-7309

Co-Authored-By: Claude Opus 5.5 <[email protected]>
This addresses a review comment on the repeated fillOutputContainer calls.

- The eight cases now pass the mode as a type to one lambda.

https://its.cern.ch/jira/browse/O2-7309

Co-Authored-By: Claude Opus 5.5 <[email protected]>
This addresses the review of the multithreaded TPC digitizer device.

- The workers copy the random rings of the first worker instead of filling their own.
- The workers no longer flush the process-wide debug streamer; the device flushes it after the join.
- The Digitizer serialises its calibration reads itself, so digitizeSector needs no mutex.
- The CCDB handling, the calibration files and the common options of both devices are in TPCDigitizerConditions.
- The device stops on a second timeframe, which the chunked digit files cannot hold.
- Shorter comments in TPCSectorDigitization.h.

https://its.cern.ch/jira/browse/O2-7309

Co-Authored-By: Claude Opus 5.5 <[email protected]>
This addresses the second review of the multithreaded TPC digitizer device.

- Old lane files are found with o2::utils::listFiles, as in the chunked merger.
- Unused includes and the SpaceCharge alias are removed from the device.
- setSectorSeedingFrom fills the rings of the source digitizer, so initSectorSeeding is private.
- The seeding documentation states that the sectors share the ring contents.

https://its.cern.ch/jira/browse/O2-7309

Co-Authored-By: Claude Opus 5.5 <[email protected]>

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

Development

Successfully merging this pull request may close these issues.

1 participant