This is an automated email from the ASF dual-hosted git repository.

github-merge-queue[bot] pushed a commit to branch 
gh-readonly-queue/main/pr-11714-fb88f81d39601a5d0244d8ef034d7e2a10788c60
in repository https://gitbox.apache.org/repos/asf/arrow-rs.git

commit 08928b340c77062c1c343815e2d140f090bd110b
Author: Michael Hoffmann <[email protected]>
AuthorDate: Sun Oct 25 22:59:04 2026 +0000

    bench(arrow): cover interleave of lists with primitive struct children 
(#11714)
    
    # Rationale for this change
    
    List interleave can copy primitive child ranges directly, but a Struct
    child takes the expanded-index path. Add coverage before changing that
    implementation so its costs and existing primitive-list behavior can be
    compared independently.
    
    # What changes are included in this PR?
    
    Extend interleave_kernels with 4,096 alternating parent selections from
    six inputs. Cover Int64/Float64 Struct children with singleton, 15- and
    90-element, and mixed-length lists, including independently nullable and
    sliced arrays. Include matching primitive-list controls.
    
    # Are these changes tested?
    
    The new benchmark cases build and run against the unmodified kernel and
    the proposed optimization using the actual Arrow workspace. No library
    code changes are included in this commit.
    
    # Are there any significant user-facing changes?
    
    No.
    
    # AI usage
    
    AI assistance was used to write and review the benchmark and run the
    comparisons. Human review and ownership remain with the submitter.
    
    Co-authored-by: RIchard Baah <[email protected]>
---
 arrow/benches/interleave_kernels.rs | 77 ++++++++++++++++++++++++++++++++++++-
 1 file changed, 75 insertions(+), 2 deletions(-)

diff --git a/arrow/benches/interleave_kernels.rs 
b/arrow/benches/interleave_kernels.rs
index 3ccc82fa1f..35cccf215a 100644
--- a/arrow/benches/interleave_kernels.rs
+++ b/arrow/benches/interleave_kernels.rs
@@ -26,7 +26,7 @@ use rand::RngExt;
 use arrow::datatypes::*;
 use arrow::util::test_util::seedable_rng;
 use arrow::{array::*, util::bench_util::*};
-use arrow_buffer::ScalarBuffer;
+use arrow_buffer::{NullBuffer, OffsetBuffer, ScalarBuffer};
 use arrow_select::interleave::interleave;
 use std::hint;
 use std::sync::Arc;
@@ -222,5 +222,78 @@ fn add_benchmark(c: &mut Criterion) {
     }
 }
 
-criterion_group!(benches, add_benchmark);
+// Alternate sources so parent rows cannot coalesce, while each selected list
+// contributes a contiguous range of 15 children. Compare struct children with
+// the existing primitive-copy path, with and without nulls.
+// Both variants use sliced inputs.
+fn bench_list_ranges(c: &mut Criterion) {
+    const ROWS: usize = 4096;
+    const SOURCES: usize = 6;
+    let indices: Vec<_> = (0..ROWS).map(|i| (i % SOURCES, i / 
SOURCES)).collect();
+    for nullable in [false, true] {
+        for primitive in [false, true] {
+            let arrays: Vec<ArrayRef> = (0..SOURCES)
+                .map(|source| {
+                    let rows = ROWS.div_ceil(SOURCES) + 3;
+                    let offsets = 
OffsetBuffer::<i32>::from_lengths(std::iter::repeat_n(15, rows));
+                    let len = *offsets.as_ref().last().unwrap() as usize;
+                    let nulls = |len, period| {
+                        (nullable && source % 3 != 0).then(|| {
+                            NullBuffer::from_iter((0..len).map(|i| (i + 
source) % period != 0))
+                        })
+                    };
+                    let ints = Int64Array::new(
+                        (0..len + 6)
+                            .map(|i| (i + source) as i64)
+                            .collect::<Vec<_>>()
+                            .into(),
+                        nulls(len + 6, 5),
+                    )
+                    .slice(1, len + 5);
+                    let values: ArrayRef = if primitive {
+                        Arc::new(ints.slice(5, len))
+                    } else {
+                        let floats = Float64Array::new(
+                            (0..len + 8)
+                                .map(|i| (i + source) as f64 * 0.25)
+                                .collect::<Vec<_>>()
+                                .into(),
+                            nulls(len + 8, 3),
+                        )
+                        .slice(3, len + 5);
+                        Arc::new(
+                            StructArray::new(
+                                vec![
+                                    Field::new("a", DataType::Int64, true),
+                                    Field::new("b", DataType::Float64, true),
+                                ]
+                                .into(),
+                                vec![Arc::new(ints), Arc::new(floats)],
+                                nulls(len + 5, 7),
+                            )
+                            .slice(5, len),
+                        )
+                    };
+                    Arc::new(
+                        ListArray::new(
+                            
Arc::new(Field::new_list_field(values.data_type().clone(), true)),
+                            offsets,
+                            values,
+                            nulls(rows, 11),
+                        )
+                        .slice(3, rows - 3),
+                    ) as ArrayRef
+                })
+                .collect();
+            let values: Vec<_> = arrays.iter().map(|a| a.as_ref()).collect();
+            let child = if primitive { "primitive" } else { "struct" };
+            let validity = if nullable { "nulls" } else { "no_nulls" };
+            c.bench_function(&format!("list_ranges/{child}/15/{validity}"), 
|b| {
+                b.iter(|| hint::black_box(interleave(&values, 
&indices).unwrap()))
+            });
+        }
+    }
+}
+
+criterion_group!(benches, add_benchmark, bench_list_ranges);
 criterion_main!(benches);

Reply via email to