Skip to content

[STACKED] perf(reduce): share strided cell copy between reduce and storage_grower - #450

Draft
henryiii wants to merge 6 commits into
boostorg:developfrom
henryiii:perf/shared-cell-copy
Draft

henryiii wants to merge 6 commits into
boostorg:developfrom
henryiii:perf/shared-cell-copy

Conversation

@henryiii

@henryiii henryiii commented Nov 2, 2026

Copy link
Copy Markdown
Contributor

🤖 AI text below 🤖

Depends on #448. This branch contains the commits of #448; only the last commit is new.

Adds detail::cell_map, which holds one lookup table per axis that maps each stored input bin to an output offset, and visits the input cells line by line along the first axis. reduce and storage_grower both use it. storage_grower no longer steps through a multi-index and calls for_each_axis for each cell. The rank-0 special case in reduce moves into cell_map.

Growth benchmark (3D, 30³ regular growth axes, one fill that grows one axis by one bin, histogram copy included):

Case Before After
dense, no flow bins 85 µs 73 µs
dense, with under/overflow 214 µs 91 µs
dynamic axes 97 µs 74 µs
unlimited storage 86 µs 74 µs

For large histograms, allocating and zeroing the new storage takes most of the time.

reduce visited every input cell through indexed() and computed the
output index with result.at(idx) per cell. It now builds one lookup
table per axis which maps each stored input position to an output
offset, or marks it as skipped, and runs a nested strided loop over the
raw storage. Skipped outer slabs are skipped as a block, so crop and
pick in crop mode scale with the output size. For arithmetic dense
storages, runs of input cells which land in the same output cell are
summed in a local accumulator, in the same order as before.

Adds pick benchmarks which mirror the boost-histogram python
benchmarks, and a test with large axes which exercises the heap-backed
lookup table.

Assisted-by: ClaudeCode:claude-fable-5-1
ClaudeCode:claude-fable-5-1
Drop reduce_command::lut and fill the per-axis table for pick commands
directly, which removes a heap allocation per picked axis and the
underflow special case. Use axis::traits::extent for the axis extent and
share the setup of the pick benchmarks.

Assisted-by: ClaudeCode:claude-opus-5-5
Assisted-by: ClaudeCode:claude-opus-5-5
The stack buffer saved about 12 ns per call, visible only on 1D
histograms with few bins.

Assisted-by: ClaudeCode:claude-fable-5-1
Assisted-by: ClaudeCode:claude-opus-5-5
Add detail::cell_map, which maps each input cell to an output offset
through one lookup table per axis and visits the cells line by line.
reduce and storage_grower now both use it. storage_grower no longer
steps through a multi-index cell by cell.

Assisted-by: ClaudeCode:claude-opus-5-5
@henryiii henryiii changed the title perf: share strided cell copy between reduce and storage_grower perf(reduce): share strided cell copy between reduce and storage_grower Nov 2, 2026
@henryiii henryiii changed the title perf(reduce): share strided cell copy between reduce and storage_grower [STACKED] perf(reduce): share strided cell copy between reduce and storage_grower Nov 3, 2026

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.

1 participant