Skip to content

perf(fatras): avoid materialising all bin edges per hit in Segmentizer - #6077

Open
pbutti wants to merge 1 commit into
acts-project:mainfrom
pbutti:feat-digi-speed
Open

pbutti wants to merge 1 commit into
acts-project:mainfrom
pbutti:feat-digi-speed

Conversation

@pbutti

@pbutti pbutti commented Sep 13, 2026

Copy link
Copy Markdown
Contributor

Segmentizer::segments() read the two or three cell boundaries a hit crosses via IAxis::getBinEdges(), which for an equidistant axis constructs and returns the complete edge vector on every call. The four call sites (plane/cylinder x and y, disc r and phi) therefore allocated nBins+1 doubles per axis per hit.

With a 1150 x 1450 segmentation (20 um pitch) that is ~2600 doubles allocated and discarded per hit. Profiling an ALICE 3 pp =30 digitisation showed Axis<Equidistant, Bound>::getBinEdges() at 22% of the algorithm, with a further ~10% of allocator traffic under the same call chain.

Index the axis with getBinLowerBound() instead, which is O(1) and allocates nothing. getBinEdges()[i] == getBinLowerBound(i + 1), and the bin indices here are zero-based while getBin() is one-based, so the required edge for zero-based bin index ib is getBinLowerBound(ib + 1); ib never exceeds nBins - 1, so the lookup is always in range. Behaviour is unchanged.

ActsUnitTestFatrasSegmentizer (27 cases), ActsUnitTestFatrasChannelizer and ActsUnitTestFatrasChannelMerger all pass.

Segmentizer::segments() read the two or three cell boundaries a hit crosses
via IAxis::getBinEdges(), which for an equidistant axis constructs and returns
the complete edge vector on every call. The four call sites (plane/cylinder x
and y, disc r and phi) therefore allocated nBins+1 doubles per axis per hit.

With a 1150 x 1450 segmentation (20 um pitch) that is ~2600 doubles allocated
and discarded per hit. Profiling an ALICE 3 pp <mu>=30 digitisation showed
Axis<Equidistant, Bound>::getBinEdges() at 22% of the algorithm, with a further
~10% of allocator traffic under the same call chain.

Index the axis with getBinLowerBound() instead, which is O(1) and allocates
nothing. getBinEdges()[i] == getBinLowerBound(i + 1), and the bin indices here
are zero-based while getBin() is one-based, so the required edge for zero-based
bin index ib is getBinLowerBound(ib + 1); ib never exceeds nBins - 1, so the
lookup is always in range. Behaviour is unchanged.

ActsUnitTestFatrasSegmentizer (27 cases), ActsUnitTestFatrasChannelizer and
ActsUnitTestFatrasChannelMerger all pass.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@github-actions github-actions Bot added the Component - Fatras Affects the Fatras module label Sep 13, 2026
@github-actions github-actions Bot added this to the next milestone Sep 13, 2026
@github-actions

Copy link
Copy Markdown
Contributor

Public API surface diff

No change to the public API surface. ✅

@sonarqubecloud

Copy link
Copy Markdown

@github-actions

Copy link
Copy Markdown
Contributor

📊: Physics performance monitoring for 7a40407

Full contents

physmon summary

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

Labels

Component - Fatras Affects the Fatras module

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant