#![allow(missing_docs)]
use std::hint::black_box;
use criterion::{BenchmarkId, Criterion, criterion_group, criterion_main};
fn bench_literal_matching(c: &mut Criterion) {
let mut group = c.benchmark_group("literal_pattern");
let haystacks = [
("short", "$ "),
("medium", "user@host:~/projects/rust-expect$ "),
(
"long",
"2024-01-01 12:00:00 [INFO] user@host:~/projects/rust-expect$ command output here",
),
];
for (name, haystack) in haystacks {
group.bench_with_input(BenchmarkId::new("rust_expect", name), haystack, |b, h| {
let pattern = rust_expect::Pattern::literal("$");
b.iter(|| pattern.matches(black_box(h)));
});
group.bench_with_input(BenchmarkId::new("expectrl", name), haystack, |b, h| {
use expectrl::Needle;
let needle: &str = "$";
b.iter(|| needle.check(black_box(h.as_bytes()), false));
});
}
group.finish();
}
fn bench_regex_matching(c: &mut Criterion) {
let mut group = c.benchmark_group("regex_pattern");
let patterns_and_texts = [
("simple", r"\$\s*$", "user@host:~$ "),
("digits", r"\d{3}-\d{4}", "Call 555-1234"),
(
"complex",
r"ERROR:\s+\[([A-Z]+)\]\s+(.+)$",
"ERROR: [AUTH] Failed login",
),
];
for (name, pattern, text) in patterns_and_texts {
group.bench_with_input(BenchmarkId::new("rust_expect", name), &text, |b, t| {
let p = rust_expect::Pattern::regex(pattern).unwrap();
b.iter(|| p.matches(black_box(*t)));
});
group.bench_with_input(BenchmarkId::new("expectrl", name), &text, |b, t| {
use expectrl::Needle;
let re = expectrl::Regex(pattern);
b.iter(|| re.check(black_box(t.as_bytes()), false));
});
}
group.finish();
}
fn bench_buffer_operations(c: &mut Criterion) {
let mut group = c.benchmark_group("buffer_ops");
let sizes = [1024, 4096, 16384];
for size in sizes {
group.bench_with_input(
BenchmarkId::new("rust_expect_append", size),
&size,
|b, &sz| {
let data: Vec<u8> = (0..64).map(|i| (i % 256) as u8).collect();
b.iter(|| {
let mut buffer = rust_expect::expect::RingBuffer::new(sz);
for _ in 0..(sz / 64) {
buffer.append(black_box(&data));
}
buffer
});
},
);
group.bench_with_input(BenchmarkId::new("vec_baseline", size), &size, |b, &sz| {
let data: Vec<u8> = (0..64).map(|i| (i % 256) as u8).collect();
b.iter(|| {
let mut buffer = Vec::with_capacity(sz);
for _ in 0..(sz / 64) {
buffer.extend_from_slice(black_box(&data));
}
buffer
});
});
}
group.bench_function("rust_expect_search", |b| {
let mut buffer = rust_expect::expect::RingBuffer::new(4096);
let data: Vec<u8> = (0..3000).map(|i| (i % 256) as u8).collect();
buffer.append(&data);
buffer.append(b"needle_here");
b.iter(|| buffer.find(black_box(b"needle_here")));
});
group.finish();
}
fn bench_multi_pattern(c: &mut Criterion) {
let mut group = c.benchmark_group("multi_pattern");
let pattern_counts = [2, 5, 10, 20];
let haystack = "user@host:~/project$ command output here";
for count in pattern_counts {
group.bench_with_input(
BenchmarkId::new("rust_expect_set", count),
&count,
|b, &n| {
let mut set = rust_expect::expect::PatternSet::new();
for i in 0..n {
set.add(rust_expect::Pattern::literal(format!("nomatch{i}")));
}
set.add(rust_expect::Pattern::literal("$")); b.iter(|| set.find_match(black_box(haystack)));
},
);
group.bench_with_input(BenchmarkId::new("expectrl_iter", count), &count, |b, &n| {
use expectrl::Needle;
let patterns: Vec<String> = (0..n).map(|i| format!("nomatch{i}")).collect();
let patterns_ref: Vec<&str> =
patterns.iter().map(std::string::String::as_str).collect();
b.iter(|| {
for p in &patterns_ref {
if let Ok(matches) = p.check(black_box(haystack.as_bytes()), false)
&& !matches.is_empty()
{
return Some(*p);
}
}
if let Ok(matches) = "$".check(black_box(haystack.as_bytes()), false)
&& !matches.is_empty()
{
return Some("$");
}
None
});
});
}
group.finish();
}
fn bench_allocation_patterns(c: &mut Criterion) {
let mut group = c.benchmark_group("allocations");
group.bench_function("rust_expect_pattern_create", |b| {
b.iter(|| {
let p1 = rust_expect::Pattern::literal("$");
let p2 = rust_expect::Pattern::regex(r"\w+@\w+").unwrap();
black_box((p1, p2))
});
});
group.bench_function("expectrl_regex_create", |b| {
b.iter(|| {
let re = expectrl::Regex(r"\w+@\w+");
black_box(re)
});
});
group.finish();
}
criterion_group!(
benches,
bench_literal_matching,
bench_regex_matching,
bench_buffer_operations,
bench_multi_pattern,
bench_allocation_patterns,
);
criterion_main!(benches);