Skip to content

Reuse buffers when interleaving byte views - #11281

Merged
Jefffrey merged 1 commit into
apache:mainfrom
pydantic:reuse_interleave_view_buffers
Oct 1, 2026
Merged

Jefffrey merged 1 commit into
apache:mainfrom
pydantic:reuse_interleave_view_buffers

Conversation

@cetra3

@cetra3 cetra3 commented Sep 29, 2026

Copy link
Copy Markdown
Contributor

Which issue does this PR close?

Fixes #11280

And also helps with: apache/datafusion#23565

Rationale for this change

See the original issue, but, basically the interleave kernel can make sub-optimal string views especially when buffers are shared.

What changes are included in this PR?

We use a btreemap on the seen buffers (not individual values) and use that to prevent us from cloning the same buffer multiple times.

Are these changes tested?

Yes tested, and locally benchmarks have shown a moderate speed increase in some of the interleave benchmarks, on my dev machine which has an AMD Ryzen 9 9950X3D processor:

benchmark main this PR change
interleave str_view(0.0) 100 [0..100, 100..230, 450..1000] 284.5 ns 268.6 ns -5.6%
interleave str_view(0.0) 400 [0..100, 100..230, 450..1000] 706.9 ns 563.9 ns -20.2%
interleave str_view(0.0) 1024 [0..100, 100..230, 450..1000] 1.717 µs 1.250 µs -27.2%
interleave str_view(0.0) 1024 [0..100, 100..230, 450..1000, 0..1000] 1.783 µs 1.274 µs -28.6%

Are there any user-facing changes?

No user facing changes, just an optimization.

@github-actions github-actions Bot added arrow Changes to the arrow crate arrow-select labels Sep 29, 2026
@cetra3

cetra3 commented Sep 29, 2026

Copy link
Copy Markdown
Contributor Author

run benchmark interleave_kernels

@adriangbot

Copy link
Copy Markdown

🤖 Arrow criterion benchmark running (GKE) | trigger
Instance: c4a-highmem-16 (12 vCPU / 65 GiB) | Linux bench-c5884066623-2903-lgtdw 6.12.94+ #1 SMP Wed Aug 19 07:47:20 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 reuse_interleave_view_buffers (e712522) to 74b630b (merge-base) diff

Run configuration
run benchmark interleave_kernels

BENCH_COMMAND=cargo bench --features=arrow,async,test_common,experimental,object_store --bench interleave_kernels
Results will be posted here when complete


File an issue against this benchmark runner

@adriangbot

Copy link
Copy Markdown

🤖 Arrow criterion benchmark completed (GKE) | trigger

Instance: c4a-highmem-16 (12 vCPU / 65 GiB)

Comparing reuse_interleave_view_buffers (e712522) to 74b630b (merge-base) diff

Run configuration
run benchmark interleave_kernels
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
Details

