From 0d79d950f35daf08b46c54fc37f7165cedce60d5 Mon Sep 17 00:00:00 2001 From: RIchard Baah Date: Thu, 1 Oct 2026 23:48:38 +0200 Subject: [PATCH 1/2] bench: introduce create_hash benchmarks --- datafusion/common/Cargo.toml | 4 + datafusion/common/benches/create_hashes.rs | 300 +++++++++++++++++++++ 2 files changed, 304 insertions(+) create mode 100644 datafusion/common/benches/create_hashes.rs diff --git a/datafusion/common/Cargo.toml b/datafusion/common/Cargo.toml index 9ee199fe82f28..8d053b5297361 100644 --- a/datafusion/common/Cargo.toml +++ b/datafusion/common/Cargo.toml @@ -52,6 +52,10 @@ recursive_protection = ["dep:recursive"] parquet = ["dep:parquet"] sql = ["sqlparser"] +[[bench]] +harness = false +name = "create_hashes" + [[bench]] harness = false name = "with_hashes" diff --git a/datafusion/common/benches/create_hashes.rs b/datafusion/common/benches/create_hashes.rs new file mode 100644 index 0000000000000..c0e5ab7b8e242 --- /dev/null +++ b/datafusion/common/benches/create_hashes.rs @@ -0,0 +1,300 @@ +// 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 arrow::array::{ + ArrayRef, ArrowPrimitiveType, DictionaryArray, FixedSizeListArray, Int32Array, + Int64Array, ListArray, ListViewArray, MapArray, NullArray, PrimitiveArray, RunArray, + StringArray, StringViewArray, StructArray, UnionArray, +}; +use arrow::buffer::{OffsetBuffer, ScalarBuffer}; +use arrow::datatypes::{DataType, Field, Fields, Int32Type, Int64Type, UnionFields}; +use criterion::{Criterion, criterion_group, criterion_main}; +use datafusion_common::hash_utils::{RandomState, create_hashes}; +use rand::Rng; +use rand::SeedableRng; +use rand::distr::{Distribution, StandardUniform}; +use rand::prelude::StdRng; +use std::sync::Arc; + +const BATCH_SIZE: usize = 8192; +const ELEMENTS_PER_ROW: usize = 5; + +fn make_rng() -> StdRng { + StdRng::seed_from_u64(42) +} + +fn bench_create_hashes(c: &mut Criterion, name: &str, array: &ArrayRef) { + let state = RandomState::default(); + let mut hashes = vec![0u64; BATCH_SIZE]; + c.bench_function(name, |b| { + b.iter(|| { + create_hashes(std::slice::from_ref(array), &state, &mut hashes).unwrap(); + }) + }); +} + +fn primitive_array() -> ArrayRef +where + T: ArrowPrimitiveType, + StandardUniform: Distribution, +{ + let mut rng = make_rng(); + Arc::new( + (0..BATCH_SIZE) + .map(|_| Some(rng.random::())) + .collect::>(), + ) +} + +fn null_array() -> ArrayRef { + Arc::new(NullArray::new(BATCH_SIZE)) +} + +fn utf8_array() -> ArrayRef { + let mut rng = make_rng(); + Arc::new(StringArray::from_iter_values((0..BATCH_SIZE).map(|_| { + let len = rng.random_range(1usize..=32); + (0..len).map(|_| rng.random::()).collect::() + }))) +} + +fn string_view_array() -> ArrayRef { + let mut rng = make_rng(); + Arc::new(StringViewArray::from_iter_values((0..BATCH_SIZE).map( + |_| { + let len = rng.random_range(1usize..=32); + (0..len).map(|_| rng.random::()).collect::() + }, + ))) +} + +fn dictionary_array() -> ArrayRef { + let pool: Vec = (0..100).map(|i| format!("value_{i}")).collect(); + let mut rng = make_rng(); + Arc::new(DictionaryArray::::from_iter( + (0..BATCH_SIZE).map(|_| Some(pool[rng.random_range(0..pool.len())].as_str())), + )) +} + +fn struct_array() -> ArrayRef { + Arc::new(StructArray::new( + Fields::from(vec![ + Field::new("a", DataType::Int64, false), + Field::new("b", DataType::Int32, false), + ]), + vec![ + primitive_array::(), + primitive_array::(), + ], + None, + )) +} + +fn list_array() -> ArrayRef { + let mut rng = make_rng(); + let total = BATCH_SIZE * ELEMENTS_PER_ROW; + let values: Int64Array = (0..total).map(|_| Some(rng.random::())).collect(); + let offsets: Vec = (0..=BATCH_SIZE) + .map(|i| (i * ELEMENTS_PER_ROW) as i32) + .collect(); + Arc::new(ListArray::new( + Arc::new(Field::new("item", DataType::Int64, true)), + OffsetBuffer::new(ScalarBuffer::from(offsets)), + Arc::new(values), + None, + )) +} + +fn list_view_array() -> ArrayRef { + let mut rng = make_rng(); + let total = BATCH_SIZE * ELEMENTS_PER_ROW; + let values: Int64Array = (0..total).map(|_| Some(rng.random::())).collect(); + let offsets: ScalarBuffer = (0..BATCH_SIZE) + .map(|i| (i * ELEMENTS_PER_ROW) as i32) + .collect(); + let sizes: ScalarBuffer = + (0..BATCH_SIZE).map(|_| ELEMENTS_PER_ROW as i32).collect(); + Arc::new(ListViewArray::new( + Arc::new(Field::new("item", DataType::Int64, true)), + offsets, + sizes, + Arc::new(values), + None, + )) +} + +fn map_array() -> ArrayRef { + let mut rng = make_rng(); + let total = BATCH_SIZE * ELEMENTS_PER_ROW; + let keys: Int32Array = (0..total).map(|_| Some(rng.random::())).collect(); + let vals: Int64Array = (0..total).map(|_| Some(rng.random::())).collect(); + let offsets: Vec = (0..=BATCH_SIZE) + .map(|i| (i * ELEMENTS_PER_ROW) as i32) + .collect(); + let entries = StructArray::try_new( + Fields::from(vec![ + Field::new("keys", DataType::Int32, false), + Field::new("values", DataType::Int64, true), + ]), + vec![Arc::new(keys), Arc::new(vals)], + None, + ) + .unwrap(); + Arc::new(MapArray::new( + Arc::new(Field::new( + "entries", + DataType::Struct(Fields::from(vec![ + Field::new("keys", DataType::Int32, false), + Field::new("values", DataType::Int64, true), + ])), + false, + )), + OffsetBuffer::new(ScalarBuffer::from(offsets)), + entries, + None, + false, + )) +} + +fn fixed_size_list_array() -> ArrayRef { + let list_size = 4i32; + Arc::new(FixedSizeListArray::new( + Arc::new(Field::new("item", DataType::Int64, true)), + list_size, + primitive_array::(), + None, + )) +} + +fn union_array() -> ArrayRef { + let mut rng = make_rng(); + let num_types: i8 = 3; + let type_ids: Vec = (0..BATCH_SIZE) + .map(|_| rng.random_range(0..num_types)) + .collect(); + let (fields, children): (Vec<_>, Vec<_>) = (0..num_types) + .map(|i| { + ( + ( + i, + Arc::new(Field::new(format!("f{i}"), DataType::Int64, true)), + ), + primitive_array::(), + ) + }) + .unzip(); + Arc::new( + UnionArray::try_new( + UnionFields::from_iter(fields), + ScalarBuffer::from(type_ids), + None, + children, + ) + .unwrap(), + ) +} + +fn run_array() -> ArrayRef { + let mut rng = make_rng(); + let mut run_ends = Vec::new(); + let mut values = Vec::new(); + let mut pos = 0; + while pos < BATCH_SIZE { + let run_len = rng.random_range(1..=50).min(BATCH_SIZE - pos); + pos += run_len; + run_ends.push(pos as i32); + values.push(Some(rng.random::())); + } + Arc::new( + RunArray::try_new( + &Int32Array::from(run_ends), + &values.into_iter().collect::(), + ) + .unwrap(), + ) +} + +fn bench_create_hashes_multi(c: &mut Criterion, name: &str, arrays: &[ArrayRef]) { + let state = RandomState::default(); + let mut hashes = vec![0u64; BATCH_SIZE]; + c.bench_function(name, |b| { + b.iter(|| { + create_hashes(arrays, &state, &mut hashes).unwrap(); + }) + }); +} + +fn criterion_benchmark(c: &mut Criterion) { + bench_create_hashes(c, "create_hashes: null", &null_array()); + bench_create_hashes(c, "create_hashes: int64", &primitive_array::()); + bench_create_hashes(c, "create_hashes: utf8", &utf8_array()); + bench_create_hashes(c, "create_hashes: utf8_view", &string_view_array()); + bench_create_hashes(c, "create_hashes: dictionary", &dictionary_array()); + bench_create_hashes(c, "create_hashes: struct", &struct_array()); + bench_create_hashes(c, "create_hashes: list", &list_array()); + bench_create_hashes(c, "create_hashes: list_view", &list_view_array()); + bench_create_hashes(c, "create_hashes: map", &map_array()); + bench_create_hashes( + c, + "create_hashes: fixed_size_list", + &fixed_size_list_array(), + ); + bench_create_hashes(c, "create_hashes: union", &union_array()); + bench_create_hashes(c, "create_hashes: run_end_encoded", &run_array()); + + let int64 = primitive_array::(); + let utf8 = utf8_array(); + let utf8_view = string_view_array(); + let dict = dictionary_array(); + bench_create_hashes_multi( + c, + "create_hashes: 2 columns int64", + &[int64.clone(), int64.clone()], + ); + bench_create_hashes_multi( + c, + "create_hashes: 3 columns mixed", + &[int64.clone(), utf8.clone(), utf8_view.clone()], + ); + bench_create_hashes_multi( + c, + "create_hashes: 5 columns mixed", + &[ + int64.clone(), + utf8.clone(), + utf8_view.clone(), + dict.clone(), + int64.clone(), + ], + ); + bench_create_hashes_multi( + c, + "create_hashes: 7 columns mixed", + &[ + int64.clone(), + utf8.clone(), + utf8_view.clone(), + dict.clone(), + int64.clone(), + utf8.clone(), + dict, + ], + ); +} + +criterion_group!(benches, criterion_benchmark); +criterion_main!(benches); From 31115fbaa944e7c4f07d7af47b81a8e6b734f309 Mon Sep 17 00:00:00 2001 From: RIchard Baah Date: Wed, 7 Oct 2026 12:05:55 -0400 Subject: [PATCH 2/2] add 3 new benchmarks to with_hashes, remove duplicate file --- datafusion/common/Cargo.toml | 4 - datafusion/common/benches/create_hashes.rs | 300 --------------------- datafusion/common/benches/with_hashes.rs | 68 ++++- 3 files changed, 64 insertions(+), 308 deletions(-) delete mode 100644 datafusion/common/benches/create_hashes.rs diff --git a/datafusion/common/Cargo.toml b/datafusion/common/Cargo.toml index 8d053b5297361..9ee199fe82f28 100644 --- a/datafusion/common/Cargo.toml +++ b/datafusion/common/Cargo.toml @@ -52,10 +52,6 @@ recursive_protection = ["dep:recursive"] parquet = ["dep:parquet"] sql = ["sqlparser"] -[[bench]] -harness = false -name = "create_hashes" - [[bench]] harness = false name = "with_hashes" diff --git a/datafusion/common/benches/create_hashes.rs b/datafusion/common/benches/create_hashes.rs deleted file mode 100644 index c0e5ab7b8e242..0000000000000 --- a/datafusion/common/benches/create_hashes.rs +++ /dev/null @@ -1,300 +0,0 @@ -// 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 arrow::array::{ - ArrayRef, ArrowPrimitiveType, DictionaryArray, FixedSizeListArray, Int32Array, - Int64Array, ListArray, ListViewArray, MapArray, NullArray, PrimitiveArray, RunArray, - StringArray, StringViewArray, StructArray, UnionArray, -}; -use arrow::buffer::{OffsetBuffer, ScalarBuffer}; -use arrow::datatypes::{DataType, Field, Fields, Int32Type, Int64Type, UnionFields}; -use criterion::{Criterion, criterion_group, criterion_main}; -use datafusion_common::hash_utils::{RandomState, create_hashes}; -use rand::Rng; -use rand::SeedableRng; -use rand::distr::{Distribution, StandardUniform}; -use rand::prelude::StdRng; -use std::sync::Arc; - -const BATCH_SIZE: usize = 8192; -const ELEMENTS_PER_ROW: usize = 5; - -fn make_rng() -> StdRng { - StdRng::seed_from_u64(42) -} - -fn bench_create_hashes(c: &mut Criterion, name: &str, array: &ArrayRef) { - let state = RandomState::default(); - let mut hashes = vec![0u64; BATCH_SIZE]; - c.bench_function(name, |b| { - b.iter(|| { - create_hashes(std::slice::from_ref(array), &state, &mut hashes).unwrap(); - }) - }); -} - -fn primitive_array() -> ArrayRef -where - T: ArrowPrimitiveType, - StandardUniform: Distribution, -{ - let mut rng = make_rng(); - Arc::new( - (0..BATCH_SIZE) - .map(|_| Some(rng.random::())) - .collect::>(), - ) -} - -fn null_array() -> ArrayRef { - Arc::new(NullArray::new(BATCH_SIZE)) -} - -fn utf8_array() -> ArrayRef { - let mut rng = make_rng(); - Arc::new(StringArray::from_iter_values((0..BATCH_SIZE).map(|_| { - let len = rng.random_range(1usize..=32); - (0..len).map(|_| rng.random::()).collect::() - }))) -} - -fn string_view_array() -> ArrayRef { - let mut rng = make_rng(); - Arc::new(StringViewArray::from_iter_values((0..BATCH_SIZE).map( - |_| { - let len = rng.random_range(1usize..=32); - (0..len).map(|_| rng.random::()).collect::() - }, - ))) -} - -fn dictionary_array() -> ArrayRef { - let pool: Vec = (0..100).map(|i| format!("value_{i}")).collect(); - let mut rng = make_rng(); - Arc::new(DictionaryArray::::from_iter( - (0..BATCH_SIZE).map(|_| Some(pool[rng.random_range(0..pool.len())].as_str())), - )) -} - -fn struct_array() -> ArrayRef { - Arc::new(StructArray::new( - Fields::from(vec![ - Field::new("a", DataType::Int64, false), - Field::new("b", DataType::Int32, false), - ]), - vec![ - primitive_array::(), - primitive_array::(), - ], - None, - )) -} - -fn list_array() -> ArrayRef { - let mut rng = make_rng(); - let total = BATCH_SIZE * ELEMENTS_PER_ROW; - let values: Int64Array = (0..total).map(|_| Some(rng.random::())).collect(); - let offsets: Vec = (0..=BATCH_SIZE) - .map(|i| (i * ELEMENTS_PER_ROW) as i32) - .collect(); - Arc::new(ListArray::new( - Arc::new(Field::new("item", DataType::Int64, true)), - OffsetBuffer::new(ScalarBuffer::from(offsets)), - Arc::new(values), - None, - )) -} - -fn list_view_array() -> ArrayRef { - let mut rng = make_rng(); - let total = BATCH_SIZE * ELEMENTS_PER_ROW; - let values: Int64Array = (0..total).map(|_| Some(rng.random::())).collect(); - let offsets: ScalarBuffer = (0..BATCH_SIZE) - .map(|i| (i * ELEMENTS_PER_ROW) as i32) - .collect(); - let sizes: ScalarBuffer = - (0..BATCH_SIZE).map(|_| ELEMENTS_PER_ROW as i32).collect(); - Arc::new(ListViewArray::new( - Arc::new(Field::new("item", DataType::Int64, true)), - offsets, - sizes, - Arc::new(values), - None, - )) -} - -fn map_array() -> ArrayRef { - let mut rng = make_rng(); - let total = BATCH_SIZE * ELEMENTS_PER_ROW; - let keys: Int32Array = (0..total).map(|_| Some(rng.random::())).collect(); - let vals: Int64Array = (0..total).map(|_| Some(rng.random::())).collect(); - let offsets: Vec = (0..=BATCH_SIZE) - .map(|i| (i * ELEMENTS_PER_ROW) as i32) - .collect(); - let entries = StructArray::try_new( - Fields::from(vec![ - Field::new("keys", DataType::Int32, false), - Field::new("values", DataType::Int64, true), - ]), - vec![Arc::new(keys), Arc::new(vals)], - None, - ) - .unwrap(); - Arc::new(MapArray::new( - Arc::new(Field::new( - "entries", - DataType::Struct(Fields::from(vec![ - Field::new("keys", DataType::Int32, false), - Field::new("values", DataType::Int64, true), - ])), - false, - )), - OffsetBuffer::new(ScalarBuffer::from(offsets)), - entries, - None, - false, - )) -} - -fn fixed_size_list_array() -> ArrayRef { - let list_size = 4i32; - Arc::new(FixedSizeListArray::new( - Arc::new(Field::new("item", DataType::Int64, true)), - list_size, - primitive_array::(), - None, - )) -} - -fn union_array() -> ArrayRef { - let mut rng = make_rng(); - let num_types: i8 = 3; - let type_ids: Vec = (0..BATCH_SIZE) - .map(|_| rng.random_range(0..num_types)) - .collect(); - let (fields, children): (Vec<_>, Vec<_>) = (0..num_types) - .map(|i| { - ( - ( - i, - Arc::new(Field::new(format!("f{i}"), DataType::Int64, true)), - ), - primitive_array::(), - ) - }) - .unzip(); - Arc::new( - UnionArray::try_new( - UnionFields::from_iter(fields), - ScalarBuffer::from(type_ids), - None, - children, - ) - .unwrap(), - ) -} - -fn run_array() -> ArrayRef { - let mut rng = make_rng(); - let mut run_ends = Vec::new(); - let mut values = Vec::new(); - let mut pos = 0; - while pos < BATCH_SIZE { - let run_len = rng.random_range(1..=50).min(BATCH_SIZE - pos); - pos += run_len; - run_ends.push(pos as i32); - values.push(Some(rng.random::())); - } - Arc::new( - RunArray::try_new( - &Int32Array::from(run_ends), - &values.into_iter().collect::(), - ) - .unwrap(), - ) -} - -fn bench_create_hashes_multi(c: &mut Criterion, name: &str, arrays: &[ArrayRef]) { - let state = RandomState::default(); - let mut hashes = vec![0u64; BATCH_SIZE]; - c.bench_function(name, |b| { - b.iter(|| { - create_hashes(arrays, &state, &mut hashes).unwrap(); - }) - }); -} - -fn criterion_benchmark(c: &mut Criterion) { - bench_create_hashes(c, "create_hashes: null", &null_array()); - bench_create_hashes(c, "create_hashes: int64", &primitive_array::()); - bench_create_hashes(c, "create_hashes: utf8", &utf8_array()); - bench_create_hashes(c, "create_hashes: utf8_view", &string_view_array()); - bench_create_hashes(c, "create_hashes: dictionary", &dictionary_array()); - bench_create_hashes(c, "create_hashes: struct", &struct_array()); - bench_create_hashes(c, "create_hashes: list", &list_array()); - bench_create_hashes(c, "create_hashes: list_view", &list_view_array()); - bench_create_hashes(c, "create_hashes: map", &map_array()); - bench_create_hashes( - c, - "create_hashes: fixed_size_list", - &fixed_size_list_array(), - ); - bench_create_hashes(c, "create_hashes: union", &union_array()); - bench_create_hashes(c, "create_hashes: run_end_encoded", &run_array()); - - let int64 = primitive_array::(); - let utf8 = utf8_array(); - let utf8_view = string_view_array(); - let dict = dictionary_array(); - bench_create_hashes_multi( - c, - "create_hashes: 2 columns int64", - &[int64.clone(), int64.clone()], - ); - bench_create_hashes_multi( - c, - "create_hashes: 3 columns mixed", - &[int64.clone(), utf8.clone(), utf8_view.clone()], - ); - bench_create_hashes_multi( - c, - "create_hashes: 5 columns mixed", - &[ - int64.clone(), - utf8.clone(), - utf8_view.clone(), - dict.clone(), - int64.clone(), - ], - ); - bench_create_hashes_multi( - c, - "create_hashes: 7 columns mixed", - &[ - int64.clone(), - utf8.clone(), - utf8_view.clone(), - dict.clone(), - int64.clone(), - utf8.clone(), - dict, - ], - ); -} - -criterion_group!(benches, criterion_benchmark); -criterion_main!(benches); diff --git a/datafusion/common/benches/with_hashes.rs b/datafusion/common/benches/with_hashes.rs index 0e9c53c896a5e..30e7e6682c272 100644 --- a/datafusion/common/benches/with_hashes.rs +++ b/datafusion/common/benches/with_hashes.rs @@ -18,9 +18,10 @@ //! Benchmarks for `with_hashes` function use arrow::array::{ - Array, ArrayRef, ArrowPrimitiveType, DictionaryArray, GenericStringArray, Int32Array, - Int64Array, ListArray, MapArray, NullBufferBuilder, OffsetSizeTrait, PrimitiveArray, - RunArray, StringViewArray, StructArray, UnionArray, make_array, + Array, ArrayRef, ArrowPrimitiveType, DictionaryArray, FixedSizeListArray, + GenericStringArray, Int32Array, Int64Array, ListArray, ListViewArray, MapArray, + NullArray, NullBufferBuilder, OffsetSizeTrait, PrimitiveArray, RunArray, + StringViewArray, StructArray, UnionArray, make_array, }; use arrow::buffer::{NullBuffer, OffsetBuffer, ScalarBuffer}; use arrow::datatypes::{ @@ -109,6 +110,21 @@ fn criterion_benchmark(c: &mut Criterion) { array: create_run_array::(BATCH_SIZE), supports_nulls: true, }, + BenchData { + name: "null", + array: Arc::new(NullArray::new(BATCH_SIZE)), + supports_nulls: false, + }, + BenchData { + name: "list_view_array", + array: list_view_array(BATCH_SIZE), + supports_nulls: true, + }, + BenchData { + name: "fixed_size_list_array", + array: fixed_size_list_array(BATCH_SIZE), + supports_nulls: true, + }, ]; for BenchData { @@ -565,5 +581,49 @@ where ) } -criterion_group!(benches, criterion_benchmark, sliced_array_benchmark); +fn list_view_array(num_rows: usize) -> ArrayRef { + let elements_per_row = 5; + let values = primitive_array::(num_rows * elements_per_row); + let offsets: ScalarBuffer = (0..num_rows) + .map(|i| (i * elements_per_row) as i32) + .collect(); + let sizes: ScalarBuffer = + (0..num_rows).map(|_| elements_per_row as i32).collect(); + Arc::new(ListViewArray::new( + Arc::new(Field::new("item", DataType::Int64, true)), + offsets, + sizes, + values, + None, + )) +} + +fn fixed_size_list_array(num_rows: usize) -> ArrayRef { + let list_size = 4; + Arc::new(FixedSizeListArray::new( + Arc::new(Field::new("item", DataType::Int64, true)), + list_size as i32, + primitive_array::(num_rows * list_size), + None, + )) +} + +/// Heterogeneous key columns +fn mixed_columns_benchmark(c: &mut Criterion) { + let pool = StringPool::new(100, 64); + let int64 = primitive_array::(BATCH_SIZE); + let utf8 = pool.string_array::(BATCH_SIZE); + let utf8_view = pool.string_view_array(BATCH_SIZE); + let arrays = vec![int64, utf8, utf8_view]; + c.bench_function("mixed: 3 columns (int64, utf8, utf8_view)", |b| { + do_hash_test(b, &arrays) + }); +} + +criterion_group!( + benches, + criterion_benchmark, + sliced_array_benchmark, + mixed_columns_benchmark +); criterion_main!(benches);