You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@arrow.apache.org by gi...@apache.org on 2026/10/07 01:37:57 UTC
(arrow-rs) 01/01: bench(arrow-cmp): add dict_cmp benchmark (#11412)
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-11412-8bdf349ae69196d757cd0f6e3df4b9651fbc445d
in repository https://gitbox.apache.org/repos/asf/arrow-rs.git
commit 2b7cab8551afa450f8178c1bec2427399bf03668
Author: RIchard Baah <13...@users.noreply.github.com>
AuthorDate: Wed Oct 7 01:37:32 2026 +0000
bench(arrow-cmp): add dict_cmp benchmark (#11412)
# Which issue does this PR close?
N/A — split out of https://github.com/apache/arrow-rs/pull/11407
# Rationale for this change
`arrow-cmp` has no benchmark coverage for its dictionary comparator
path, so the cost of `make_comparator` on `DictionaryArray`s is not
visible in CI or local perf runs.
# What changes are included in this PR?
- `arrow-cmp/benches/dict_cmp.rs`; new criterion benchmark. Builds
`Dictionary<Int32, Utf8>` arrays with 1M rows at each of 8 cardinalities
(`10, 50, 100, 500, 750, 1000, 4000, 8192`), seeded for reproducibility.
Each iteration constructs the comparator via `make_comparator` and
invokes the returned closure 100 times on pseudo-random index pairs.
# Are there any user-facing changes?
no
---
Cargo.lock | 2 ++
arrow-cmp/Cargo.toml | 6 ++++
arrow-cmp/benches/dict_cmp.rs | 80 +++++++++++++++++++++++++++++++++++++++++++
3 files changed, 88 insertions(+)
diff --git a/Cargo.lock b/Cargo.lock
index 07843eb699..a97ccd4ea5 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -314,7 +314,9 @@ dependencies = [
"arrow-array",
"arrow-buffer",
"arrow-schema",
+ "criterion",
"half",
+ "rand 0.10.3",
]
[[package]]
diff --git a/arrow-cmp/Cargo.toml b/arrow-cmp/Cargo.toml
index 9109f2b9a1..c4b00f32c7 100644
--- a/arrow-cmp/Cargo.toml
+++ b/arrow-cmp/Cargo.toml
@@ -41,6 +41,12 @@ arrow-schema = { workspace = true }
[dev-dependencies]
half = { version = "2.1", default-features = false, features = ["num-traits"] }
+criterion = { workspace = true }
+rand = { version = "0.10", default-features = false, features = ["std", "std_rng", "thread_rng"] }
+
+[[bench]]
+name = "dict_cmp"
+harness = false
[lints]
workspace = true
diff --git a/arrow-cmp/benches/dict_cmp.rs b/arrow-cmp/benches/dict_cmp.rs
new file mode 100644
index 0000000000..52d1f809b8
--- /dev/null
+++ b/arrow-cmp/benches/dict_cmp.rs
@@ -0,0 +1,80 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+use std::hint::black_box;
+use std::sync::Arc;
+
+use arrow_array::types::Int32Type;
+use arrow_array::{DictionaryArray, Int32Array, StringArray};
+use arrow_cmp::make_comparator;
+use arrow_schema::SortOptions;
+use criterion::{BenchmarkId, Criterion, Throughput, criterion_group, criterion_main};
+use rand::rngs::StdRng;
+use rand::{RngExt, SeedableRng};
+
+const BATCH_SIZE: usize = 8_192;
+const CALLS: usize = 100;
+const CARDINALITIES: [usize; 8] = [10, 50, 100, 500, 750, 1_000, 4_000, 8_192];
+const SEED: u64 = 0xC0FFEE;
+
+fn build_dict(rows: usize, cardinality: usize, seed: u64) -> DictionaryArray<Int32Type> {
+ let values: Vec<String> = (0..cardinality).map(|i| format!("v{i:07}")).collect();
+ let values = StringArray::from(values);
+
+ let mut rng = StdRng::seed_from_u64(seed);
+ let keys: Int32Array = (0..rows)
+ .map(|_| rng.random_range(0..cardinality) as i32)
+ .collect();
+
+ DictionaryArray::<Int32Type>::try_new(keys, Arc::new(values)).unwrap()
+}
+
+fn index_pairs(bound: usize, count: usize) -> Vec<(usize, usize)> {
+ let mut rng = StdRng::seed_from_u64(SEED.wrapping_add(0x1234));
+ (0..count)
+ .map(|_| (rng.random_range(0..bound), rng.random_range(0..bound)))
+ .collect()
+}
+
+fn bench_dict_cmp(c: &mut Criterion) {
+ let pairs = index_pairs(BATCH_SIZE, CALLS);
+
+ let mut group = c.benchmark_group("dict_cmp_utf8/100_calls_8k_batch");
+ group.throughput(Throughput::Elements(CALLS as u64));
+ group.sample_size(10);
+
+ for &card in &CARDINALITIES {
+ let left = build_dict(BATCH_SIZE, card, SEED);
+ let right = build_dict(BATCH_SIZE, card, SEED ^ 0xA5A5_A5A5);
+
+ group.bench_with_input(BenchmarkId::from_parameter(card), &card, |b, _| {
+ b.iter(|| {
+ let cmp = make_comparator(&left, &right, SortOptions::default()).unwrap();
+ let mut acc = 0i64;
+ for &(i, j) in &pairs {
+ acc += cmp(i, j) as i64;
+ }
+ black_box(acc)
+ })
+ });
+ }
+
+ group.finish();
+}
+
+criterion_group!(benches, bench_dict_cmp);
+criterion_main!(benches);