Skip to content

Use interleave for fragmented zip masks#10368

Open
Jo2234 wants to merge 2 commits into
apache:mainfrom
Jo2234:perf/zip-interleave
Open

Use interleave for fragmented zip masks#10368
Jo2234 wants to merge 2 commits into
apache:mainfrom
Jo2234:perf/zip-interleave

Conversation

@Jo2234

@Jo2234 Jo2234 commented Jul 18, 2026

Copy link
Copy Markdown

Which issue does this PR close?

Rationale for this change

zip currently uses MutableArrayData, which is efficient when a mask contains long runs but performs one extension per run. Fragmented array/array masks therefore pay substantial per-run overhead, while the specialized interleave kernels are faster for this shape.

What changes are included in this PR?

  • Count true runs in large masks and route fragmented array/array inputs to interleave
  • Keep the existing MutableArrayData path for inputs shorter than 1,024 rows, scalar inputs, and masks with fewer runs
  • Treat null mask entries as false before dispatch, preserving existing zip semantics
  • Extend the zip benchmark with a direct interleave comparison and a contiguous true_then_false case

The run-count threshold is conservative: interleave is selected only above one true run per eight rows. Counting the complete bitmap also avoids sampling errors for masks whose fragmentation is unevenly distributed.

Are these changes tested?

Yes. The new tests cover dispatch decisions for short, fragmented, sparse/dense, contiguous, unevenly fragmented, and offset masks, plus end-to-end fragmented array selection with null mask and input values.

Validation:

  • CARGO_BUILD_JOBS=2 cargo test -p arrow-select --all-features (394 unit tests and 17 doctests passed)
  • CARGO_BUILD_JOBS=2 cargo clippy -p arrow-select --all-targets --all-features -- -D warnings
  • CARGO_BUILD_JOBS=2 cargo clippy -p arrow --bench zip_kernels --features=async,test_utils -- -D warnings
  • cargo +stable fmt --all -- --check
  • CARGO_BUILD_JOBS=2 RUSTDOCFLAGS='-D warnings' cargo doc -p arrow-select --no-deps

Criterion used 30 samples, a 2-second warm-up, and a 5-second measurement. On 8,192-row array/array inputs with random 50%-true masks, the existing run path was forced by temporarily raising the local dispatch threshold; the benchmark-only control was then restored:

Input Run path Adaptive Improvement
i32 76.889 us 33.676 us 56.20%
short strings 101.600 us 69.580 us 31.52%
long strings 214.880 us 125.560 us 41.57%
short bytes 103.680 us 70.169 us 32.32%
long bytes 218.090 us 123.040 us 43.58%
short string views 85.114 us 38.201 us 55.12%
longer string views 84.633 us 49.308 us 41.74%

At the 1,024-row boundary, i32 measured 14.350 us on the forced run path versus 4.6005 us on the adaptive path. The contiguous true_then_false case remains on the run-oriented path.

AI assistance was used to draft parts of the adaptive dispatch, tests, and benchmark changes. The resulting diff was reviewed against the zip, MutableArrayData, BooleanBuffer, and interleave implementations; an edge-sampling flaw found during review was replaced with a complete run count and covered by a regression test. The checks and benchmark results above were rerun on the final implementation.

Are there any user-facing changes?

No API or semantic changes. Fragmented array/array zip calls use a faster internal implementation; scalar, short, and contiguous-mask calls retain the existing path.

Count true runs in large array/array masks and dispatch fragmented masks to the interleave kernel while retaining MutableArrayData for scalar, short, and contiguous inputs. Extend zip benchmarks with direct interleave and long-run comparisons.
@github-actions github-actions Bot added the arrow Changes to the arrow crate label Jul 18, 2026
@Jo2234
Jo2234 marked this pull request as ready for review July 18, 2026 06:31
@Jefffrey

Copy link
Copy Markdown
Contributor

run benchmark zip_kernels

Comment thread arrow-select/src/zip.rs
zip_impl(mask, &truthy, truthy_is_scalar, &falsy, falsy_is_scalar)
}