group                                                                                        main                                   reuse_interleave_view_buffers
-----                                                                                        ----                                   -----------------------------
interleave dict(20, 0.0) 100 [0..100, 100..230, 450..1000]                                   1.00    620.2±2.35ns        ? ?/sec    1.01    625.7±4.41ns        ? ?/sec
interleave dict(20, 0.0) 1024 [0..100, 100..230, 450..1000, 0..1000]                         1.00   1847.7±8.65ns        ? ?/sec    1.00   1840.2±5.17ns        ? ?/sec
interleave dict(20, 0.0) 1024 [0..100, 100..230, 450..1000]                                  1.00  1797.0±11.18ns        ? ?/sec    1.01  1810.8±11.70ns        ? ?/sec
interleave dict(20, 0.0) 400 [0..100, 100..230, 450..1000]                                   1.00   1007.4±4.01ns        ? ?/sec    1.02   1028.0±5.79ns        ? ?/sec
interleave dict_distinct 100                                                                 1.01      2.0±0.00µs        ? ?/sec    1.00   1993.2±2.87ns        ? ?/sec
interleave dict_distinct 1024                                                                1.00      6.3±0.01µs        ? ?/sec    1.01      6.3±0.01µs        ? ?/sec
interleave dict_distinct 2048                                                                1.00      3.5±0.02µs        ? ?/sec    1.01      3.5±0.02µs        ? ?/sec
interleave dict_sparse(20, 0.0) 100 [0..100, 100..230, 450..1000]                            1.00   1513.5±2.63ns        ? ?/sec    1.00   1519.9±4.46ns        ? ?/sec
interleave dict_sparse(20, 0.0) 1024 [0..100, 100..230, 450..1000, 0..1000]                  1.00      3.0±0.01µs        ? ?/sec    1.01      3.0±0.01µs        ? ?/sec
interleave dict_sparse(20, 0.0) 1024 [0..100, 100..230, 450..1000]                           1.00      2.7±0.01µs        ? ?/sec    1.01      2.7±0.01µs        ? ?/sec
interleave dict_sparse(20, 0.0) 400 [0..100, 100..230, 450..1000]                            1.00   1912.9±3.19ns        ? ?/sec    1.02   1943.6±3.03ns        ? ?/sec
interleave fixed_size_list<i64,5>(0.0,0.0) 100 [0..100, 100..230, 450..1000]                 1.00    498.6±2.20ns        ? ?/sec    1.01    502.6±1.65ns        ? ?/sec
interleave fixed_size_list<i64,5>(0.0,0.0) 1024 [0..100, 100..230, 450..1000, 0..1000]       1.02      3.0±0.01µs        ? ?/sec    1.00      2.9±0.00µs        ? ?/sec
interleave fixed_size_list<i64,5>(0.0,0.0) 1024 [0..100, 100..230, 450..1000]                1.04      3.0±0.01µs        ? ?/sec    1.00      2.9±0.00µs        ? ?/sec
interleave fixed_size_list<i64,5>(0.0,0.0) 400 [0..100, 100..230, 450..1000]                 1.02   1280.9±3.50ns        ? ?/sec    1.00   1253.9±7.50ns        ? ?/sec
interleave fixed_size_list<i64,5>(0.1,0.1) 100 [0..100, 100..230, 450..1000]                 1.00      2.3±0.05µs        ? ?/sec    1.00      2.3±0.05µs        ? ?/sec
interleave fixed_size_list<i64,5>(0.1,0.1) 1024 [0..100, 100..230, 450..1000, 0..1000]       1.00     19.0±0.52µs        ? ?/sec    1.00     19.1±0.51µs        ? ?/sec
interleave fixed_size_list<i64,5>(0.1,0.1) 1024 [0..100, 100..230, 450..1000]                1.00     19.0±0.53µs        ? ?/sec    1.00     19.1±0.52µs        ? ?/sec
interleave fixed_size_list<i64,5>(0.1,0.1) 400 [0..100, 100..230, 450..1000]                 1.00      7.7±0.20µs        ? ?/sec    1.00      7.7±0.19µs        ? ?/sec
interleave i32(0.0) 100 [0..100, 100..230, 450..1000]                                        1.00    214.0±4.36ns        ? ?/sec    1.01    216.2±3.49ns        ? ?/sec
interleave i32(0.0) 1024 [0..100, 100..230, 450..1000, 0..1000]                              1.01    965.7±6.61ns        ? ?/sec    1.00    959.7±1.07ns        ? ?/sec
interleave i32(0.0) 1024 [0..100, 100..230, 450..1000]                                       1.06   1016.9±2.33ns        ? ?/sec    1.00    955.2±1.44ns        ? ?/sec
interleave i32(0.0) 400 [0..100, 100..230, 450..1000]                                        1.13    516.0±1.81ns        ? ?/sec    1.00    454.7±0.66ns        ? ?/sec
interleave i32(0.5) 100 [0..100, 100..230, 450..1000]                                        1.00    450.3±2.38ns        ? ?/sec    1.00    451.6±2.48ns        ? ?/sec
interleave i32(0.5) 1024 [0..100, 100..230, 450..1000, 0..1000]                              1.00      2.9±0.01µs        ? ?/sec    1.00      2.9±0.01µs        ? ?/sec
interleave i32(0.5) 1024 [0..100, 100..230, 450..1000]                                       1.00      3.0±0.01µs        ? ?/sec    1.00      3.0±0.02µs        ? ?/sec
interleave i32(0.5) 400 [0..100, 100..230, 450..1000]                                        1.00   1265.1±4.49ns        ? ?/sec    1.00   1264.3±7.81ns        ? ?/sec
interleave list<i64>(0.0,0.0,20) 100 [0..100, 100..230, 450..1000]                           1.00    852.1±1.08ns        ? ?/sec    1.03    877.5±4.49ns        ? ?/sec
interleave list<i64>(0.0,0.0,20) 1024 [0..100, 100..230, 450..1000, 0..1000]                 1.00      6.6±0.01µs        ? ?/sec    1.01      6.7±0.01µs        ? ?/sec
interleave list<i64>(0.0,0.0,20) 1024 [0..100, 100..230, 450..1000]                          1.00      6.6±0.01µs        ? ?/sec    1.00      6.7±0.01µs        ? ?/sec
interleave list<i64>(0.0,0.0,20) 400 [0..100, 100..230, 450..1000]                           1.00      2.8±0.00µs        ? ?/sec    1.00      2.8±0.00µs        ? ?/sec
interleave list<i64>(0.1,0.1,20) 100 [0..100, 100..230, 450..1000]                           1.03      2.5±0.01µs        ? ?/sec    1.00      2.5±0.01µs        ? ?/sec
interleave list<i64>(0.1,0.1,20) 1024 [0..100, 100..230, 450..1000, 0..1000]                 1.00     20.2±0.06µs        ? ?/sec    1.00     20.2±0.04µs        ? ?/sec
interleave list<i64>(0.1,0.1,20) 1024 [0..100, 100..230, 450..1000]                          1.00     20.4±0.07µs        ? ?/sec    1.00     20.4±0.06µs        ? ?/sec
interleave list<i64>(0.1,0.1,20) 400 [0..100, 100..230, 450..1000]                           1.00      8.2±0.02µs        ? ?/sec    1.01      8.3±0.01µs        ? ?/sec
interleave list_view<i64>(0.0,0.0,20) 100 [0..100, 100..230, 450..1000]                      1.01      2.2±0.01µs        ? ?/sec    1.00      2.2±0.01µs        ? ?/sec
interleave list_view<i64>(0.0,0.0,20) 1024 [0..100, 100..230, 450..1000, 0..1000]            1.01     14.2±0.03µs        ? ?/sec    1.00     14.1±0.02µs        ? ?/sec
interleave list_view<i64>(0.0,0.0,20) 1024 [0..100, 100..230, 450..1000]                     1.00     14.0±0.03µs        ? ?/sec    1.00     14.0±0.06µs        ? ?/sec
interleave list_view<i64>(0.0,0.0,20) 400 [0..100, 100..230, 450..1000]                      1.01      6.2±0.02µs        ? ?/sec    1.00      6.1±0.01µs        ? ?/sec
interleave list_view<i64>(0.1,0.1,20) 100 [0..100, 100..230, 450..1000]                      1.00      3.7±0.01µs        ? ?/sec    1.00      3.7±0.04µs        ? ?/sec
interleave list_view<i64>(0.1,0.1,20) 1024 [0..100, 100..230, 450..1000, 0..1000]            1.00     24.8±0.13µs        ? ?/sec    1.00     24.8±0.14µs        ? ?/sec
interleave list_view<i64>(0.1,0.1,20) 1024 [0..100, 100..230, 450..1000]                     1.00     24.9±0.12µs        ? ?/sec    1.00     24.9±0.13µs        ? ?/sec
interleave list_view<i64>(0.1,0.1,20) 400 [0..100, 100..230, 450..1000]                      1.00     10.5±0.03µs        ? ?/sec    1.01     10.6±0.06µs        ? ?/sec
interleave list_view_overlapping<i64>(80x,20) 100 [0..100, 100..230, 450..1000]              1.01      2.4±0.00µs        ? ?/sec    1.00      2.4±0.01µs        ? ?/sec
interleave list_view_overlapping<i64>(80x,20) 1024 [0..100, 100..230, 450..1000, 0..1000]    1.00      5.9±0.02µs        ? ?/sec    1.00      5.9±0.03µs        ? ?/sec
interleave list_view_overlapping<i64>(80x,20) 1024 [0..100, 100..230, 450..1000]             1.00      5.7±0.02µs        ? ?/sec    1.00      5.7±0.03µs        ? ?/sec
interleave list_view_overlapping<i64>(80x,20) 400 [0..100, 100..230, 450..1000]              1.00      2.8±0.01µs        ? ?/sec    1.01      2.9±0.01µs        ? ?/sec
interleave map<utf8,i64>(0.0,5,8) 100 [0..100, 100..230, 450..1000]                          1.00      2.5±0.00µs        ? ?/sec    1.00      2.5±0.00µs        ? ?/sec
interleave map<utf8,i64>(0.0,5,8) 1024 [0..100, 100..230, 450..1000, 0..1000]                1.00     18.9±0.03µs        ? ?/sec    1.00     18.9±0.02µs        ? ?/sec
interleave map<utf8,i64>(0.0,5,8) 1024 [0..100, 100..230, 450..1000]                         1.01     18.8±0.09µs        ? ?/sec    1.00     18.7±0.02µs        ? ?/sec
interleave map<utf8,i64>(0.0,5,8) 400 [0..100, 100..230, 450..1000]                          1.00      7.8±0.01µs        ? ?/sec    1.00      7.8±0.01µs        ? ?/sec
interleave map<utf8,i64>(0.1,5,8) 100 [0..100, 100..230, 450..1000]                          1.01      2.6±0.00µs        ? ?/sec    1.00      2.6±0.00µs        ? ?/sec
interleave map<utf8,i64>(0.1,5,8) 1024 [0..100, 100..230, 450..1000, 0..1000]                1.00     19.3±0.03µs        ? ?/sec    1.00     19.2±0.02µs        ? ?/sec
interleave map<utf8,i64>(0.1,5,8) 1024 [0..100, 100..230, 450..1000]                         1.00     18.9±0.04µs        ? ?/sec    1.00     18.8±0.04µs        ? ?/sec
interleave map<utf8,i64>(0.1,5,8) 400 [0..100, 100..230, 450..1000]                          1.00      7.9±0.02µs        ? ?/sec    1.00      7.8±0.02µs        ? ?/sec
interleave ree_i32<dict<u32,utf8>>(64 runs) 100 [0..100, 100..230, 450..1000]                1.00      3.5±0.01µs        ? ?/sec    1.02      3.6±0.01µs        ? ?/sec
interleave ree_i32<dict<u32,utf8>>(64 runs) 1024 [0..100, 100..230, 450..1000, 0..1000]      1.01     19.9±0.06µs        ? ?/sec    1.00     19.7±0.07µs        ? ?/sec
interleave ree_i32<dict<u32,utf8>>(64 runs) 1024 [0..100, 100..230, 450..1000]               1.01     19.5±0.06µs        ? ?/sec    1.00     19.4±0.07µs        ? ?/sec
interleave ree_i32<dict<u32,utf8>>(64 runs) 400 [0..100, 100..230, 450..1000]                1.00      8.7±0.02µs        ? ?/sec    1.01      8.8±0.02µs        ? ?/sec
interleave ree_i32<i64>(64 runs) 100 [0..100, 100..230, 450..1000]                           1.00      2.8±0.01µs        ? ?/sec    1.01      2.8±0.01µs        ? ?/sec
interleave ree_i32<i64>(64 runs) 1024 [0..100, 100..230, 450..1000, 0..1000]                 1.00     18.7±0.07µs        ? ?/sec    1.00     18.7±0.07µs        ? ?/sec
interleave ree_i32<i64>(64 runs) 1024 [0..100, 100..230, 450..1000]                          1.00     18.2±0.05µs        ? ?/sec    1.00     18.2±0.05µs        ? ?/sec
interleave ree_i32<i64>(64 runs) 400 [0..100, 100..230, 450..1000]                           1.00      7.8±0.02µs        ? ?/sec    1.01      7.9±0.02µs        ? ?/sec
interleave str(20, 0.0) 100 [0..100, 100..230, 450..1000]                                    1.03    598.3±0.97ns        ? ?/sec    1.00    579.6±1.65ns        ? ?/sec
interleave str(20, 0.0) 1024 [0..100, 100..230, 450..1000, 0..1000]                          1.00      4.6±0.01µs        ? ?/sec    1.00      4.6±0.01µs        ? ?/sec
interleave str(20, 0.0) 1024 [0..100, 100..230, 450..1000]                                   1.00      4.6±0.01µs        ? ?/sec    1.00      4.6±0.01µs        ? ?/sec
interleave str(20, 0.0) 400 [0..100, 100..230, 450..1000]                                    1.00   1887.5±3.09ns        ? ?/sec    1.01   1905.8±2.89ns        ? ?/sec
interleave str(20, 0.5) 100 [0..100, 100..230, 450..1000]                                    1.00    747.2±1.13ns        ? ?/sec    1.00    745.1±1.66ns        ? ?/sec
interleave str(20, 0.5) 1024 [0..100, 100..230, 450..1000, 0..1000]                          1.00      6.0±0.02µs        ? ?/sec    1.00      5.9±0.01µs        ? ?/sec
interleave str(20, 0.5) 1024 [0..100, 100..230, 450..1000]                                   1.00      5.9±0.01µs        ? ?/sec    1.00      5.9±0.02µs        ? ?/sec
interleave str(20, 0.5) 400 [0..100, 100..230, 450..1000]                                    1.01      2.5±0.01µs        ? ?/sec    1.00      2.4±0.01µs        ? ?/sec
interleave str_view(0.0) 100 [0..100, 100..230, 450..1000]                                   1.15    546.2±1.85ns        ? ?/sec    1.00    474.1±1.43ns        ? ?/sec
interleave str_view(0.0) 1024 [0..100, 100..230, 450..1000, 0..1000]                         1.10      2.6±0.01µs        ? ?/sec    1.00      2.3±0.01µs        ? ?/sec
interleave str_view(0.0) 1024 [0..100, 100..230, 450..1000]                                  1.12      2.6±0.01µs        ? ?/sec    1.00      2.3±0.01µs        ? ?/sec
interleave str_view(0.0) 400 [0..100, 100..230, 450..1000]                                   1.16   1216.5±5.90ns        ? ?/sec    1.00   1046.8±2.59ns        ? ?/sec
interleave struct(i32(0.0), i32(0.0) 100 [0..100, 100..230, 450..1000]                       1.00    639.1±6.86ns        ? ?/sec    1.03    655.0±4.88ns        ? ?/sec
interleave struct(i32(0.0), i32(0.0) 1024 [0..100, 100..230, 450..1000, 0..1000]             1.01      2.1±0.01µs        ? ?/sec    1.00      2.1±0.01µs        ? ?/sec
interleave struct(i32(0.0), i32(0.0) 1024 [0..100, 100..230, 450..1000]                      1.01      2.2±0.01µs        ? ?/sec    1.00      2.1±0.00µs        ? ?/sec
interleave struct(i32(0.0), i32(0.0) 400 [0..100, 100..230, 450..1000]                       1.06   1217.7±4.49ns        ? ?/sec    1.00   1148.3±4.29ns        ? ?/sec
interleave struct(i32(0.0), str(20, 0.0) 100 [0..100, 100..230, 450..1000]                   1.00   1021.5±3.31ns        ? ?/sec    1.01   1036.7±3.25ns        ? ?/sec
interleave struct(i32(0.0), str(20, 0.0) 1024 [0..100, 100..230, 450..1000, 0..1000]         1.00      5.9±0.01µs        ? ?/sec    1.00      5.8±0.01µs        ? ?/sec
interleave struct(i32(0.0), str(20, 0.0) 1024 [0..100, 100..230, 450..1000]                  1.01      5.9±0.01µs        ? ?/sec    1.00      5.8±0.01µs        ? ?/sec
interleave struct(i32(0.0), str(20, 0.0) 400 [0..100, 100..230, 450..1000]                   1.00      2.6±0.01µs        ? ?/sec    1.01      2.6±0.00µs        ? ?/sec
interleave struct(str(20, 0.0), str(20, 0.0)) 100 [0..100, 100..230, 450..1000]              1.01   1416.3±3.78ns        ? ?/sec    1.00   1407.4±1.89ns        ? ?/sec
interleave struct(str(20, 0.0), str(20, 0.0)) 1024 [0..100, 100..230, 450..1000, 0..1000]    1.00      9.7±0.02µs        ? ?/sec    1.00      9.6±0.03µs        ? ?/sec
interleave struct(str(20, 0.0), str(20, 0.0)) 1024 [0..100, 100..230, 450..1000]             1.00      9.6±0.03µs        ? ?/sec    1.00      9.5±0.02µs        ? ?/sec
interleave struct(str(20, 0.0), str(20, 0.0)) 400 [0..100, 100..230, 450..1000]              1.00      4.1±0.01µs        ? ?/sec    1.00      4.1±0.01µs        ? ?/sec

Resource Usage

base (merge-base)

Metric Value
Wall time 845.2s
Peak memory 17.2 MiB
Avg memory 16.4 MiB
CPU user 839.8s
CPU sys 0.1s
Peak spill 0 B

branch

Metric Value
Wall time 840.2s
Peak memory 16.4 MiB
Avg memory 16.1 MiB
CPU user 836.0s
CPU sys 0.0s
Peak spill 0 B

File an issue against this benchmark runner

@cetra3

cetra3 commented Sep 29, 2026

Copy link
Copy Markdown
Contributor Author

Summary of benchmark results across both architectures:

benchmark x86-64 (Ryzen 9 9950X3D) aarch64 (Neoverse-V2, bot run)
interleave str_view(0.0) 100 [0..100, 100..230, 450..1000] 284.5 ns → 268.6 ns (-5.6%) 546.2 ns → 474.1 ns (-13.2%)
interleave str_view(0.0) 400 [0..100, 100..230, 450..1000] 706.9 ns → 563.9 ns (-20.2%) 1216.5 ns → 1046.8 ns (-14.0%)
interleave str_view(0.0) 1024 [0..100, 100..230, 450..1000] 1.717 µs → 1.250 µs (-27.2%) 2.6 µs → 2.3 µs (-10.7%)
interleave str_view(0.0) 1024 [0..100, 100..230, 450..1000, 0..1000] 1.783 µs → 1.274 µs (-28.6%) 2.6 µs → 2.3 µs (-9.1%)

No regressions in the rest of interleave_kernels on the bot run: every other benchmark is within noise (at most 3% either way).


// contains the mapping from old buffer index to new buffer index
let mut buffer_to_new_index = vec![None; total_buffers];
let mut buffer_to_new_index = vec![UNASSIGNED; total_buffers];

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.

is switching from option to a sentinel value a performance optimization or ergonomic change?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

This was left over from a bit of churn. I tried about 5 different approaches to get this shape.

However, this does add a speed bump, since an Option<u32> is 8 bytes vs 4

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.

makes sense, thanks

/// buffer, so this checks by identity to ensure it is only emitted once
#[inline(never)]
fn push_buffer(
seen: &mut BTreeMap<(*const u8, usize), u32>,

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.

a minor optimization could be to hash only on pointer then always accept the buffer with larger len (which means retroactively changing the buffer in buffers), but i suppose thats more trouble than its worth for presumably a rare case 🤔

  • and probably less performant

@Jefffrey Jefffrey changed the title Reuse buffers when interleaving Reuse buffers when interleaving byte views Oct 1, 2026
@Jefffrey
Jefffrey merged commit 007894e into apache:main Oct 1, 2026
42 checks passed
@Jefffrey

Jefffrey commented Oct 1, 2026

Copy link
Copy Markdown
Contributor

thanks @cetra3

cetra3 added a commit to pydantic/arrow-rs that referenced this pull request Oct 2, 2026
# Which issue does this PR close?

Fixes apache#11280

And also helps with: apache/datafusion#23565

# Rationale for this change

See the original issue, but, basically the interleave kernel can make
sub-optimal string views especially when buffers are shared.

# What changes are included in this PR?

We use a btreemap on the seen buffers (not individual values) and use
that to prevent us from cloning the same buffer multiple times.

# Are these changes tested?

Yes tested, and locally benchmarks have shown a moderate speed increase
in some of the interleave benchmarks, on my dev machine which has an
**AMD Ryzen 9 9950X3D** processor:

| benchmark | main | this PR | change |

|-----------------------------------------------------------------------|----------|----------|--------|
| interleave str_view(0.0) 100 [0..100, 100..230, 450..1000] | 284.5 ns
| 268.6 ns | -5.6% |
| interleave str_view(0.0) 400 [0..100, 100..230, 450..1000] | 706.9 ns
| 563.9 ns | -20.2% |
| interleave str_view(0.0) 1024 [0..100, 100..230, 450..1000] | 1.717 µs
| 1.250 µs | -27.2% |
| interleave str_view(0.0) 1024 [0..100, 100..230, 450..1000, 0..1000] |
1.783 µs | 1.274 µs | -28.6% |

# Are there any user-facing changes?

No user facing changes, just an optimization.

(cherry picked from commit 007894e)
alamb added a commit to alamb/datafusion that referenced this pull request Oct 16, 2026
* `interleave` no longer repeats a shared data buffer for byte view arrays
  (apache/arrow-rs#11281), so the spill `compact_view_array` tests build
  the repeated-buffer array by hand
* Casting a naive timestamp to a named time zone now resolves DST-ambiguous
  and nonexistent local times like PostgreSQL instead of erroring
  (apache/arrow-rs#11038): update `timestamps_timezone.slt`

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
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 arrow-select performance

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Interleave for String Views duplicates buffers

3 participants