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-11768-b90914fecd0ba85a8827f386af3bcc51cce5b162
in repository https://gitbox.apache.org/repos/asf/arrow-rs.git

commit 3db18f75b40921b8abf17daed32999ec58064f7d
Author: Neil Conway <[email protected]>
AuthorDate: Fri Oct 23 05:42:00 2026 +0000

    bench: improve `concat`, `coalesce_kernels` benchmarks (#11768)
    
    # Which issue does this PR close?
    
    - N/A
    
    # Rationale for this change
    
    This PR improves the `concat` and `coalesce_kernels` benchmarks:
    
    * `concat`: Add a case that mixes inline and out-of-line strings (3 to
    19 bytes). Previously, every string in a case had the same length (12,
    20 or 128 bytes).
    * `concat`: Each case concatenated 10 copies of the same 8192-row array,
    so after the first copy the input views were already in cache.
    Real-world data doesn't look like this; each each iteration now
    concatenates the next 10 of 32 arrays with different seeds.
    * `coalesce_kernels`: Add a benchmark case for out-of-line strings that
    don't take the copy-path in the coalescer.
    * `coalesce_kernels`: For `Utf8View`, `Utf8`, and `Dictionary(Int32,
    Utf8)` inputs, the RNG seed was ignored. Fix it to pass the seed to the
    RNG, so we don't generate identical data.
    
    # What changes are included in this PR?
    
    See above.
    
    # Are these changes tested?
    
    Benchmark change only.
    
    # Are there any significant user-facing changes?
    
    No, benchmark change only.
---
 arrow/benches/coalesce_kernels.rs   | 65 ++++++++++++++++++++++++++++++++-----
 arrow/benches/concatenate_kernel.rs | 44 +++++++++++++++++++------
 2 files changed, 90 insertions(+), 19 deletions(-)

diff --git a/arrow/benches/coalesce_kernels.rs 
b/arrow/benches/coalesce_kernels.rs
index d43001a514..9cdd71cdc3 100644
--- a/arrow/benches/coalesce_kernels.rs
+++ b/arrow/benches/coalesce_kernels.rs
@@ -169,6 +169,7 @@ fn add_all_filter_benchmarks(c: &mut Criterion) {
                 num_output_batches: 50,
                 null_density,
                 selectivity,
+                min_string_len: 0,
                 max_string_len: 30,
                 schema: &primitive_schema,
             }
@@ -181,6 +182,7 @@ fn add_all_filter_benchmarks(c: &mut Criterion) {
                 num_output_batches: 50,
                 null_density,
                 selectivity,
+                min_string_len: 0,
                 max_string_len: 30,
                 schema: &single_schema,
             }
@@ -193,11 +195,26 @@ fn add_all_filter_benchmarks(c: &mut Criterion) {
                 num_output_batches: 50,
                 null_density,
                 selectivity,
+                min_string_len: 0,
                 max_string_len: 8,
                 schema: &single_schema,
             }
             .build();
 
+            // Model strings that are all stored out of line, such as UUIDs
+            FilterBenchmarkBuilder {
+                c,
+                name: "single_utf8view (string_len=13..40)",
+                batch_size,
+                num_output_batches: 50,
+                null_density,
+                selectivity,
+                min_string_len: 13,
+                max_string_len: 40,
+                schema: &single_schema,
+            }
+            .build();
+
             FilterBenchmarkBuilder {
                 c,
                 name: "single_binaryview",
@@ -205,6 +222,7 @@ fn add_all_filter_benchmarks(c: &mut Criterion) {
                 num_output_batches: 50,
                 null_density,
                 selectivity,
+                min_string_len: 0,
                 max_string_len: 30,
                 schema: &single_binaryview_schema,
             }
@@ -217,6 +235,7 @@ fn add_all_filter_benchmarks(c: &mut Criterion) {
                 num_output_batches: 50,
                 null_density,
                 selectivity,
+                min_string_len: 0,
                 max_string_len: 8,
                 schema: &single_binaryview_schema,
             }
@@ -229,6 +248,7 @@ fn add_all_filter_benchmarks(c: &mut Criterion) {
                 num_output_batches: 50,
                 null_density,
                 selectivity,
+                min_string_len: 0,
                 max_string_len: 30,
                 schema: &single_utf8_schema,
             }
@@ -241,6 +261,7 @@ fn add_all_filter_benchmarks(c: &mut Criterion) {
                 num_output_batches: 50,
                 null_density,
                 selectivity,
+                min_string_len: 0,
                 max_string_len: 30,
                 schema: &single_binary_schema,
             }
@@ -254,6 +275,7 @@ fn add_all_filter_benchmarks(c: &mut Criterion) {
                 num_output_batches: 20,
                 null_density,
                 selectivity,
+                min_string_len: 0,
                 max_string_len: 20,
                 schema: &mixed_utf8view_schema,
             }
@@ -266,6 +288,7 @@ fn add_all_filter_benchmarks(c: &mut Criterion) {
                 num_output_batches: 20,
                 null_density,
                 selectivity,
+                min_string_len: 0,
                 max_string_len: 8,
                 schema: &mixed_utf8view_schema,
             }
@@ -279,6 +302,7 @@ fn add_all_filter_benchmarks(c: &mut Criterion) {
                 num_output_batches: 20,
                 null_density,
                 selectivity,
+                min_string_len: 0,
                 max_string_len: 128,
                 schema: &mixed_utf8view_schema,
             }
@@ -291,6 +315,7 @@ fn add_all_filter_benchmarks(c: &mut Criterion) {
                 num_output_batches: 20,
                 null_density,
                 selectivity,
+                min_string_len: 0,
                 max_string_len: 20,
                 schema: &mixed_binaryview_schema,
             }
@@ -303,6 +328,7 @@ fn add_all_filter_benchmarks(c: &mut Criterion) {
                 num_output_batches: 20,
                 null_density,
                 selectivity,
+                min_string_len: 0,
                 max_string_len: 8,
                 schema: &mixed_binaryview_schema,
             }
@@ -315,6 +341,7 @@ fn add_all_filter_benchmarks(c: &mut Criterion) {
                 num_output_batches: 20,
                 null_density,
                 selectivity,
+                min_string_len: 0,
                 max_string_len: 128,
                 schema: &mixed_binaryview_schema,
             }
@@ -327,6 +354,7 @@ fn add_all_filter_benchmarks(c: &mut Criterion) {
                 num_output_batches: 20,
                 null_density,
                 selectivity,
+                min_string_len: 0,
                 max_string_len: 30,
                 schema: &mixed_utf8_schema,
             }
@@ -339,6 +367,7 @@ fn add_all_filter_benchmarks(c: &mut Criterion) {
                 num_output_batches: 10,
                 null_density,
                 selectivity,
+                min_string_len: 0,
                 max_string_len: 30,
                 schema: &mixed_dict_schema,
             }
@@ -351,6 +380,7 @@ fn add_all_filter_benchmarks(c: &mut Criterion) {
                 num_output_batches: 25,
                 null_density,
                 selectivity,
+                min_string_len: 0,
                 max_string_len: 30,
                 schema: &single_dictionary_schema,
             }
@@ -363,6 +393,7 @@ fn add_all_filter_benchmarks(c: &mut Criterion) {
                 num_output_batches: 50,
                 null_density,
                 selectivity,
+                min_string_len: 0,
                 max_string_len: 16,
                 schema: &single_fsb16_schema,
             }
@@ -375,6 +406,7 @@ fn add_all_filter_benchmarks(c: &mut Criterion) {
                 num_output_batches: 50,
                 null_density,
                 selectivity,
+                min_string_len: 0,
                 max_string_len: 32,
                 schema: &single_fsb32_schema,
             }
@@ -387,6 +419,7 @@ fn add_all_filter_benchmarks(c: &mut Criterion) {
                 num_output_batches: 50,
                 null_density,
                 selectivity,
+                min_string_len: 0,
                 max_string_len: 0,
                 schema: &single_boolean_schema,
             }
@@ -399,6 +432,7 @@ fn add_all_filter_benchmarks(c: &mut Criterion) {
                 num_output_batches: 25,
                 null_density,
                 selectivity,
+                min_string_len: 0,
                 max_string_len: 0,
                 schema: &single_run_end_schema,
             }
@@ -411,6 +445,7 @@ fn add_all_filter_benchmarks(c: &mut Criterion) {
                 num_output_batches: 50,
                 null_density,
                 selectivity,
+                min_string_len: 0,
                 max_string_len: 0,
                 schema: &single_fsl4_schema,
             }
@@ -423,6 +458,7 @@ fn add_all_filter_benchmarks(c: &mut Criterion) {
                 num_output_batches: 50,
                 null_density,
                 selectivity,
+                min_string_len: 0,
                 max_string_len: 0,
                 schema: &single_list_schema,
             }
@@ -743,6 +779,8 @@ struct FilterBenchmarkBuilder<'a> {
     null_density: f32,
     /// between 0.0 .. 1.0, percent of rows that should be kept by the filter
     selectivity: f32,
+    /// The minimum length of strings in the data stream
+    min_string_len: usize,
     /// The maximum length of strings in the data stream
     ///
     /// For StringViewArray, strings <= 12 bytes are stored inline, longer
@@ -762,6 +800,7 @@ impl FilterBenchmarkBuilder<'_> {
             num_output_batches,
             null_density,
             selectivity,
+            min_string_len,
             max_string_len,
             schema,
         } = self;
@@ -775,6 +814,7 @@ impl FilterBenchmarkBuilder<'_> {
         let data = DataStreamBuilder::new(Arc::clone(schema))
             .with_batch_size(batch_size)
             .with_null_density(null_density)
+            .with_min_string_len(min_string_len)
             .with_max_string_len(max_string_len)
             .build();
 
@@ -1317,6 +1357,7 @@ struct DataStreamBuilder {
     batch_size: usize,
     null_density: f32,
     num_batches: usize,    // number of unique batches to create
+    min_string_len: usize, // minimum length of strings in the data stream
     max_string_len: usize, // maximum length of strings in the data stream
 }
 
@@ -1327,6 +1368,7 @@ impl DataStreamBuilder {
             batch_size: 8192,
             null_density: 0.0,
             num_batches: 10,
+            min_string_len: 0,
             max_string_len: 30,
         }
     }