fn count_true_runs(mask: &BooleanBuffer) -> usize {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we should probably have some unit tests for this specific function

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added direct count_true_runs coverage in 8c47191, including empty/all-false/all-true masks, multiple runs, 64-bit chunk boundaries with trailing padding, and sliced masks with non-zero bit offsets. cargo test -p arrow-select --all-features passes (394 unit tests and 17 doctests); formatting and clippy checks also pass.

@adriangbot

Copy link
Copy Markdown

🤖 Arrow criterion benchmark running (GKE) | trigger
Instance: c4a-highmem-16 (12 vCPU / 65 GiB) | Linux bench-c5015804642-1157-742hk 6.12.85+ #1 SMP Mon May 11 08:17:35 UTC 2026 aarch64 GNU/Linux

CPU Details (lscpu)
Architecture:                            aarch64
CPU op-mode(s):                          64-bit
Byte Order:                              Little Endian
CPU(s):                                  16
On-line CPU(s) list:                     0-15
Vendor ID:                               ARM
Model name:                              Neoverse-V2
Model:                                   1
Thread(s) per core:                      1
Core(s) per cluster:                     16
Socket(s):                               -
Cluster(s):                              1
Stepping:                                r0p1
BogoMIPS:                                2000.00
Flags:                                   fp asimd evtstrm aes pmull sha1 sha2 crc32 atomics fphp asimdhp cpuid asimdrdm jscvt fcma lrcpc dcpop sha3 sm3 sm4 asimddp sha512 sve asimdfhm dit uscat ilrcpc flagm sb paca pacg dcpodp sve2 sveaes svepmull svebitperm svesha3 svesm4 flagm2 frint svei8mm svebf16 i8mm bf16 dgh rng bti
L1d cache:                               1 MiB (16 instances)
L1i cache:                               1 MiB (16 instances)
L2 cache:                                32 MiB (16 instances)
L3 cache:                                80 MiB (1 instance)
NUMA node(s):                            1
NUMA node0 CPU(s):                       0-15
Vulnerability Gather data sampling:      Not affected
Vulnerability Indirect target selection: Not affected
Vulnerability Itlb multihit:             Not affected
Vulnerability L1tf:                      Not affected
Vulnerability Mds:                       Not affected
Vulnerability Meltdown:                  Not affected
Vulnerability Mmio stale data:           Not affected
Vulnerability Reg file data sampling:    Not affected
Vulnerability Retbleed:                  Not affected
Vulnerability Spec rstack overflow:      Not affected
Vulnerability Spec store bypass:         Mitigation; Speculative Store Bypass disabled via prctl
Vulnerability Spectre v1:                Mitigation; __user pointer sanitization
Vulnerability Spectre v2:                Mitigation; CSV2, BHB
Vulnerability Srbds:                     Not affected
Vulnerability Tsa:                       Not affected
Vulnerability Tsx async abort:           Not affected
Vulnerability Vmscape:                   Not affected

Comparing perf/zip-interleave (c4c42dc) to 305bf26 (merge-base) diff
BENCH_NAME=zip_kernels
BENCH_COMMAND=cargo bench --features=arrow,async,test_common,experimental,object_store --bench zip_kernels
BENCH_FILTER=
Results will be posted here when complete


File an issue against this benchmark runner

@adriangbot

Copy link
Copy Markdown

Benchmark for this request hit the 7200s job deadline before finishing.

Benchmarks requested: zip_kernels

Kubernetes message
Job was active longer than specified deadline

File an issue against this benchmark runner

@Jo2234

Jo2234 commented Jul 19, 2026

Copy link
Copy Markdown
Author

The full zip_kernels run hit the 7200s runner deadline. A documented filtered retry with BENCH_FILTER: array_vs_array would cover the dispatch-affected array/array cases while excluding scalar-only cases; the bot does not permit me to launch it. The PR body includes local Criterion results on the final production head.

@adriangbot

Copy link
Copy Markdown

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

arrow Changes to the arrow crate

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Evaluate Using Interleave Kernel for Zip

3 participants