profile-inspect 0.1.2

Analyze V8 CPU and heap profiles from Node.js/Chrome DevTools
Documentation
use std::path::PathBuf;

use bpaf::Bpaf;

use profile_inspect::analysis::CallerCalleeAnalyzer;
use profile_inspect::classify::FrameClassifier;
use profile_inspect::output::format_time_us;
use profile_inspect::parser::CpuProfileParser;

/// Explain a specific function (show callers/callees)
#[derive(Debug, Clone, Bpaf)]
#[bpaf(command("explain"))]
pub struct ExplainCommand {
    /// Function name to explain
    #[bpaf(long, argument("NAME"))]
    pub function: String,

    /// Path to profile
    #[bpaf(positional("INPUT"))]
    pub input: PathBuf,
}

impl ExplainCommand {
    pub fn run(self) -> Result<(), Box<dyn std::error::Error>> {
        let classifier = FrameClassifier::default();
        let parser = CpuProfileParser::new(classifier);
        let profile = parser.parse_file(&self.input)?;

        // Find the function
        let frame = CallerCalleeAnalyzer::find_frame_by_name(&profile, &self.function)
            .ok_or_else(|| format!("Function not found: {}", self.function))?;

        let analyzer = CallerCalleeAnalyzer::new();
        let analysis = analyzer
            .analyze(&profile, frame.id)
            .ok_or("Failed to analyze function")?;

        eprintln!("Function Analysis: {}", analysis.target_name);
        eprintln!("Location: {}", analysis.target_location);
        eprintln!();
        eprintln!("Self time:  {}", format_time_us(analysis.target_self_time));
        eprintln!("Total time: {}", format_time_us(analysis.target_total_time));
        eprintln!();

        if !analysis.callers.is_empty() {
            eprintln!("Top Callers:");
            for caller in analysis.callers.iter().take(10) {
                eprintln!(
                    "  {} - {} ({} calls)",
                    caller.name,
                    format_time_us(caller.time),
                    caller.call_count
                );
            }
            eprintln!();
        }

        if !analysis.callees.is_empty() {
            eprintln!("Top Callees:");
            for callee in analysis.callees.iter().take(10) {
                eprintln!(
                    "  {} - {} ({} calls)",
                    callee.name,
                    format_time_us(callee.self_time),
                    callee.call_count
                );
            }
        }

        Ok(())
    }
}