//! Criterion benchmark for the filter pipeline.
//!
//! Run with `cargo bench --bench filter_bench`.
use criterion::{black_box, criterion_group, criterion_main, BenchmarkId, Criterion};
use ripgrab::filter::{dsl, FilterSet, MatchOutcome};
mod fixtures;
fn bench_basic_includes(c: &mut Criterion) {
let lines = fixtures::access_log(fixtures::DEFAULT_LINES);
let filter = FilterSet::compile(
&["error|warn|fatal".to_string()],
&["heartbeat".to_string()],
None,
)
.unwrap();
c.bench_function("filter/basic-includes", |b| {
b.iter(|| {
let mut hits = 0;
for line in &lines {
if let MatchOutcome::Plain = filter.apply(black_box(line)) {
hits += 1;
}
}
black_box(hits)
})
});
}
fn bench_dsl_compiled(c: &mut Criterion) {
let lines = fixtures::access_log(fixtures::DEFAULT_LINES);
let compiled = dsl::parse_and_compile("status >= 400").unwrap();
c.bench_function("filter/dsl-compiled", |b| {
b.iter(|| {
let mut ctx = dsl::EvalContext::new();
let mut hits = 0;
for line in &lines {
let status = extract_status(line);
ctx.clear();
ctx.set("status", status);
if dsl::evaluate(&compiled, &ctx) {
hits += 1;
}
}
black_box(hits)
})
});
}
fn bench_dsl_by_line_length(c: &mut Criterion) {
let mut group = c.benchmark_group("filter/dsl-line-length");
for &len in &[128usize, 256, 512, 1024] {
let line = format!("host=api status=503 body={}", "x".repeat(len));
let compiled = dsl::parse_and_compile("status >= 400").unwrap();
group.bench_with_input(BenchmarkId::from_parameter(len), &line, |b, l| {
let mut ctx = dsl::EvalContext::new();
b.iter(|| {
ctx.clear();
ctx.set("status", extract_status(l));
black_box(dsl::evaluate(&compiled, &ctx));
})
});
}
group.finish();
}
fn extract_status(line: &str) -> &str {
line.split_whitespace()
.find_map(|f| f.strip_prefix("status="))
.unwrap_or("0")
}
criterion_group!(benches, bench_basic_includes, bench_dsl_compiled, bench_dsl_by_line_length);
criterion_main!(benches);