Skip to content

Add TakeSlices for fixed-size-list take#8674

Open
danking wants to merge 3 commits into
developfrom
codex/take-slices-fsl
Open

Add TakeSlices for fixed-size-list take#8674
danking wants to merge 3 commits into
developfrom
codex/take-slices-fsl

Conversation

@danking

@danking danking commented Jul 7, 2026

Copy link
Copy Markdown
Contributor

The key issue here is that fixed_size_list.take(indices) explodes the indices into one index per list element. For a fixed size list of length 4096, this means the number of take indices expands by three orders of magnitude. Moreover, the take kernel must either naively copy each index separately or reconstruct the fact that these are actually slices so that it can use copy_from_slice.

Concretely, for a FixedSizeList<100, u8> array, this:

fixed_size_list.take([10, 100, 0])

becomes:

fixed_size_list.elements().take([1000, 1001, ..., 1099, 10000, 10001, ..., 10099, 0, 1, ..., 99])

My new benchmarks make clear that using take with these indices on a canonical elements array (implemented here) is much slower than using a sequence of output.extend_from_slice(buffer[...]) (implemented here).

This is a table of results for FixedSizeList<N, f16>

list size bytes/list indices per-index take_slices manual range copy per-index / take_slices
1 2 B 100 1.17 us 1.04 us 666 ns 1.12x
1 2 B 1000 3.08 us 4.00 us 2.42 us 0.77x
16 32 B 100 4.33 us 1.21 us 661 ns 3.59x
16 32 B 1000 35.3 us 5.54 us 2.71 us 6.37x
256 512 B 100 55.9 us 1.83 us 1.35 us 30.5x
256 512 B 1000 552 us 12.7 us 10.1 us 43.4x
1024 2048 B 100 220 us 3.87 us 3.42 us 56.7x
1024 2048 B 1000 2.40 ms 105 us 99.6 us 22.8x
4096 8192 B 100 927 us 13.5 us 12.9 us 68.7x
4096 8192 B 1000 9.18 ms 391 us 381 us 23.5x

Codex:

Summary

  • Add TakeSlicesArray as a lazy ordered-range selection over one child.
  • Route FixedSizeList take through ordered element ranges via take_slices, leaving child encodings responsible for optimization.
  • Add a primitive TakeSlicesExecute kernel that copies each requested range directly from the primitive slice.
  • Expand take_fsl benchmarks across element byte widths and forced f16 strategy comparisons.

Correctness and Coverage

  • TakeSlices validates all public construction ranges as non-empty and in-bounds.
  • Generic TakeSlices execution repeatedly slices the child and appends each range; it does not require a canonical child up front.
  • Nullable FSL take uses placeholder element ranges for null output rows and keeps nullness in outer FSL validity.
  • Tests cover reordered ranges, duplicate ranges, overlapping ranges, empty children, empty outputs, size-one children, invalid ranges, nested TakeSlices, nullable primitive validity, scalar/validity access, generic encoded-child fallback, nullable encoded-child fallback, and nullable FSL take with nullable indices.

Validation

  • cargo +nightly fmt --all
  • cargo test -p vortex-array take_slices
  • cargo test -p vortex-array fixed_size_list::tests::take
  • cargo check -p vortex-array --all-targets
  • cargo clippy --all-targets --all-features
  • git diff --cached --check

@codspeed-hq

codspeed-hq Bot commented Jul 7, 2026

Copy link
Copy Markdown

Merging this PR will not alter performance

⚡ 3 improved benchmarks
❌ 2 regressed benchmarks
✅ 1582 untouched benchmarks
🆕 152 new benchmarks
⏩ 62 skipped benchmarks1

Warning

Please fix the performance issues or acknowledge them on CodSpeed.

Performance Changes

