perf(nullbuf::expand) non aligned counts - #10980
Conversation
|
run benchmark take_kernels |
|
🤖 Arrow criterion benchmark running (GKE) | trigger CPU Details (lscpu)Comparing rich-T-kid/optimize-non-aligned-expand (1f37f77) to ec21627 (merge-base) diff Run configurationrun benchmark take_kernels
env:
BENCH_FILTER: "fixed_size_list"BENCH_COMMAND=cargo bench --features=arrow,async,test_common,experimental,object_store --bench take_kernels File an issue against this benchmark runner |
|
🤖 Arrow criterion benchmark completed (GKE) | trigger Instance: Comparing rich-T-kid/optimize-non-aligned-expand (1f37f77) to ec21627 (merge-base) diff Run configurationrun benchmark take_kernels
env:
BENCH_FILTER: "fixed_size_list"CPU Details (lscpu)Details
Resource Usagebase (merge-base)
branch
File an issue against this benchmark runner |
|
nice |
…counts Use BitSliceIterator to process runs of valid bits at a time rather than calling set_bit once per bit per count. For a run [start, end of valid source bits the output range [start*count, end*count) is filled by OR-masking the two boundary bytes and memsetting interior bytes to 0xFF. Benchmarks (len=1024, alternating 4 valid / 4 null): count=7: 2.54 µs → 442 ns (-83%) count=17: 8.15 µs → 441 ns (-95%) count=29: 16.9 µs → 580 ns (-97%) EOF )
1f37f77 to
95fadd0
Compare
|
run benchmark take_kernels |
1 similar comment
|
run benchmark take_kernels |
|
@Jefffrey this is also ready for review now. split it from the other PR since it has a lot of bit manipulation logic. |
|
🤖 Arrow criterion benchmark running (GKE) | trigger CPU Details (lscpu)Comparing rich-T-kid/optimize-non-aligned-expand (623846c) to cb682a2 (merge-base) diff Run configurationrun benchmark take_kernels
env:
BENCH_FILTER: "fixed_size_list"BENCH_COMMAND=cargo bench --features=arrow,async,test_common,experimental,object_store --bench take_kernels File an issue against this benchmark runner |
|
🤖 Arrow criterion benchmark running (GKE) | trigger CPU Details (lscpu)Comparing rich-T-kid/optimize-non-aligned-expand (623846c) to cb682a2 (merge-base) diff Run configurationrun benchmark take_kernels
env:
BENCH_FILTER: "fixed_size_list"BENCH_COMMAND=cargo bench --features=arrow,async,test_common,experimental,object_store --bench take_kernels File an issue against this benchmark runner |
|
🤖 Arrow criterion benchmark completed (GKE) | trigger Instance: Comparing rich-T-kid/optimize-non-aligned-expand (623846c) to cb682a2 (merge-base) diff Run configurationrun benchmark take_kernels
env:
BENCH_FILTER: "fixed_size_list"CPU Details (lscpu)Details
Resource Usagebase (merge-base)
branch
File an issue against this benchmark runner |
|
🤖 Arrow criterion benchmark completed (GKE) | trigger Instance: Comparing rich-T-kid/optimize-non-aligned-expand (623846c) to cb682a2 (merge-base) diff Run configurationrun benchmark take_kernels
env:
BENCH_FILTER: "fixed_size_list"CPU Details (lscpu)Details
Resource Usagebase (merge-base)
branch
File an issue against this benchmark runner |
note I did use ai to help me with the bit maniluplation logic!
Which issue does this PR close?
Rationale for this change
NullBuffer::expandnow has a fast path for count % 8 == 0 (byte-aligned) and count % 4 == 0 (nibble-aligned) counts. For all other values of count the fallback iterated every bit individually, calling set_bit per valid index. This is O(n × count) bit-level writes even when the validity buffer is mostly non-null.What changes are included in this PR?
Replaces the bit-by-bit fallback in
NullBuffer::try_expandwith a BitSliceIterator based approach that works over contiguous runs of valid bits rather than individual bits. For each run [start, end) it computes the output byte range [startcount/8, endcount/8] and sets it with byte-level OR masks:Are these changes tested?
yes, test was introduced in #10976
Are there any user-facing changes?
no