From be4f18f314bb72e15d0869d819da62073b7b5583 Mon Sep 17 00:00:00 2001 From: Matthew Kim <38759997+friendlymatthew@users.noreply.github.com> Date: Thu, 26 Mar 2026 16:31:41 -0400 Subject: [PATCH 1/3] tune benchmark --- datafusion/core/benches/parquet_struct_projection.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/datafusion/core/benches/parquet_struct_projection.rs b/datafusion/core/benches/parquet_struct_projection.rs index d6cf86a91c86b..171c120afa06e 100644 --- a/datafusion/core/benches/parquet_struct_projection.rs +++ b/datafusion/core/benches/parquet_struct_projection.rs @@ -41,10 +41,10 @@ use std::sync::Arc; use tempfile::NamedTempFile; use tokio::runtime::Runtime; -const NUM_BATCHES: usize = 64; -const WRITE_RECORD_BATCH_SIZE: usize = 4096; -const ROW_GROUP_ROW_COUNT: usize = 65536; -const EXPECTED_ROW_GROUPS: usize = 4; +const NUM_BATCHES: usize = 4; +const WRITE_RECORD_BATCH_SIZE: usize = 512; +const ROW_GROUP_ROW_COUNT: usize = 1024; +const EXPECTED_ROW_GROUPS: usize = 2; const LARGE_STRING_LEN: usize = 128 * 1024; fn narrow_schema() -> SchemaRef { From d2c8373a1f13dbf7185138f1bc4f457fd2a840dd Mon Sep 17 00:00:00 2001 From: Adrian Garcia Badaracco <1755071+adriangb@users.noreply.github.com> Date: Thu, 26 Mar 2026 20:15:06 -0500 Subject: [PATCH 2/3] make even faster --- .../core/benches/parquet_struct_projection.rs | 33 ++++++++++++------- 1 file changed, 22 insertions(+), 11 deletions(-) diff --git a/datafusion/core/benches/parquet_struct_projection.rs b/datafusion/core/benches/parquet_struct_projection.rs index 171c120afa06e..b0f49dafb002e 100644 --- a/datafusion/core/benches/parquet_struct_projection.rs +++ b/datafusion/core/benches/parquet_struct_projection.rs @@ -37,15 +37,20 @@ use parquet::arrow::ArrowWriter; use parquet::file::properties::{WriterProperties, WriterVersion}; use std::hint::black_box; use std::path::Path; -use std::sync::Arc; +use std::sync::{Arc, OnceLock}; +use std::time::Duration; use tempfile::NamedTempFile; use tokio::runtime::Runtime; -const NUM_BATCHES: usize = 4; -const WRITE_RECORD_BATCH_SIZE: usize = 512; -const ROW_GROUP_ROW_COUNT: usize = 1024; +const NUM_BATCHES: usize = 2; +const WRITE_RECORD_BATCH_SIZE: usize = 256; +const ROW_GROUP_ROW_COUNT: usize = 256; const EXPECTED_ROW_GROUPS: usize = 2; -const LARGE_STRING_LEN: usize = 128 * 1024; +const LARGE_STRING_LEN: usize = 16 * 1024; + +static NARROW_FILE: OnceLock = OnceLock::new(); +static WIDE_FILE: OnceLock = OnceLock::new(); +static NESTED_FILE: OnceLock = OnceLock::new(); fn narrow_schema() -> SchemaRef { let struct_fields = Fields::from(vec![ @@ -201,7 +206,8 @@ fn query(ctx: &SessionContext, rt: &Runtime, sql: &str) { } fn narrow_benchmarks(c: &mut Criterion) { - let temp_file = generate_file(narrow_schema(), narrow_batch, "narrow_struct"); + let temp_file = NARROW_FILE + .get_or_init(|| generate_file(narrow_schema(), narrow_batch, "narrow_struct")); let file_path = temp_file.path().display().to_string(); assert!(Path::new(&file_path).exists(), "path not found"); @@ -209,6 +215,8 @@ fn narrow_benchmarks(c: &mut Criterion) { let ctx = create_context(&rt, &file_path, "t"); let mut group = c.benchmark_group("narrow_struct"); + group.sample_size(10); + group.measurement_time(Duration::from_secs(2)); // baseline: full struct, must decode both leaves group.bench_function("select_struct", |b| { @@ -241,11 +249,11 @@ fn narrow_benchmarks(c: &mut Criterion) { }); group.finish(); - drop(temp_file); } fn wide_benchmarks(c: &mut Criterion) { - let temp_file = generate_file(wide_schema(), wide_batch, "wide_struct"); + let temp_file = + WIDE_FILE.get_or_init(|| generate_file(wide_schema(), wide_batch, "wide_struct")); let file_path = temp_file.path().display().to_string(); assert!(Path::new(&file_path).exists(), "path not found"); @@ -253,6 +261,8 @@ fn wide_benchmarks(c: &mut Criterion) { let ctx = create_context(&rt, &file_path, "t"); let mut group = c.benchmark_group("wide_struct"); + group.sample_size(10); + group.measurement_time(Duration::from_secs(2)); // baseline: full struct, must decode all 5 leaves group.bench_function("select_struct", |b| { @@ -285,7 +295,6 @@ fn wide_benchmarks(c: &mut Criterion) { }); group.finish(); - drop(temp_file); } fn nested_schema() -> SchemaRef { @@ -351,7 +360,8 @@ fn nested_batch(batch_id: usize) -> RecordBatch { } fn nested_benchmarks(c: &mut Criterion) { - let temp_file = generate_file(nested_schema(), nested_batch, "nested_struct"); + let temp_file = NESTED_FILE + .get_or_init(|| generate_file(nested_schema(), nested_batch, "nested_struct")); let file_path = temp_file.path().display().to_string(); assert!(Path::new(&file_path).exists(), "path not found"); @@ -359,6 +369,8 @@ fn nested_benchmarks(c: &mut Criterion) { let ctx = create_context(&rt, &file_path, "t"); let mut group = c.benchmark_group("nested_struct"); + group.sample_size(10); + group.measurement_time(Duration::from_secs(2)); // baseline: full outer struct, decode all 3 leaves group.bench_function("select_struct", |b| { @@ -391,7 +403,6 @@ fn nested_benchmarks(c: &mut Criterion) { }); group.finish(); - drop(temp_file); } criterion_group!( From ec8311c36b4005ef225954ab927d998cb3fdec98 Mon Sep 17 00:00:00 2001 From: Adrian Garcia Badaracco <1755071+adriangb@users.noreply.github.com> Date: Thu, 26 Mar 2026 23:03:43 -0500 Subject: [PATCH 3/3] Revert OnceLock caching and add warm_up_time(1s) to benchmarks File generation is fast (~10ms), so OnceLock is unnecessary. Reduce Criterion warm-up from default 3s to 1s per benchmark for faster runs. Co-Authored-By: Claude Opus 4.6 (1M context) --- .../core/benches/parquet_struct_projection.rs | 21 +++++++++---------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/datafusion/core/benches/parquet_struct_projection.rs b/datafusion/core/benches/parquet_struct_projection.rs index b0f49dafb002e..65b3905da89a0 100644 --- a/datafusion/core/benches/parquet_struct_projection.rs +++ b/datafusion/core/benches/parquet_struct_projection.rs @@ -37,7 +37,7 @@ use parquet::arrow::ArrowWriter; use parquet::file::properties::{WriterProperties, WriterVersion}; use std::hint::black_box; use std::path::Path; -use std::sync::{Arc, OnceLock}; +use std::sync::Arc; use std::time::Duration; use tempfile::NamedTempFile; use tokio::runtime::Runtime; @@ -48,10 +48,6 @@ const ROW_GROUP_ROW_COUNT: usize = 256; const EXPECTED_ROW_GROUPS: usize = 2; const LARGE_STRING_LEN: usize = 16 * 1024; -static NARROW_FILE: OnceLock = OnceLock::new(); -static WIDE_FILE: OnceLock = OnceLock::new(); -static NESTED_FILE: OnceLock = OnceLock::new(); - fn narrow_schema() -> SchemaRef { let struct_fields = Fields::from(vec![ Field::new("large_string", DataType::Utf8, false), @@ -206,8 +202,7 @@ fn query(ctx: &SessionContext, rt: &Runtime, sql: &str) { } fn narrow_benchmarks(c: &mut Criterion) { - let temp_file = NARROW_FILE - .get_or_init(|| generate_file(narrow_schema(), narrow_batch, "narrow_struct")); + let temp_file = generate_file(narrow_schema(), narrow_batch, "narrow_struct"); let file_path = temp_file.path().display().to_string(); assert!(Path::new(&file_path).exists(), "path not found"); @@ -216,6 +211,7 @@ fn narrow_benchmarks(c: &mut Criterion) { let mut group = c.benchmark_group("narrow_struct"); group.sample_size(10); + group.warm_up_time(Duration::from_secs(1)); group.measurement_time(Duration::from_secs(2)); // baseline: full struct, must decode both leaves @@ -249,11 +245,11 @@ fn narrow_benchmarks(c: &mut Criterion) { }); group.finish(); + drop(temp_file); } fn wide_benchmarks(c: &mut Criterion) { - let temp_file = - WIDE_FILE.get_or_init(|| generate_file(wide_schema(), wide_batch, "wide_struct")); + let temp_file = generate_file(wide_schema(), wide_batch, "wide_struct"); let file_path = temp_file.path().display().to_string(); assert!(Path::new(&file_path).exists(), "path not found"); @@ -262,6 +258,7 @@ fn wide_benchmarks(c: &mut Criterion) { let mut group = c.benchmark_group("wide_struct"); group.sample_size(10); + group.warm_up_time(Duration::from_secs(1)); group.measurement_time(Duration::from_secs(2)); // baseline: full struct, must decode all 5 leaves @@ -295,6 +292,7 @@ fn wide_benchmarks(c: &mut Criterion) { }); group.finish(); + drop(temp_file); } fn nested_schema() -> SchemaRef { @@ -360,8 +358,7 @@ fn nested_batch(batch_id: usize) -> RecordBatch { } fn nested_benchmarks(c: &mut Criterion) { - let temp_file = NESTED_FILE - .get_or_init(|| generate_file(nested_schema(), nested_batch, "nested_struct")); + let temp_file = generate_file(nested_schema(), nested_batch, "nested_struct"); let file_path = temp_file.path().display().to_string(); assert!(Path::new(&file_path).exists(), "path not found"); @@ -370,6 +367,7 @@ fn nested_benchmarks(c: &mut Criterion) { let mut group = c.benchmark_group("nested_struct"); group.sample_size(10); + group.warm_up_time(Duration::from_secs(1)); group.measurement_time(Duration::from_secs(2)); // baseline: full outer struct, decode all 3 leaves @@ -403,6 +401,7 @@ fn nested_benchmarks(c: &mut Criterion) { }); group.finish(); + drop(temp_file); } criterion_group!(