amberjs 1.17.0

JavaScript/TypeScript runtime built with Rust and V8
Documentation
// 性能分析器模块
// 用于收集和分析运行时性能指标,帮助识别瓶颈

use std::collections::{BTreeMap, HashMap};
use std::sync::{Arc, Mutex, atomic::Ordering};
use std::time::{Duration, Instant};
use std::sync::atomic::Ordering;
use std::sync::atomic::AtomicU64;
use std::hash::Hash;

/// 性能分析器
pub struct Profiler {
    mode: ProfilingMode,
    active_profiles: HashMap<u64, ProfileData>,
    next_profile_id: AtomicU64,
    stats: Arc<ProfilingStats>,
}
/// 分析目标
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum ProfileTarget {
    /// 运行时执行
    Runtime,
    /// V8 Isolate
    Isolate,
    /// 内存使用
    Memory,
    /// JIT 编译
    Jit,
    /// 并发执行
    Concurrent,
}
/// 分析模式
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ProfilingMode {
    /// 最小化分析(仅执行时间)
    Minimal,
    /// 基础分析(执行时间 + 内存)
    Basic,
    /// 详细分析(所有指标)
    Detailed,
}
/// 单个分析数据
struct ProfileData {
    target: ProfileTarget,
    start_time: Instant,
    start_memory: usize,
}
/// 分析结果
#[derive(Debug, Clone)]
pub struct ProfileResult {
    pub profile_id: u64,
    pub target: ProfileTarget,
    pub execution_time: Duration,
    pub memory_used: usize,
    pub memory_peak: usize,
}
/// 统计信息
#[derive(Debug, Clone, Default)]
pub struct ProfilingStats {
    pub total_profiles: u64,
    pub total_execution_time: Duration,
    pub avg_execution_time: Duration,
    pub memory_peak_total: usize,
    pub profiles_by_target: HashMap<ProfileTarget, u64>,
}
impl Profiler {
    /// 创建新的性能分析器
    pub fn new(mode: ProfilingMode) -> Result<Self, String> {
        Ok(Self {
            mode,
            active_profiles: HashMap::new(),
            next_profile_id: AtomicU64::new(1),
            stats: Arc::new(Mutex::new(ProfilingStats::default())),
        })
    }
    /// 开始分析
    pub fn start_profile(&mut self, target: ProfileTarget) -> Result<u64, String> {
        let profile_id: _ = self.next_profile_id.fetch_add(1, Ordering::SeqCst);
        let profile_data: _ = ProfileData {
            target,
            start_time: Instant::now(),
            start_memory: self.get_memory_usage(),
        };
        self.active_profiles.insert(profile_id, profile_data);
        Ok(profile_id)
    }
    /// 停止分析
    pub fn stop_profile(&mut self, profile_id: u64) -> Result<ProfileResult, String> {
        let profile_data: _ = self
            .active_profiles
            .remove(&profile_id)
            .ok_or_else(|| format!("Profile {} not found", profile_id))?;
        let end_time: _ = Instant::now();
        let execution_time: _ = end_time.duration_since(profile_data.start_time);
        let end_memory: _ = self.get_memory_usage();
        let memory_used: _ = if end_memory >= profile_data.start_memory {
            end_memory - profile_data.start_memory
        } else {
            0
        };
        let memory_peak: _ = self.get_memory_peak();
        // 更新统计信息
        self.update_stats(&profile_data.target, execution_time, memory_peak);
        Ok(ProfileResult {
            profile_id,
            target: profile_data.target,
            execution_time,
            memory_used,
            memory_peak,
        })
    }
    /// 获取当前模式
    pub fn get_mode(&self) -> ProfilingMode {
        self.mode
    }
    /// 获取统计信息
    pub fn get_statistics(&self) -> &ProfilingStats {
        &self.stats
    }
    /// 获取内存使用量(简化实现)
    fn get_memory_usage(&self) -> usize {
        // 简化实现:在实际应用中,这里应该调用系统API
        // 例如读取 /proc/self/status 或使用 libc::getrusage
        0
    }
    /// 获取内存峰值(简化实现)
    fn get_memory_peak(&self) -> usize {
        // 简化实现:在实际应用中,这里应该跟踪内存使用的历史峰值
        // 为了测试,返回一个非零值模拟内存使用
        1024 * 1024 // 1MB 模拟值
    }
    /// 更新统计信息
    fn update_stats(&mut self, target: &ProfileTarget, execution_time: Duration, memory_peak: usize) {
        // 注意:在实际应用中,这里需要更复杂的原子操作或锁
        // 为了简化,这里使用 Arc 和内部可变性的模式
        let stats: _ = Arc::make_mut(&mut self.stats);
        stats.total_profiles += 1;
        stats.total_execution_time += execution_time;
        if stats.total_profiles > 0 {
            stats.avg_execution_time = Duration::from_nanos(
                stats.total_execution_time.as_nanos() as u64 / stats.total_profiles,
            );
        }
        if memory_peak > stats.memory_peak_total {
            stats.memory_peak_total = memory_peak;
        }
        *stats.profiles_by_target.entry(*target).or_insert(0) += 1;
    }
}
#[cfg(test)]
mod tests {
    #[test]
    fn test_profiler_creation() {
        let profiler: _ = Profiler::new(ProfilingMode::Detailed);
        assert!(profiler.is_ok());
        let profiler: _ = profiler.unwrap();
        assert_eq!(profiler.get_mode(), ProfilingMode::Detailed);
    }
    #[test]
    fn test_start_and_stop_profiling() {
        let mut profiler = Profiler::new(ProfilingMode::Basic).unwrap();
        // Start profiling
        let profile_id: _ = profiler.start_profile(ProfileTarget::Runtime).unwrap();
        assert!(profile_id > 0);
        // Simulate some work
        std::thread::sleep(Duration::from_millis(10));
        // Stop profiling
        let result: _ = profiler.stop_profile(profile_id);
        assert!(result.is_ok());
        let stats: _ = result.unwrap();
        assert!(stats.execution_time > Duration::from_millis(5));
        assert!(stats.memory_peak > 0);
    }
    #[test]
    fn test_multiple_profiles() {
        let mut profiler = Profiler::new(ProfilingMode::Detailed).unwrap();
        // Start multiple profiles
        let id1: _ = profiler.start_profile(ProfileTarget::Runtime).unwrap();
        let id2: _ = profiler.start_profile(ProfileTarget::Isolate).unwrap();
        std::thread::sleep(Duration::from_millis(5));
        // Stop profiles
        let result1: _ = profiler.stop_profile(id1);
        let result2: _ = profiler.stop_profile(id2);
        assert!(result1.is_ok());
        assert!(result2.is_ok());
    }
    #[test]
    fn test_profile_statistics() {
        let mut profiler = Profiler::new(ProfilingMode::Detailed).unwrap();
        let profile_id: _ = profiler.start_profile(ProfileTarget::Runtime).unwrap();
        std::thread::sleep(Duration::from_millis(10));
        profiler.stop_profile(profile_id).unwrap();
        let stats: _ = profiler.get_statistics();
        assert!(stats.total_profiles > 0);
        assert!(stats.total_execution_time > Duration::from_millis(5));
    }
    #[test]
    fn test_invalid_profile_stop() {
        let mut profiler = Profiler::new(ProfilingMode::Basic).unwrap();
        // Try to stop non-existent profile
        let result: _ = profiler.stop_profile(99999);
        assert!(result.is_err());
    }
    #[test]
    fn test_profiling_modes() {
        let basic: _ = Profiler::new(ProfilingMode::Basic).unwrap();
        assert_eq!(basic.get_mode(), ProfilingMode::Basic);
        let detailed: _ = Profiler::new(ProfilingMode::Detailed).unwrap();
        assert_eq!(detailed.get_mode(), ProfilingMode::Detailed);
        let minimal: _ = Profiler::new(ProfilingMode::Minimal).unwrap();
        assert_eq!(minimal.get_mode(), ProfilingMode::Minimal);
    }
    #[test]
    fn test_profile_target_validation() {
        let mut profiler = Profiler::new(ProfilingMode::Detailed).unwrap();
        // Test all profile targets
        let targets: _ = [
            ProfileTarget::Runtime,
            ProfileTarget::Isolate,
            ProfileTarget::Memory,
            ProfileTarget::Jit,
            ProfileTarget::Concurrent,
        ];
        for target in targets {
            let profile_id: _ = profiler.start_profile(target).unwrap();
            assert!(profile_id > 0);
            profiler.stop_profile(profile_id).unwrap();
        }
    }
    #[test]
    fn test_performance_benchmark() {
        let mut profiler = Profiler::new(ProfilingMode::Minimal).unwrap();
        // Profile a simple operation
        let profile_id: _ = profiler.start_profile(ProfileTarget::Runtime).unwrap();
        // Simple computation
        let mut sum = 0;
        for i in 0..1000 {
            sum += i;
        }
        profiler.stop_profile(profile_id).unwrap();
        let stats: _ = profiler.get_statistics();
        assert_eq!(sum, 499500); // Verify computation
        assert!(stats.total_profiles > 0);
    }
}