Skip to content

Commit 3cfe9d7

Browse files
bench: cover dictionary validity in dynamic IN
Compare Float32 dictionary inputs with and without negative zero and an all-valid values bitmap. Keep setup and result checks outside timing. Run with: cargo bench --profile release-nonlto -p datafusion-physical-expr --bench dictionary_float_zero
1 parent 846f2b0 commit 3cfe9d7

2 files changed

Lines changed: 101 additions & 0 deletions

File tree

‎datafusion/physical-expr/Cargo.toml‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,3 +114,7 @@ ignored = ["half"]
114114
[[bench]]
115115
harness = false
116116
name = "equivalence_properties"
117+
118+
[[bench]]
119+
harness = false
120+
name = "dictionary_float_zero"
Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
// Licensed to the Apache Software Foundation (ASF) under one
2+
// or more contributor license agreements. See the NOTICE file
3+
// distributed with this work for additional information
4+
// regarding copyright ownership. The ASF licenses this file
5+
// to you under the Apache License, Version 2.0 (the
6+
// "License"); you may not use this file except in compliance
7+
// with the License. You may obtain a copy of the License at
8+
//
9+
// http://www.apache.org/licenses/LICENSE-2.0
10+
//
11+
// Unless required by applicable law or agreed to in writing,
12+
// software distributed under the License is distributed on an
13+
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14+
// KIND, either express or implied. See the License for the
15+
// specific language governing permissions and limitations
16+
// under the License.
17+
18+
//! Dynamic IN over dictionary floats, with and without signed-zero rewriting.
19+
//! An all-valid values bitmap can add work when computing logical nulls.
20+
//! Physical expressions preserve this exact Arrow layout, which SQL does not
21+
//! specify. Float32 suffices to exercise the bitmap mechanism.
22+
23+
use std::hint::black_box;
24+
use std::sync::Arc;
25+
26+
use arrow::array::{
27+
ArrayRef, AsArray, BooleanArray, DictionaryArray, Float32Array, Int32Array,
28+
};
29+
use arrow::buffer::NullBuffer;
30+
use arrow::datatypes::Int32Type;
31+
use arrow::record_batch::RecordBatch;
32+
use criterion::{Criterion, criterion_group, criterion_main};
33+
use datafusion_common::ScalarValue;
34+
use datafusion_physical_expr::{
35+
PhysicalExpr,
36+
expressions::{InListExpr, col, lit},
37+
};
38+
39+
fn benchmark(c: &mut Criterion) {
40+
const ROWS: usize = 8192;
41+
const CARDINALITY: usize = 16;
42+
const ZERO_KEY: usize = CARDINALITY / 2;
43+
44+
for negative_zero in [false, true] {
45+
for all_valid_bitmap in [false, true] {
46+
let zero = if negative_zero { -0.0_f32 } else { 0.0 };
47+
let values = Float32Array::new(
48+
(0..CARDINALITY)
49+
.map(|i| if i == ZERO_KEY { zero } else { (i + 1) as f32 })
50+
.collect::<Vec<_>>()
51+
.into(),
52+
all_valid_bitmap.then(|| NullBuffer::new_valid(CARDINALITY)),
53+
);
54+
let a: ArrayRef = Arc::new(DictionaryArray::<Int32Type>::new(
55+
Int32Array::from_iter_values((0..ROWS).map(|i| (i % CARDINALITY) as i32)),
56+
Arc::new(values),
57+
));
58+
// Keep the RHS bitmap-free to isolate the LHS representation.
59+
let b: ArrayRef = Arc::new(DictionaryArray::<Int32Type>::new(
60+
Int32Array::from(vec![0; ROWS]),
61+
Arc::new(Float32Array::from(vec![0.0])),
62+
));
63+
let batch = RecordBatch::try_from_iter([("a", a), ("b", b)]).unwrap();
64+
let schema = batch.schema();
65+
// A column forces dynamic evaluation; positive nonzero needles
66+
// cannot match the negative literals, so all four terms are visited.
67+
let expr = InListExpr::try_new(
68+
col("a", &schema).unwrap(),
69+
vec![
70+
col("b", &schema).unwrap(),
71+
lit(ScalarValue::Float32(Some(-1.0))),
72+
lit(ScalarValue::Float32(Some(-2.0))),
73+
lit(ScalarValue::Float32(Some(-3.0))),
74+
],
75+
false,
76+
&schema,
77+
)
78+
.unwrap();
79+
let expected: BooleanArray = (0..ROWS)
80+
.map(|i| Some(i % CARDINALITY == ZERO_KEY))
81+
.collect();
82+
let result = expr.evaluate(&batch).unwrap().into_array(ROWS).unwrap();
83+
assert_eq!(result.as_boolean(), &expected);
84+
85+
let name = format!(
86+
"dictionary_float_zero/negative_zero={negative_zero}/all_valid_bitmap={all_valid_bitmap}"
87+
);
88+
c.bench_function(&name, |b| {
89+
// Reuse the original input; setup and validation are untimed.
90+
b.iter(|| black_box(expr.evaluate(black_box(&batch)).unwrap()))
91+
});
92+
}
93+
}
94+
}
95+
96+
criterion_group!(benches, benchmark);
97+
criterion_main!(benches);

0 commit comments

Comments
 (0)