waynexia opened a new pull request, #12042:
URL: https://github.com/apache/arrow-rs/pull/12042

   
   # Which issue does this PR close?
   
   - N/A
   
   # Rationale for this change
   
   `BooleanBufferBuilder::append_slice` (which also backs 
`BooleanBuilder::append_slice`, `NullBufferBuilder::append_slice`, 
`PrimitiveBuilder::append_values`, and `BooleanBuffer::from(&[bool])`) 
previously appended booleans one bit at a time:
   
   ```rust
   for (i, v) in slice.iter().enumerate() {
       if *v {
           unsafe { bit_util::set_bit_raw(self.buffer.as_mut_ptr(), offset + i) 
}
       }
   }
   ```
   
   This had two main performance bottlenecks:
   1. **Branch mispredictions**: Every element required a conditional branch 
(`if *v`), causing frequent branch mispredictions on unpredictable boolean 
inputs.
   2. **Repeated byte-level read-modify-writes**: `set_bit_raw` performs a byte 
read, bitwise OR, and store for every `true` bit, creating a store-to-load 
dependency chain on the same target byte up to 8 times.
   
   Packing 8 booleans at a time into a single byte without branches and storing 
whole bytes eliminates both the branch mispredictions and the per-bit 
read-modify-write traffic.
   
   ## Human Rationale
   
   I'm trying to find something to burn my token, and come across this. This PR 
is fully written by AI. I have read and understand all logic changes. It 
increases complexity, but given that this part is not likely to be touched too 
often, I thought it was acceptable.
   
   # What changes are included in this PR?
   
   - Refactor `BooleanBufferBuilder::append_slice` into three phases:
     1. **Head**: If the current bit offset is not byte-aligned, pack the 
leading booleans into the existing partial byte while preserving 
already-written low bits and zeroing upper padding bits.
     2. **Middle**: Process 8 booleans at a time (`as_chunks::<8>()`) using a 
branchless SWAR multiplication 
(`(u64::from_le_bytes(bytes).wrapping_mul(0x0102_0408_1020_4080) >> 56) as u8`) 
and write full bytes directly to the buffer. 
`wrapping_mul(0x0102_0408_1020_4080) >> 56)` equals to 8 continuous "shift-left 
+ OR" 
     3. **Tail**: Pack any remaining `< 8` booleans into the final byte, 
keeping the trailing padding bits zeroed.
   - Add unit tests in `arrow-buffer` covering unaligned head/tail 
combinations, all-true/all-false inputs, empty slices, zeroed padding 
invariants, and randomized comparisons against a reference bit-by-bit 
implementation.
   
   # Are these changes tested?
   
   Yes
   
   Performance can also be verified with the existing `bench_bool` benchmark in 
`arrow/benches/builder.rs` (`cargo bench -p arrow --bench builder -- 
bench_bool`).
   
   On my local env, depends on the scenario, this patch can achieve at least 5x 
improvement on microbenchmark, except one bad case that append 1 bit a time
   
   # Are there any significant user-facing changes?
   
   No.


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to