//! `ripgrab bench` — micro-benchmark the filter pipeline without Criterion.
//!
//! This is a debugging aid for profiling, not a rigorous benchmark. Use
//! `cargo bench` (see `benches/`) for real numbers.
use std::time::Instant;
use anyhow::Result;
use tokio::fs::File;
use tokio::io::{AsyncBufReadExt, BufReader};
use crate::cli::args::BenchArgs;
use crate::filter::FilterSet;
pub async fn run(args: BenchArgs) -> Result<()> {
let lines = load_lines(&args.input).await?;
let filter = FilterSet::compile(&["error|warn|fatal".to_string()], &[], None)?;
let start = Instant::now();
let mut hits = 0u64;
for _ in 0..args.iterations {
for line in &lines {
if matches!(filter.apply(line), crate::filter::MatchOutcome::Plain) {
hits += 1;
}
}
}
let elapsed = start.elapsed();
let total = (args.iterations as u64) * lines.len() as u64;
let per_sec = (total as f64) / elapsed.as_secs_f64();
println!(
"bench: {} lines across {} iterations = {} total in {:.2?} ({:.0} lines/s, {} hits)",
lines.len(),
args.iterations,
total,
elapsed,
per_sec,
hits,
);
Ok(())
}
async fn load_lines(path: &std::path::Path) -> Result<Vec<String>> {
let file = File::open(path).await?;
let mut reader = BufReader::new(file);
let mut buf = String::new();
let mut lines = Vec::new();
loop {
buf.clear();
let read = reader.read_line(&mut buf).await?;
if read == 0 {
break;
}
while buf.ends_with('\n') || buf.ends_with('\r') {
buf.pop();
}
lines.push(buf.clone());
}
Ok(lines)
}