use std::path::PathBuf;
use bpaf::Bpaf;
use profile_inspect::analysis::ProfileDiffer;
use profile_inspect::classify::FrameClassifier;
use profile_inspect::output::format_time_us;
use profile_inspect::parser::CpuProfileParser;
#[derive(Debug, Clone, Bpaf)]
#[bpaf(command("diff"))]
pub struct DiffCommand {
#[bpaf(long, fallback(1.0))]
pub min_delta: f64,
#[bpaf(positional("BEFORE"))]
pub before: PathBuf,
#[bpaf(positional("AFTER"))]
pub after: PathBuf,
}
impl DiffCommand {
pub fn run(self) -> Result<(), Box<dyn std::error::Error>> {
let classifier = FrameClassifier::default();
let parser = CpuProfileParser::new(classifier);
let before_profile = parser.parse_file(&self.before)?;
let classifier2 = FrameClassifier::default();
let parser2 = CpuProfileParser::new(classifier2);
let after_profile = parser2.parse_file(&self.after)?;
let differ = ProfileDiffer::new().min_delta_percent(self.min_delta);
let diff = differ.diff(&before_profile, &after_profile);
eprintln!("Profile Comparison");
eprintln!("==================");
eprintln!();
eprintln!("Before: {}", format_time_us(diff.before_total));
eprintln!("After: {}", format_time_us(diff.after_total));
eprintln!("Change: {:+.1}%", diff.overall_delta_percent);
eprintln!();
if !diff.regressions.is_empty() {
eprintln!("Regressions (slower):");
for reg in diff.regressions.iter().take(10) {
eprintln!(
" {} - {:+.1}% ({} -> {})",
reg.name,
reg.delta_percent,
format_time_us(reg.before_time),
format_time_us(reg.after_time)
);
}
eprintln!();
}
if !diff.improvements.is_empty() {
eprintln!("Improvements (faster):");
for imp in diff.improvements.iter().take(10) {
eprintln!(
" {} - {:.1}% ({} -> {})",
imp.name,
imp.delta_percent,
format_time_us(imp.before_time),
format_time_us(imp.after_time)
);
}
}
Ok(())
}
}