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

Jefffrey pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/arrow-rs.git


The following commit(s) were added to refs/heads/main by this push:
     new 0be3a5f636 bench(parquet): add wide-schema writer benchmark with 
repeated batches (#10878)
0be3a5f636 is described below

commit 0be3a5f6363fd2a473d9fda5bd7f8303fe7f08d9
Author: Adrian Garcia Badaracco <[email protected]>
AuthorDate: Thu Aug 27 10:24:27 2026 -0500

    bench(parquet): add wide-schema writer benchmark with repeated batches 
(#10878)
    
    # Which issue does this PR close?
    
    - Contributes to #9722.
    
    # Rationale for this change
    
    `parquet/benches/writer_overhead.rs` writes a single one-row batch per
    file. That
    measures column writer construction, allocation and metadata assembly,
    and it
    measures them well, but it never reaches the work a wide schema repeats
    on every
    batch: the per-column setup inside `ColumnWriter::write_batch`, and the
    per-mini-batch and per-page checks below it.
    
    With one `write` call per file, a change to that per-batch path is
    invisible here.
    
    # What changes are included in this PR?
    
    Adds `writer_overhead/{1000,5000}_cols/repeated_batches`. It holds the
    number of
    column writers fixed and writes 32 batches of 32 rows into a single row
    group,
    reusing the same wide schema and the same per-column `WriterProperties`
    as the
    existing cases, so the only difference from `writer_overhead/{n}_cols`
    is the
    number of `write` calls.
    
    The 10,000 column case is deliberately left out of the new benchmark so
    that one
    iteration stays well under a second. On the machine used here an
    iteration is
    roughly 13 ms at 1,000 columns and 90 ms at 5,000 columns.
    
    # Are these changes tested?
    
    No, this is a benchmark-only change. Run it with:
    
        cargo bench -p parquet --bench writer_overhead
    
    # Are there any user-facing changes?
    
    No.
    
    # AI usage
    
    This PR was written with Claude Code and reviewed by a human.
    
    ---------
    
    Co-authored-by: Claude Opus 5 <[email protected]>
---
 parquet/benches/writer_overhead.rs | 58 ++++++++++++++++++++++++++++++++++----
 1 file changed, 53 insertions(+), 5 deletions(-)

diff --git a/parquet/benches/writer_overhead.rs 
b/parquet/benches/writer_overhead.rs
index fc4f616eb2..e0bbe7b551 100644
--- a/parquet/benches/writer_overhead.rs
+++ b/parquet/benches/writer_overhead.rs
@@ -19,9 +19,9 @@
 //!
 //! These benchmarks measure the structural cost of creating, writing, and
 //! closing a parquet file with many columns while keeping actual data
-//! encoding negligible (1 row per column). This isolates overhead such as
-//! `WriterProperties` per-column lookups, `GenericColumnWriter` allocation,
-//! and metadata assembly.
+//! encoding negligible. This isolates overhead such as `WriterProperties`
+//! per-column lookups, `GenericColumnWriter` allocation, metadata assembly,
+//! and the per-column work repeated by every `write` call.
 
 use criterion::{Criterion, criterion_group, criterion_main};
 use std::hint::black_box;
@@ -45,8 +45,12 @@ fn make_wide_schema(num_columns: usize) -> SchemaRef {
 }
 
 fn make_single_row_batch(schema: &SchemaRef) -> RecordBatch {
+    make_batch(schema, 1)
+}
+
+fn make_batch(schema: &SchemaRef, num_rows: usize) -> RecordBatch {
     let columns: Vec<Arc<dyn arrow_array::Array>> = (0..schema.fields().len())
-        .map(|_| Arc::new(Float32Array::from(vec![0.0f32])) as _)
+        .map(|_| Arc::new(Float32Array::from(vec![0.0f32; num_rows])) as _)
         .collect();
     RecordBatch::try_new(schema.clone(), columns).unwrap()
 }
@@ -64,6 +68,12 @@ fn make_per_column_props(schema: &SchemaRef) -> 
WriterProperties {
     builder.build()
 }
 
+/// Measures the per-column-writer overhead of a wide schema, by writing a
+/// single one-row batch per file.
+///
+/// Writing one batch per file means this is dominated by column writer
+/// construction and metadata assembly. [`bench_writer_repeated_batches`]
+/// isolates the work that repeats on every batch instead.
 fn bench_writer_overhead(c: &mut Criterion) {
     for &num_cols in COLUMN_COUNTS {
         let schema = make_wide_schema(num_cols);
@@ -82,5 +92,43 @@ fn bench_writer_overhead(c: &mut Criterion) {
     }
 }
 
-criterion_group!(benches, bench_writer_overhead);
+/// Measures the per-`write` (rather than per-column-writer) overhead of a wide
+/// schema, by writing many small batches into a single row group.
+///
+/// This keeps the number of column writers fixed and increases the number of
+/// `write` calls, isolating the work that repeats on every batch.
+fn bench_writer_repeated_batches(c: &mut Criterion) {
+    // Number of batches written per file, and the number of rows in each.
+    const BATCH_COUNT: usize = 32;
+    const BATCH_ROWS: usize = 32;
+
+    // Kept below the widest case in `COLUMN_COUNTS` so that one iteration 
stays
+    // well under a second.
+    for &num_cols in &[1_000, 5_000] {
+        let schema = make_wide_schema(num_cols);
+        let batch = make_batch(&schema, BATCH_ROWS);
+        let props = make_per_column_props(&schema);
+
+        c.bench_function(
+            &format!("writer_overhead/{num_cols}_cols/repeated_batches"),
+            |b| {
+                b.iter(|| {
+                    let mut writer =
+                        ArrowWriter::try_new(Empty::default(), schema.clone(), 
Some(props.clone()))
+                            .unwrap();
+                    for _ in 0..BATCH_COUNT {
+                        writer.write(black_box(&batch)).unwrap();
+                    }
+                    black_box(writer.close()).unwrap();
+                });
+            },
+        );
+    }
+}
+
+criterion_group!(
+    benches,
+    bench_writer_overhead,
+    bench_writer_repeated_batches
+);
 criterion_main!(benches);

Reply via email to