perf: branchless mask-select for listview zip#8264
Conversation
Merging this PR will not alter performance
|
| Mode | Benchmark | BASE |
HEAD |
Efficiency | |
|---|---|---|---|---|---|
| 🆕 | Simulation | nonnull |
N/A | 302.5 µs | N/A |
| 🆕 | Simulation | nullable |
N/A | 315.4 µs | N/A |
Comparing claude/wizardly-carson-6Cixf (3b5db68) with develop (0026d3a)
Footnotes
-
4 benchmarks were skipped, so the baseline results were used instead. If they were deleted from the codebase, click here and archive them to remove them from the performance reports. ↩
d11d3b8 to
ddeb10d
Compare
8ea7fb9 to
f05b6a0
Compare
|
This PR has been marked as stale because it has been open for 14 days with no activity. Please comment or remove the stale label if you wish to keep it active, otherwise it will be closed in 7 days |
a9516cf to
8c26832
Compare
Replace the per-element, data-dependent branch in the listview zip kernel's offset/size selection with a branchless, chunk-at-a-time mask select that the compiler can auto-vectorize. For each 64-bit mask chunk, each bit is expanded to a full-width lane mask and both sides are blended with `(t & m) | (f & !m)` via a shared `select_column` helper, so the inner loop is branch-free regardless of mask shape. `if_false` offsets are shifted into the second half of the concatenated elements as before. Adds a `listview_zip` divan benchmark across fragmented/block/sparse/dense masks for nullable and non-nullable inputs. Signed-off-by: Joe Isaacs <joe.isaacs@live.co.uk>
Reduce the divan bench to one Fragmented (alternating) mask with non-nullable and nullable inputs, and lower LEN to 8192 so each case stays well under a few hundred microseconds. The branchless chunked select is mask-shape-independent, so a single shape suffices; drop the now-unused MaskShape matrix. Signed-off-by: Joe Isaacs <joe.isaacs@live.co.uk>
CodSpeed's instruction-count simulation runs ~10x local walltime, putting the 8192-list bench at ~550us there. Drop to 4096 lists so each case stays well under a few hundred microseconds in CI while still exercising the select. Signed-off-by: Joe Isaacs <joe.isaacs@live.co.uk>
1e8c616 to
3b5db68
Compare
Summary
Replaces the per-element, data-dependent branch in the listview zip kernel's offset/size selection with a branchless, chunk-at-a-time mask select that the compiler can auto-vectorize.
For each 64-bit mask chunk, each bit is expanded to a full-width lane mask and both sides are blended with
(t & m) | (f & !m)via a sharedselect_columnhelper, so the inner loop is branch-free regardless of mask shape.if_falseoffsets are shifted into the second half of the concatenatedelementsas before; sizes are taken verbatim from the chosen side.Changes
vortex-array/src/arrays/listview/compute/zip.rs: branchless chunked offset/size select viaselect_column; added a test that spans the 64-bit chunk boundary + remainder.vortex-array/benches/listview_zip.rs: a small divan bench — one Fragmented (alternating) mask with non-nullable and nullable inputs.Benchmark
Because the branchless select is mask-shape-independent, the bench uses a single Fragmented mask (the worst case for the replaced per-element branch) with both nullability variants.
LENis 8,192: listview zip cost is dominated by element concatenation and per-list canonicalization, so a few thousand lists already exercise the select while keeping each case well under a few hundred microseconds (~37 µs non-null, ~41 µs nullable locally).The kernel change itself is a single-to-low-double-digit-percent win on the offset/size select; end-to-end listview zip is dominated by element concatenation + canonicalization, so the select is a small slice of total cost.
Testing
vortex-arraylistview zip tests pass (incl. the new multi-chunk-span test);cargo +nightly fmtandclippy -D warnings(default + all-features) clean.https://claude.ai/code/session_01N5ivPiCJy7dGQjMEP7ips9