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-11416-2b7cab8551afa450f8178c1bec2427399bf03668 in repository https://gitbox.apache.org/repos/asf/arrow-rs.git
commit 29ec1c09fa6c8454848b596f95eafcf36662fc87 Author: Kosta Tarasov <[email protected]> AuthorDate: Wed Oct 7 01:51:42 2026 +0000 Add Variant integer-to-decimal and float-to-decimal benchmarks (#11416) # Which issue does this PR close? - Relates to #10795 and #11309. - Adds Variant benchmark coverage for #11302 and the integer conversion fix tracked in #11309. # Rationale for this change The existing `variant_get` benchmarks do not cover integer or floating-point conversion to decimals. These cases provide a baseline for measuring changes to precision validation and scaling behavior. # What changes are included in this PR? Add 16 cases covering successful safe/strict conversions, scaling, Decimal256 output, precision overflow, and non-finite floating-point inputs. Fixtures contain 8,192 unshredded Variant rows with approximately 10% nulls and a fixed RNG seed. They reuse the existing benchmark helper, with fixture construction outside timing. Float precision-overflow cases run before and after #11302, although their outputs differ: the fix replaces out-of-precision values with nulls. # Are these changes tested? This PR adds benchmarks only. All 16 cases were smoke-tested and measured against #11302 and its base. No library behavior changes or additional unit tests are included. # Are there any significant user-facing changes? No. # AI usage Developed with assistance from OpenAI Codex for implementation, validation, and this description. --- parquet-variant-compute/benches/variant_kernels.rs | 147 +++++++++++++++++++++ 1 file changed, 147 insertions(+) diff --git a/parquet-variant-compute/benches/variant_kernels.rs b/parquet-variant-compute/benches/variant_kernels.rs index 0d35d68901..95bd73e766 100644 --- a/parquet-variant-compute/benches/variant_kernels.rs +++ b/parquet-variant-compute/benches/variant_kernels.rs @@ -19,6 +19,7 @@ use arrow::array::{ Array, ArrayRef, BinaryViewArray, BinaryViewBuilder, Int32Array, StringArray, StructArray, }; use arrow::buffer::Buffer; +use arrow::compute::CastOptions; use arrow_schema::{DataType, Field, FieldRef, Fields}; use chrono::{DateTime, NaiveDate, NaiveDateTime, NaiveTime}; use criterion::{BatchSize, Criterion, criterion_group, criterion_main}; @@ -520,6 +521,150 @@ pub fn variant_get_binary_from_string_bench(c: &mut Criterion) { ); } +pub fn variant_get_decimal_from_int_bench(c: &mut Criterion) { + let int32 = |rng: &mut StdRng| Variant::Int32(rng.random_range(-1_000_000..1_000_000)); + let int64 = |rng: &mut StdRng| Variant::Int64(rng.random_range(-1_000_000..1_000_000)); + bench_variant_get_decimal( + c, + "int32_to_decimal32(9,0)_valid", + int32, + DataType::Decimal32(9, 0), + &[true, false], + ); + bench_variant_get_decimal( + c, + "int64_to_decimal128(38,2)_scale_up", + int64, + DataType::Decimal128(38, 2), + &[true, false], + ); + bench_variant_get_decimal( + c, + "int64_to_decimal256(76,-1)_scale_down", + int64, + DataType::Decimal256(76, -1), + &[true], + ); + bench_variant_get_decimal( + c, + "int64_to_decimal32(9,-20)_all_zero", + int64, + DataType::Decimal32(9, -20), + &[true], + ); + + let wide = |rng: &mut StdRng| Variant::Int64(rng.random_range(5_000_000_000..5_000_100_000)); + bench_variant_get_decimal( + c, + "int64_to_decimal32(9,-1)_scale_before_narrowing", + wide, + DataType::Decimal32(9, -1), + &[true], + ); + let overflow = |rng: &mut StdRng| Variant::Int32(rng.random_range(100_000_000..1_000_000_000)); + bench_variant_get_decimal( + c, + "int32_to_decimal32(8,0)_precision_overflow", + overflow, + DataType::Decimal32(8, 0), + &[true], + ); +} + +pub fn variant_get_decimal_from_float_bench(c: &mut Criterion) { + let float = |rng: &mut StdRng| Variant::Float(rng.random_range(-9999.0..9999.0)); + let double = |rng: &mut StdRng| Variant::Double(rng.random_range(-9999.0..9999.0)); + bench_variant_get_decimal( + c, + "float_to_decimal32(7,2)_valid", + float, + DataType::Decimal32(7, 2), + &[true, false], + ); + bench_variant_get_decimal( + c, + "double_to_decimal128(20,3)_valid", + double, + DataType::Decimal128(20, 3), + &[true, false], + ); + bench_variant_get_decimal( + c, + "double_to_decimal256(40,-2)_scale_down", + double, + DataType::Decimal256(40, -2), + &[true], + ); + + // Include direct and rounding-induced precision overflow for both source types. + // Before #11302 these return out-of-precision values instead of nulls. Keep + // the fixture usable on both revisions so the cost of the fix can be measured. + let samples = [1000.0, -1000.0, 999.75, -999.75]; + bench_variant_get_decimal( + c, + "float_to_decimal64(3,0)_precision_overflow", + |rng| Variant::Float(samples[rng.random_range(0..samples.len())] as f32), + DataType::Decimal64(3, 0), + &[true], + ); + bench_variant_get_decimal( + c, + "double_to_decimal64(3,0)_precision_overflow", + |rng| Variant::Double(samples[rng.random_range(0..samples.len())]), + DataType::Decimal64(3, 0), + &[true], + ); + + let samples = [f64::NAN, f64::INFINITY, f64::NEG_INFINITY]; + bench_variant_get_decimal( + c, + "double_to_decimal128(20,3)_non_finite", + |rng| Variant::Double(samples[rng.random_range(0..samples.len())]), + DataType::Decimal128(20, 3), + &[true], + ); +} + +fn bench_variant_get_decimal( + c: &mut Criterion, + name: &str, + value: impl Fn(&mut StdRng) -> Variant<'static, 'static>, + target: DataType, + modes: &[bool], +) { + for &safe in modes { + let options = GetOptions::new() + .with_as_type(Some(Arc::new(Field::new( + "typed_value", + target.clone(), + true, + )))) + .with_cast_options(CastOptions { + safe, + ..Default::default() + }); + let mode = if safe { "safe" } else { "strict" }; + bench_variant_get( + c, + &format!("variant_get_decimal_{name}_8192_{mode}"), + |rng, array_size| { + // Unshredded input exercises Variant's scalar conversion. Keep + // the requested numeric type and make every tenth row null. + let mut builder = VariantArrayBuilder::new(array_size); + for i in 0..array_size { + if i % 10 == 0 { + builder.append_null(); + } else { + builder.append_variant(value(rng)); + } + } + builder.build() + }, + options, + ); + } +} + criterion_group!( benches, variant_get_bench, @@ -543,6 +688,8 @@ criterion_group!( variant_get_utf8_from_list_bench, variant_get_utf8_from_map_in_list_bench, variant_get_binary_from_string_bench, + variant_get_decimal_from_int_bench, + variant_get_decimal_from_float_bench, ); criterion_main!(benches);
