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,
Isolate,
Memory,
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 {
0
}
fn get_memory_peak(&self) -> usize {
1024 * 1024 }
fn update_stats(&mut self, target: &ProfileTarget, execution_time: Duration, memory_peak: usize) {
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();
let profile_id: _ = profiler.start_profile(ProfileTarget::Runtime).unwrap();
assert!(profile_id > 0);
std::thread::sleep(Duration::from_millis(10));
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();
let id1: _ = profiler.start_profile(ProfileTarget::Runtime).unwrap();
let id2: _ = profiler.start_profile(ProfileTarget::Isolate).unwrap();
std::thread::sleep(Duration::from_millis(5));
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();
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();
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();
let profile_id: _ = profiler.start_profile(ProfileTarget::Runtime).unwrap();
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); assert!(stats.total_profiles > 0);
}
}