99 lines
3.2 KiB
Rust
Raw Normal View History

//! Benchmarks for the chase subsystem.
//!
//! These are designed to retroactively validate the semi-naive and Skolem
//! work and catch future regressions. Each workload runs several chase
//! variants over the same input so relative numbers are meaningful.
use criterion::{BatchSize, Criterion, criterion_group, criterion_main};
use query_engine::chase::rule::RuleBuilder;
use query_engine::chase::{ChaseConfig, ChaseVariant, Rule, chase_with_config};
use query_engine::{Atom, Instance, Term};
fn chain_edges(n: usize) -> Instance {
(0..n)
.map(|i| {
Atom::new(
"Edge",
vec![
Term::constant(format!("n{}", i)),
Term::constant(format!("n{}", i + 1)),
],
)
})
.collect()
}
fn transitive_closure_rules() -> Vec<Rule> {
let edge_to_path = RuleBuilder::new()
.when("Edge", vec![Term::var("X"), Term::var("Y")])
.then("Path", vec![Term::var("X"), Term::var("Y")])
.build();
let extend_path = RuleBuilder::new()
.when("Path", vec![Term::var("X"), Term::var("Y")])
.when("Edge", vec![Term::var("Y"), Term::var("Z")])
.then("Path", vec![Term::var("X"), Term::var("Z")])
.build();
vec![edge_to_path, extend_path]
}
fn bench_transitive_closure(c: &mut Criterion) {
let mut group = c.benchmark_group("transitive_closure_chain_20");
let instance = chain_edges(20);
let rules = transitive_closure_rules();
for (label, variant, semi) in [
("restricted_naive", ChaseVariant::Restricted, false),
("restricted_semi_naive", ChaseVariant::Restricted, true),
("standard_naive", ChaseVariant::Standard, false),
("standard_semi_naive", ChaseVariant::Standard, true),
] {
let config = ChaseConfig {
variant,
semi_naive: semi,
..Default::default()
};
group.bench_function(label, |b| {
b.iter_batched(
|| instance.clone(),
|inst| chase_with_config(inst, &rules, config.clone()),
BatchSize::SmallInput,
);
});
}
group.finish();
}
fn bench_existentials(c: &mut Criterion) {
let mut group = c.benchmark_group("existentials_50_people");
let instance: Instance = (0..50)
.map(|i| Atom::new("Person", vec![Term::constant(format!("p{}", i))]))
.collect();
let rule = RuleBuilder::new()
.when("Person", vec![Term::var("X")])
.then("HasId", vec![Term::var("X"), Term::var("Y")])
.build();
let rules = vec![rule];
for (label, variant) in [
("restricted", ChaseVariant::Restricted),
("skolem", ChaseVariant::Skolem),
] {
let config = ChaseConfig {
variant,
semi_naive: false,
..Default::default()
};
group.bench_function(label, |b| {
b.iter_batched(
|| instance.clone(),
|inst| chase_with_config(inst, &rules, config.clone()),
BatchSize::SmallInput,
);
});
}
group.finish();
}
criterion_group!(benches, bench_transitive_closure, bench_existentials);
criterion_main!(benches);