use akar_common::types::PhysicalTypeID;
use akar_common::vector::{DataChunk, ValueVector};
use akar_processor::physical_operator::{PhysicalAggregate, PhysicalOperatorExec};
use criterion::{Criterion, criterion_group, criterion_main};
use std::hint::black_box;
fn make_i64_chunk(values: &[i64]) -> DataChunk {
let n = values.len();
let mut v = ValueVector::new(PhysicalTypeID::Int64, n);
v.resize(n);
for (i, &val) in values.iter().enumerate() {
v.set_i64(i, val);
}
DataChunk::from_legacy(vec![v])
}
fn make_grouped_chunk(keys: &[i64], values: &[i64]) -> DataChunk {
let n = keys.len();
let mut c0 = ValueVector::new(PhysicalTypeID::Int64, n);
c0.resize(n);
let mut c1 = ValueVector::new(PhysicalTypeID::Int64, n);
c1.resize(n);
for i in 0..n {
c0.set_i64(i, keys[i]);
c1.set_i64(i, values[i]);
}
DataChunk::from_legacy(vec![c0, c1])
}
fn make_multi_key_chunk(key_a: &[i64], key_b: &[i64], values: &[i64]) -> DataChunk {
let n = key_a.len();
let mut c0 = ValueVector::new(PhysicalTypeID::Int64, n);
c0.resize(n);
let mut c1 = ValueVector::new(PhysicalTypeID::Int64, n);
c1.resize(n);
let mut c2 = ValueVector::new(PhysicalTypeID::Int64, n);
c2.resize(n);
for i in 0..n {
c0.set_i64(i, key_a[i]);
c1.set_i64(i, key_b[i]);
c2.set_i64(i, values[i]);
}
DataChunk::from_legacy(vec![c0, c1, c2])
}
fn bench_count_100(c: &mut Criterion) {
let agg = PhysicalAggregate {
group_by_cols: vec![],
aggregate_functions: vec!["COUNT".into()],
};
let chunk = make_i64_chunk(&(0..100).collect::<Vec<i64>>());
c.bench_function("aggregate/count_100", |b| {
b.iter(|| {
black_box(agg.execute(black_box(vec![chunk.clone()])).unwrap());
})
});
}
fn bench_count_10k(c: &mut Criterion) {
let agg = PhysicalAggregate {
group_by_cols: vec![],
aggregate_functions: vec!["COUNT".into()],
};
let chunk = make_i64_chunk(&(0..10_000).collect::<Vec<i64>>());
c.bench_function("aggregate/count_10k", |b| {
b.iter(|| {
black_box(agg.execute(black_box(vec![chunk.clone()])).unwrap());
})
});
}
fn bench_sum_10k(c: &mut Criterion) {
let agg = PhysicalAggregate {
group_by_cols: vec![],
aggregate_functions: vec!["SUM".into()],
};
let chunk = make_i64_chunk(&(0..10_000).collect::<Vec<i64>>());
c.bench_function("aggregate/sum_10k", |b| {
b.iter(|| {
black_box(agg.execute(black_box(vec![chunk.clone()])).unwrap());
})
});
}
fn bench_avg_10k(c: &mut Criterion) {
let agg = PhysicalAggregate {
group_by_cols: vec![],
aggregate_functions: vec!["AVG".into()],
};
let chunk = make_i64_chunk(&(0..10_000).collect::<Vec<i64>>());
c.bench_function("aggregate/avg_10k", |b| {
b.iter(|| {
black_box(agg.execute(black_box(vec![chunk.clone()])).unwrap());
})
});
}
fn bench_multi_agg_10k(c: &mut Criterion) {
let agg = PhysicalAggregate {
group_by_cols: vec![],
aggregate_functions: vec!["COUNT".into(), "SUM".into(), "AVG".into(), "MIN".into(), "MAX".into()],
};
let chunk = make_i64_chunk(&(0..10_000).collect::<Vec<i64>>());
c.bench_function("aggregate/multi_func_10k", |b| {
b.iter(|| {
black_box(agg.execute(black_box(vec![chunk.clone()])).unwrap());
})
});
}
fn bench_group_by_few(c: &mut Criterion) {
let agg = PhysicalAggregate {
group_by_cols: vec![0],
aggregate_functions: vec!["COUNT".into(), "SUM".into()],
};
let keys: Vec<i64> = (0..10_000).map(|i| (i % 10) as i64).collect();
let vals: Vec<i64> = (0..10_000).collect();
let chunk = make_grouped_chunk(&keys, &vals);
c.bench_function("aggregate/group_by_10_groups_10k", |b| {
b.iter(|| {
black_box(agg.execute(black_box(vec![chunk.clone()])).unwrap());
})
});
}
fn bench_group_by_many(c: &mut Criterion) {
let agg = PhysicalAggregate {
group_by_cols: vec![0],
aggregate_functions: vec!["COUNT".into()],
};
let keys: Vec<i64> = (0..10_000).map(|i| (i % 1000) as i64).collect();
let vals: Vec<i64> = (0..10_000).collect();
let chunk = make_grouped_chunk(&keys, &vals);
c.bench_function("aggregate/group_by_1k_groups_10k", |b| {
b.iter(|| {
black_box(agg.execute(black_box(vec![chunk.clone()])).unwrap());
})
});
}
fn bench_group_by_multi_key(c: &mut Criterion) {
let agg = PhysicalAggregate {
group_by_cols: vec![0, 1],
aggregate_functions: vec!["COUNT".into()],
};
let key_a: Vec<i64> = (0..10_000).map(|i| (i % 10) as i64).collect();
let key_b: Vec<i64> = (0..10_000).map(|i| ((i / 10) % 10) as i64).collect();
let vals: Vec<i64> = (0..10_000).collect();
let chunk = make_multi_key_chunk(&key_a, &key_b, &vals);
c.bench_function("aggregate/multi_key_group_by_10k", |b| {
b.iter(|| {
black_box(agg.execute(black_box(vec![chunk.clone()])).unwrap());
})
});
}
fn bench_group_by_string_key(c: &mut Criterion) {
let agg = PhysicalAggregate {
group_by_cols: vec![0],
aggregate_functions: vec!["COUNT".into()],
};
let n = 10_000;
let mut c0 = ValueVector::new(PhysicalTypeID::String, n);
c0.resize(n);
let mut c1 = ValueVector::new(PhysicalTypeID::Int64, n);
c1.resize(n);
let labels = [
"alpha", "beta", "gamma", "delta", "epsilon", "zeta", "eta", "theta", "iota", "kappa",
];
for i in 0..n {
let label = labels[i % 10];
let bytes = label.as_bytes();
let offset = i * 16;
c0.data_mut()[offset] = bytes.len() as u8;
c0.data_mut()[offset + 1..offset + 1 + bytes.len()].copy_from_slice(bytes);
c0.set_null(i, false);
c1.set_i64(i, i as i64);
}
let chunk = DataChunk::from_legacy(vec![c0, c1]);
c.bench_function("aggregate/group_by_string_key_10k", |b| {
b.iter(|| {
black_box(agg.execute(black_box(vec![chunk.clone()])).unwrap());
})
});
}
criterion_group!(
benches,
bench_count_100,
bench_count_10k,
bench_sum_10k,
bench_avg_10k,
bench_multi_agg_10k,
bench_group_by_few,
bench_group_by_many,
bench_group_by_multi_key,
bench_group_by_string_key,
);
criterion_main!(benches);