@@ -1344,6 +1386,11 @@ impl DataStreamBuilder {
         self
     }
 
+    fn with_min_string_len(mut self, min_string_len: usize) -> Self {
+        self.min_string_len = min_string_len;
+        self
+    }
+
     fn with_max_string_len(mut self, max_string_len: usize) -> Self {
         self.max_string_len = max_string_len;
         self
@@ -1368,6 +1415,7 @@ impl DataStreamBuilder {
             batch_size,
             null_density: _,
             num_batches: _,
+            min_string_len: _,
             max_string_len: _,
         } = self;
 
@@ -1408,23 +1456,22 @@ impl DataStreamBuilder {
             >(
                 self.batch_size,
                 self.null_density,
-                0,
+                self.min_string_len,
                 self.max_string_len,
                 b"",
                 seed,
             )),
-            DataType::Utf8View => {
-                Arc::new(create_string_view_array_with_max_len(
-                    self.batch_size,
-                    self.null_density,
-                    self.max_string_len,
-                )) // TODO seed
-            }
+            DataType::Utf8View => 
Arc::new(create_string_view_array_with_len_range_and_seed(
+                self.batch_size,
+                self.null_density,
+                self.min_string_len..self.max_string_len,
+                seed,
+            )),
             DataType::BinaryView => Arc::new(BinaryViewArray::from_iter(
                 create_binary_array_with_len_range_and_prefix_and_seed::<i32>(
                     self.batch_size,
                     self.null_density,
-                    0,
+                    self.min_string_len,
                     self.max_string_len,
                     b"",
                     seed,
diff --git a/arrow/benches/concatenate_kernel.rs 
b/arrow/benches/concatenate_kernel.rs
index 7e4f90f354..fbc2e87c72 100644
--- a/arrow/benches/concatenate_kernel.rs
+++ b/arrow/benches/concatenate_kernel.rs
@@ -144,17 +144,41 @@ fn add_benchmark(c: &mut Criterion) {
         });
     }
 
-    // String view arrays
+    // String view arrays. Each iteration concatenates the next 10 of
+    // `NUM_VIEW_INPUTS` arrays, so the CPU can't learn the order of inline and
+    // out-of-line strings, or of nulls, in the input.
+    const NUM_VIEW_INPUTS: usize = 32;
     for null_density in [0.0, 0.2] {
-        // Any strings less than 12 characters are stored as prefix only, so 
specially
-        // benchmark cases that have different mixes of lengths.
-        for (name, str_len) in [("all_inline", 12), ("", 20), ("", 128)] {
-            let array = create_string_view_array_with_len(8192, null_density, 
str_len, false);
-            let arrays = (0..10).map(|_| &array as &dyn 
Array).collect::<Vec<_>>();
-            let id = format!(
-                "concat utf8_view {name} max_str_len={str_len} 
null_density={null_density}"
-            );
-            c.bench_function(&id, |b| b.iter(|| bench_concat_arrays(&arrays)));
+        // Strings of 12 bytes or fewer are stored inline in the view, so the
+        // cases cover all inline, all out of line, and a mix of the two.
+        for (name, lengths) in [
+            ("all_inline str_len=12", 12..13),
+            ("str_len=20", 20..21),
+            ("str_len=128", 128..129),
+            ("mixed str_len=3..20", 3..20),
+        ] {
+            let inputs = (0..NUM_VIEW_INPUTS as u64)
+                .map(|seed| {
+                    create_string_view_array_with_len_range_and_seed(
+                        8192,
+                        null_density,
+                        lengths.clone(),
+                        seed,
+                    )
+                })
+                .collect::<Vec<_>>();
+            let mut next = inputs.iter().cycle();
+            let id = format!("concat utf8_view {name} 
null_density={null_density}");
+            c.bench_function(&id, |b| {
+                b.iter(|| {
+                    let arrays = next
+                        .by_ref()
+                        .take(10)
+                        .map(|a| a as &dyn Array)
+                        .collect::<Vec<_>>();
+                    bench_concat_arrays(&arrays)
+                })
+            });
         }
     }
 

Reply via email to