use std::path::PathBuf;
use std::time::{Duration, Instant};
use tldr_core::{
enriched_search, enriched_search_with_structure_cache, get_code_structure,
read_structure_cache, write_structure_cache, EnrichedSearchOptions, Language, SearchMode,
};
fn main() {
let root = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("src");
let language = Language::Rust;
let file_count = walkdir::WalkDir::new(&root)
.into_iter()
.filter_map(|e| e.ok())
.filter(|e| e.path().extension().is_some_and(|x| x == "rs"))
.count();
println!("=== Structure Cache Benchmark ===");
println!("Project: crates/tldr-core/src/ ({} .rs files)", file_count);
println!();
let build_start = Instant::now();
let structure = get_code_structure(&root, language, 0, None).unwrap();
let build_time = build_start.elapsed();
let total_defs: usize = structure.files.iter().map(|f| f.definitions.len()).sum();
println!(
"get_code_structure(): {:.2} ms ({} files, {} definitions)",
ms(build_time),
structure.files.len(),
total_defs
);
let cache_path = std::env::temp_dir().join("tldr_structure_cache_bench.json");
let write_start = Instant::now();
write_structure_cache(&structure, &cache_path).unwrap();
let write_time = write_start.elapsed();
let cache_size = std::fs::metadata(&cache_path).unwrap().len();
println!(
"write_structure_cache(): {:.2} ms ({:.0} KB)",
ms(write_time),
cache_size as f64 / 1024.0
);
let read_start = Instant::now();
let lookup = read_structure_cache(&cache_path).unwrap();
let read_time = read_start.elapsed();
println!(
"read_structure_cache(): {:.2} ms ({} files in lookup)",
ms(read_time),
lookup.by_file.len()
);
println!();
let queries: Vec<(&str, &str)> = vec![
("impl\\s+\\w+\\s+for\\s+\\w+", "broad (impl for)"),
("pub\\s+fn", "broad (pub fn)"),
("fn\\s+search", "focused (fn search)"),
("BM25", "literal (BM25)"),
("WarmCallEdge", "rare (WarmCallEdge)"),
];
println!(
"{:<32} {:>12} {:>12} {:>8}",
"Query", "Uncached", "Cached", "Speedup"
);
println!("{}", "-".repeat(68));
for (pattern, label) in &queries {
let options_uncached = EnrichedSearchOptions {
top_k: 10,
include_callgraph: false,
search_mode: SearchMode::Regex(pattern.to_string()),
};
let mut uncached_times = Vec::new();
for _ in 0..5 {
let start = Instant::now();
let _report =
enriched_search(pattern, &root, language, options_uncached.clone()).unwrap();
uncached_times.push(start.elapsed());
}
let uncached_med = median(&mut uncached_times);
let options_cached = EnrichedSearchOptions {
top_k: 10,
include_callgraph: false,
search_mode: SearchMode::Regex(pattern.to_string()),
};
let mut cached_times = Vec::new();
for _ in 0..10 {
let start = Instant::now();
let _report = enriched_search_with_structure_cache(
pattern,
&root,
language,
options_cached.clone(),
&lookup,
)
.unwrap();
cached_times.push(start.elapsed());
}
let cached_med = median(&mut cached_times);
let speedup = ms(uncached_med) / ms(cached_med);
println!(
"{:<32} {:>9.2} ms {:>9.2} ms {:>7.1}x",
label,
ms(uncached_med),
ms(cached_med),
speedup
);
}
println!();
println!("=== Cache Overhead ===");
println!("Structure build: {:.2} ms", ms(build_time));
println!(
"Cache write: {:.2} ms ({:.0} KB)",
ms(write_time),
cache_size as f64 / 1024.0
);
println!("Cache read: {:.2} ms", ms(read_time));
let _ = std::fs::remove_file(&cache_path);
}
fn ms(d: Duration) -> f64 {
d.as_secs_f64() * 1000.0
}
fn median(times: &mut [Duration]) -> Duration {
times.sort();
times[times.len() / 2]
}