Mode Benchmark BASE HEAD Efficiency
Simulation slice_empty_vortex 310.3 ns 368.6 ns -15.83%
Simulation chunked_varbinview_opt_canonical_into[(100, 100)] 305.2 µs 341.5 µs -10.63%
Simulation chunked_varbinview_canonical_into[(1000, 10)] 190.9 µs 154.9 µs +23.28%
Simulation bitwise_not_vortex_buffer_mut[128] 244.4 ns 215.3 ns +13.55%
Simulation bitwise_not_vortex_buffer_mut[1024] 304.7 ns 275.6 ns +10.58%
🆕 Simulation take_fsl_f16_force_per_index[1, 100] N/A 28.4 µs N/A
🆕 Simulation take_fsl_f16_force_per_index[1, 1000] N/A 41.9 µs N/A
🆕 Simulation take_fsl_f16_force_per_index[1024, 100] N/A 1.2 ms N/A
🆕 Simulation take_fsl_f16_force_per_index[1024, 1000] N/A 11.6 ms N/A
🆕 Simulation take_fsl_f16_force_per_index[128, 100] N/A 160.9 µs N/A
🆕 Simulation take_fsl_f16_force_per_index[128, 1000] N/A 1.3 ms N/A
🆕 Simulation take_fsl_f16_force_per_index[16, 100] N/A 46.6 µs N/A
🆕 Simulation take_fsl_f16_force_per_index[16, 1000] N/A 191.5 µs N/A
🆕 Simulation take_fsl_f16_force_per_index[2, 100] N/A 30.2 µs N/A
🆕 Simulation take_fsl_f16_force_per_index[2, 1000] N/A 52 µs N/A
🆕 Simulation take_fsl_f16_force_per_index[2048, 100] N/A 2.4 ms N/A
🆕 Simulation take_fsl_f16_force_per_index[2048, 1000] N/A 26.6 ms N/A
🆕 Simulation take_fsl_f16_force_per_index[256, 100] N/A 330.2 µs N/A
🆕 Simulation take_fsl_f16_force_per_index[256, 1000] N/A 2.9 ms N/A
🆕 Simulation take_fsl_f16_force_per_index[4, 100] N/A 32.9 µs N/A
... ... ... ... ... ...

ℹ️ Only the first 20 benchmarks are displayed. Go to the app to view all benchmarks.

Tip

Investigate this regression by commenting @codspeedbot fix this regression on this PR, or directly use the CodSpeed MCP with your agent.


Comparing codex/take-slices-fsl (b5bf567) with develop (1e91494)

Open in CodSpeed

Footnotes

  1. 62 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.

@danking danking force-pushed the codex/take-slices-fsl branch 4 times, most recently from 0908aec to a039028 Compare July 7, 2026 18:12
@danking danking added the changelog/performance A performance improvement label Jul 7, 2026
Introduce a lazy TakeSlices array for ordered child ranges, wire FixedSizeList take to emit element ranges, and add a primitive child execution kernel for contiguous range copies.

Expand FSL take benchmarks and cover TakeSlices edge cases, nullable validity, generic slice-based execution, and nullable FSL take with nullable indices.

Signed-off-by: "Daniel King" <dan@spiraldb.com>
Signed-off-by: Daniel King <dan@spiraldb.com>
@danking danking force-pushed the codex/take-slices-fsl branch from a039028 to 949cfcb Compare July 7, 2026 20:00
danking added 2 commits July 7, 2026 16:50
Refactor fixed-size-list take around structural cases, tighten TakeSlices validation, and extend edge-case coverage. Also document the local-reasoning guideline that would have avoided threading fallback state through the main path.

Signed-off-by: "Daniel King" <dan@spiraldb.com>
Signed-off-by: Daniel King <dan@spiraldb.com>
Replace ambiguous ordered-range wording with caller-provided sequence terminology so the API docs do not imply sorted or disjoint ranges.

Signed-off-by: "Daniel King" <dan@spiraldb.com>
Signed-off-by: Daniel King <dan@spiraldb.com>
@danking danking marked this pull request as ready for review July 7, 2026 21:06
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

changelog/performance A performance improvement

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant