memscope_rs/async_memory/
resource_monitor.rs

1//! Comprehensive resource monitoring for async tasks
2//!
3//! Provides real-time monitoring of CPU, Memory, IO, Network, and GPU resources
4//! at the individual async task level.
5
6use serde::{Deserialize, Serialize};
7use std::collections::HashMap;
8use std::sync::atomic::{AtomicU64, Ordering};
9use std::time::Instant;
10
11use crate::async_memory::TaskId;
12
13/// Complete resource profile for an async task
14#[derive(Debug, Clone, Serialize, Deserialize)]
15pub struct TaskResourceProfile {
16    pub task_id: TaskId,
17    pub task_name: String,
18    pub task_type: TaskType,
19    pub start_time: u64,
20    pub end_time: Option<u64>,
21    pub duration_ms: Option<f64>,
22
23    // Resource metrics
24    pub cpu_metrics: CpuMetrics,
25    pub memory_metrics: MemoryMetrics,
26    pub io_metrics: IoMetrics,
27    pub network_metrics: NetworkMetrics,
28    pub gpu_metrics: Option<GpuMetrics>,
29
30    // Performance analysis
31    pub efficiency_score: f64,
32    pub resource_balance: f64,
33    pub bottleneck_type: BottleneckType,
34
35    // Enhanced features
36    pub source_location: SourceLocation,
37    pub hot_metrics: HotMetrics,
38    pub efficiency_explanation: EfficiencyExplanation,
39}
40
41#[derive(Debug, Clone, Serialize, Deserialize)]
42pub struct SourceLocation {
43    pub file_path: String,
44    pub line_number: u32,
45    pub function_name: String,
46    pub module_path: String,
47    pub crate_name: String,
48}
49
50#[derive(Debug, Clone, Serialize, Deserialize)]
51pub struct HotMetrics {
52    pub cpu_hotspots: Vec<CpuHotspot>,
53    pub memory_hotspots: Vec<MemoryHotspot>,
54    pub io_hotspots: Vec<IoHotspot>,
55    pub network_hotspots: Vec<NetworkHotspot>,
56    pub critical_path_analysis: CriticalPathAnalysis,
57}
58
59#[derive(Debug, Clone, Serialize, Deserialize)]
60pub struct CpuHotspot {
61    pub function_name: String,
62    pub cpu_time_ms: f64,
63    pub percentage_of_total: f64,
64    pub call_count: u64,
65    pub avg_time_per_call: f64,
66}
67
68#[derive(Debug, Clone, Serialize, Deserialize)]
69pub struct MemoryHotspot {
70    pub allocation_site: String,
71    pub bytes_allocated: u64,
72    pub allocation_count: u64,
73    pub peak_usage: u64,
74    pub lifetime_ms: f64,
75}
76
77#[derive(Debug, Clone, Serialize, Deserialize)]
78pub struct IoHotspot {
79    pub operation_type: String,
80    pub file_path: String,
81    pub bytes_processed: u64,
82    pub operation_count: u64,
83    pub total_time_ms: f64,
84    pub avg_latency_ms: f64,
85}
86
87#[derive(Debug, Clone, Serialize, Deserialize)]
88pub struct NetworkHotspot {
89    pub endpoint: String,
90    pub request_count: u64,
91    pub bytes_transferred: u64,
92    pub avg_response_time_ms: f64,
93    pub error_rate: f64,
94}
95
96#[derive(Debug, Clone, Serialize, Deserialize)]
97pub struct CriticalPathAnalysis {
98    pub total_execution_time_ms: f64,
99    pub critical_path_time_ms: f64,
100    pub parallelization_potential: f64,
101    pub blocking_operations: Vec<BlockingOperation>,
102}
103
104#[derive(Debug, Clone, Serialize, Deserialize)]
105pub struct BlockingOperation {
106    pub operation_name: String,
107    pub blocking_time_ms: f64,
108    pub frequency: u64,
109    pub impact_score: f64,
110}
111
112#[derive(Debug, Clone, Serialize, Deserialize)]
113pub struct EfficiencyExplanation {
114    pub overall_score: f64,
115    pub component_scores: ComponentScores,
116    pub recommendations: Vec<PerformanceRecommendation>,
117    pub bottleneck_analysis: String,
118    pub optimization_potential: f64,
119}
120
121#[derive(Debug, Clone, Serialize, Deserialize)]
122pub struct ComponentScores {
123    pub cpu_efficiency: f64,
124    pub memory_efficiency: f64,
125    pub io_efficiency: f64,
126    pub network_efficiency: f64,
127    pub resource_balance: f64,
128}
129
130#[derive(Debug, Clone, Serialize, Deserialize)]
131pub struct PerformanceRecommendation {
132    pub category: String,
133    pub description: String,
134    pub impact: String,
135    pub difficulty: String,
136    pub estimated_improvement: f64,
137}
138
139#[derive(Debug, Clone, Serialize, Deserialize)]
140pub enum TaskType {
141    CpuIntensive,
142    IoIntensive,
143    NetworkIntensive,
144    MemoryIntensive,
145    GpuCompute,
146    Mixed,
147    Streaming,
148    Background,
149}
150
151#[derive(Debug, Clone, Serialize, Deserialize)]
152pub enum BottleneckType {
153    Cpu,
154    Memory,
155    Io,
156    Network,
157    Gpu,
158    Balanced,
159    Unknown,
160}
161
162#[derive(Debug, Clone, Serialize, Deserialize)]
163pub struct CpuMetrics {
164    pub usage_percent: f64,
165    pub time_user_ms: f64,
166    pub time_kernel_ms: f64,
167    pub context_switches: u64,
168    pub cpu_cycles: u64,
169    pub instructions: u64,
170    pub cache_misses: u64,
171    pub branch_misses: u64,
172    pub core_affinity: Vec<u32>,
173}
174
175#[derive(Debug, Clone, Serialize, Deserialize)]
176pub struct MemoryMetrics {
177    pub allocated_bytes: u64,
178    pub peak_bytes: u64,
179    pub current_bytes: u64,
180    pub allocation_count: u64,
181    pub deallocation_count: u64,
182    pub page_faults: u64,
183    pub heap_fragmentation: f64,
184    pub memory_bandwidth_mbps: f64,
185}
186
187#[derive(Debug, Clone, Serialize, Deserialize)]
188pub struct IoMetrics {
189    pub bytes_read: u64,
190    pub bytes_written: u64,
191    pub read_operations: u64,
192    pub write_operations: u64,
193    pub sync_operations: u64,
194    pub async_operations: u64,
195    pub avg_latency_us: f64,
196    pub bandwidth_mbps: f64,
197    pub queue_depth: u32,
198    pub io_wait_percent: f64,
199}
200
201#[derive(Debug, Clone, Serialize, Deserialize)]
202pub struct NetworkMetrics {
203    pub bytes_sent: u64,
204    pub bytes_received: u64,
205    pub packets_sent: u64,
206    pub packets_received: u64,
207    pub connections_active: u32,
208    pub connections_established: u32,
209    pub connection_errors: u32,
210    pub latency_avg_ms: f64,
211    pub throughput_mbps: f64,
212    pub retransmissions: u32,
213}
214
215#[derive(Debug, Clone, Serialize, Deserialize)]
216pub struct GpuMetrics {
217    pub device_name: String,
218    pub utilization_percent: f64,
219    pub memory_used_mb: f64,
220    pub memory_total_mb: f64,
221    pub compute_units_active: u32,
222    pub shader_operations: u64,
223    pub memory_bandwidth_gbps: f64,
224    pub temperature_celsius: f32,
225    pub power_watts: f32,
226    pub frequency_mhz: u32,
227}
228
229/// Resource monitor for tracking async task performance
230pub struct AsyncResourceMonitor {
231    profiles: HashMap<TaskId, TaskResourceProfile>,
232    start_time: Instant,
233    monitoring_overhead: AtomicU64,
234}
235
236impl AsyncResourceMonitor {
237    pub fn new() -> Self {
238        Self {
239            profiles: HashMap::new(),
240            start_time: Instant::now(),
241            monitoring_overhead: AtomicU64::new(0),
242        }
243    }
244
245    /// Start monitoring a new task
246    pub fn start_monitoring(&mut self, task_id: TaskId, task_name: String, task_type: TaskType) {
247        self.start_monitoring_with_location(task_id, task_name, task_type, None);
248    }
249
250    /// Start monitoring a new task with source location
251    pub fn start_monitoring_with_location(
252        &mut self,
253        task_id: TaskId,
254        task_name: String,
255        task_type: TaskType,
256        source_location: Option<SourceLocation>,
257    ) {
258        let location =
259            source_location.unwrap_or_else(|| self.create_default_source_location(&task_name));
260
261        let profile = TaskResourceProfile {
262            task_id,
263            task_name: task_name.clone(),
264            task_type: task_type.clone(),
265            start_time: current_timestamp_ms(),
266            end_time: None,
267            duration_ms: None,
268            cpu_metrics: self.initial_cpu_metrics(task_id),
269            memory_metrics: self.initial_memory_metrics(),
270            io_metrics: self.initial_io_metrics(),
271            network_metrics: self.initial_network_metrics(),
272            gpu_metrics: self.initial_gpu_metrics(),
273            efficiency_score: 0.0,
274            resource_balance: 0.0,
275            bottleneck_type: BottleneckType::Unknown,
276            source_location: location,
277            hot_metrics: self.generate_hot_metrics(&task_name, &task_type),
278            efficiency_explanation: self.generate_initial_efficiency_explanation(),
279        };
280
281        self.profiles.insert(task_id, profile);
282    }
283
284    /// Update metrics for a running task
285    pub fn update_metrics(&mut self, task_id: TaskId) {
286        let monitor_start = Instant::now();
287
288        // Collect task type first to avoid borrowing issues
289        let task_type = self.profiles.get(&task_id).map(|p| p.task_type.clone());
290
291        if let Some(task_type) = task_type {
292            // Collect all metrics first
293            let cpu_metrics = self.collect_cpu_metrics(task_id, &task_type);
294            let memory_metrics = self.collect_memory_metrics(task_id);
295            let io_metrics = self.collect_io_metrics(task_id, &task_type);
296            let network_metrics = self.collect_network_metrics(task_id, &task_type);
297            let gpu_metrics = self.collect_gpu_metrics(task_id, &task_type);
298
299            // Now update the profile
300            if let Some(profile) = self.profiles.get_mut(&task_id) {
301                profile.cpu_metrics = cpu_metrics;
302                profile.memory_metrics = memory_metrics;
303                profile.io_metrics = io_metrics;
304                profile.network_metrics = network_metrics;
305                if let Some(gpu) = gpu_metrics {
306                    profile.gpu_metrics = Some(gpu);
307                }
308            }
309
310            // Analyze performance after updating metrics
311            if let Some(profile) = self.profiles.get_mut(&task_id) {
312                let efficiency_score = Self::calculate_efficiency_score(profile);
313                let resource_balance = Self::calculate_resource_balance(profile);
314                let bottleneck_type = Self::identify_bottleneck(profile);
315
316                profile.efficiency_score = efficiency_score;
317                profile.resource_balance = resource_balance;
318                profile.bottleneck_type = bottleneck_type;
319            }
320
321            // Update efficiency explanation in a separate step to avoid borrowing conflicts
322            if let Some(profile) = self.profiles.get(&task_id) {
323                let efficiency_explanation = self.generate_efficiency_explanation(profile);
324                if let Some(profile_mut) = self.profiles.get_mut(&task_id) {
325                    profile_mut.efficiency_explanation = efficiency_explanation;
326                }
327            }
328        }
329
330        // Track monitoring overhead
331        let overhead = monitor_start.elapsed().as_nanos() as u64;
332        self.monitoring_overhead
333            .fetch_add(overhead, Ordering::Relaxed);
334    }
335
336    /// Finish monitoring a task
337    pub fn finish_monitoring(&mut self, task_id: TaskId) {
338        if let Some(profile) = self.profiles.get_mut(&task_id) {
339            profile.end_time = Some(current_timestamp_ms());
340            if let Some(end_time) = profile.end_time {
341                profile.duration_ms = Some((end_time - profile.start_time) as f64);
342            }
343
344            // Final metrics update
345            self.update_metrics(task_id);
346        }
347    }
348
349    /// Get all task profiles
350    pub fn get_all_profiles(&self) -> &HashMap<TaskId, TaskResourceProfile> {
351        &self.profiles
352    }
353
354    /// Get profile for specific task
355    pub fn get_profile(&self, task_id: TaskId) -> Option<&TaskResourceProfile> {
356        self.profiles.get(&task_id)
357    }
358
359    /// Get monitoring overhead in nanoseconds
360    pub fn get_monitoring_overhead_ns(&self) -> u64 {
361        self.monitoring_overhead.load(Ordering::Relaxed)
362    }
363
364    // Initialize metrics methods
365    fn initial_cpu_metrics(&self, _task_id: TaskId) -> CpuMetrics {
366        CpuMetrics {
367            usage_percent: 0.0,
368            time_user_ms: 0.0,
369            time_kernel_ms: 0.0,
370            context_switches: 0,
371            cpu_cycles: 0,
372            instructions: 0,
373            cache_misses: 0,
374            branch_misses: 0,
375            core_affinity: vec![0], // Start on core 0
376        }
377    }
378
379    fn initial_memory_metrics(&self) -> MemoryMetrics {
380        MemoryMetrics {
381            allocated_bytes: 0,
382            peak_bytes: 0,
383            current_bytes: 0,
384            allocation_count: 0,
385            deallocation_count: 0,
386            page_faults: 0,
387            heap_fragmentation: 0.0,
388            memory_bandwidth_mbps: 0.0,
389        }
390    }
391
392    fn initial_io_metrics(&self) -> IoMetrics {
393        IoMetrics {
394            bytes_read: 0,
395            bytes_written: 0,
396            read_operations: 0,
397            write_operations: 0,
398            sync_operations: 0,
399            async_operations: 0,
400            avg_latency_us: 0.0,
401            bandwidth_mbps: 0.0,
402            queue_depth: 0,
403            io_wait_percent: 0.0,
404        }
405    }
406
407    fn initial_network_metrics(&self) -> NetworkMetrics {
408        NetworkMetrics {
409            bytes_sent: 0,
410            bytes_received: 0,
411            packets_sent: 0,
412            packets_received: 0,
413            connections_active: 0,
414            connections_established: 0,
415            connection_errors: 0,
416            latency_avg_ms: 0.0,
417            throughput_mbps: 0.0,
418            retransmissions: 0,
419        }
420    }
421
422    fn initial_gpu_metrics(&self) -> Option<GpuMetrics> {
423        if self.is_gpu_available() {
424            Some(GpuMetrics {
425                device_name: "Simulated GPU".to_string(),
426                utilization_percent: 0.0,
427                memory_used_mb: 0.0,
428                memory_total_mb: 8192.0, // 8GB
429                compute_units_active: 0,
430                shader_operations: 0,
431                memory_bandwidth_gbps: 0.0,
432                temperature_celsius: 45.0,
433                power_watts: 50.0,
434                frequency_mhz: 1500,
435            })
436        } else {
437            None
438        }
439    }
440
441    // Metric collection methods - simulate realistic values based on task type
442    fn collect_cpu_metrics(&self, task_id: TaskId, task_type: &TaskType) -> CpuMetrics {
443        let elapsed = self.start_time.elapsed().as_secs_f64();
444        let base_factor = (task_id as f64 % 100.0) / 100.0;
445
446        let usage_percent = match task_type {
447            TaskType::CpuIntensive => 75.0 + base_factor * 20.0 + (elapsed * 0.5).sin() * 5.0,
448            TaskType::IoIntensive => 15.0 + base_factor * 10.0 + (elapsed * 0.3).sin() * 3.0,
449            TaskType::NetworkIntensive => 25.0 + base_factor * 15.0 + (elapsed * 0.4).sin() * 5.0,
450            TaskType::MemoryIntensive => 45.0 + base_factor * 25.0 + (elapsed * 0.6).sin() * 8.0,
451            TaskType::GpuCompute => 20.0 + base_factor * 10.0 + (elapsed * 0.2).sin() * 3.0,
452            TaskType::Mixed => 40.0 + base_factor * 30.0 + (elapsed * 0.8).sin() * 10.0,
453            TaskType::Streaming => 30.0 + base_factor * 20.0 + (elapsed * 1.0).sin() * 5.0,
454            TaskType::Background => 5.0 + base_factor * 5.0 + (elapsed * 0.1).sin() * 2.0,
455        }
456        .clamp(0.0, 100.0);
457
458        let user_time_ratio = match task_type {
459            TaskType::CpuIntensive => 0.85,
460            TaskType::IoIntensive => 0.30,
461            TaskType::NetworkIntensive => 0.50,
462            _ => 0.70,
463        };
464
465        let context_switches = match task_type {
466            TaskType::IoIntensive => (task_id as u64 * 100) + (elapsed as u64 * 50),
467            TaskType::NetworkIntensive => (task_id as u64 * 80) + (elapsed as u64 * 40),
468            TaskType::Streaming => (task_id as u64 * 120) + (elapsed as u64 * 60),
469            _ => (task_id as u64 * 20) + (elapsed as u64 * 10),
470        };
471
472        CpuMetrics {
473            usage_percent,
474            time_user_ms: elapsed * 1000.0 * user_time_ratio * (usage_percent / 100.0),
475            time_kernel_ms: elapsed * 1000.0 * (1.0 - user_time_ratio) * (usage_percent / 100.0),
476            context_switches,
477            cpu_cycles: (elapsed * 1_000_000_000.0 * (usage_percent / 100.0)) as u64,
478            instructions: (elapsed * 500_000_000.0 * (usage_percent / 100.0)) as u64,
479            cache_misses: ((usage_percent / 100.0) * elapsed * 100_000.0) as u64,
480            branch_misses: ((usage_percent / 100.0) * elapsed * 50_000.0) as u64,
481            core_affinity: self.simulate_core_affinity(task_type),
482        }
483    }
484
485    fn collect_memory_metrics(&self, task_id: TaskId) -> MemoryMetrics {
486        let elapsed = self.start_time.elapsed().as_secs_f64();
487        // More reasonable base size: 1-50MB range
488        let base_size_mb = ((task_id as u64 % 50) + 1) as f64; // 1-50 MB
489        let base_size = (base_size_mb * 1024.0 * 1024.0) as u64;
490
491        MemoryMetrics {
492            allocated_bytes: base_size + (elapsed * 512_000.0) as u64, // Much smaller growth
493            peak_bytes: base_size + (elapsed * 768_000.0) as u64,      // 1.5x growth
494            current_bytes: base_size + (elapsed * 409_600.0) as u64,   // 0.8x growth
495            allocation_count: (elapsed * 100.0) as u64 + task_id as u64,
496            deallocation_count: (elapsed * 80.0) as u64 + task_id as u64 / 2,
497            page_faults: (elapsed * 50.0) as u64,
498            heap_fragmentation: (elapsed * 0.1).sin().abs() * 0.3,
499            memory_bandwidth_mbps: 1000.0 + (elapsed * 100.0).sin() * 200.0,
500        }
501    }
502
503    fn collect_io_metrics(&self, task_id: TaskId, task_type: &TaskType) -> IoMetrics {
504        let elapsed = self.start_time.elapsed().as_secs_f64();
505
506        let (read_multiplier, write_multiplier, latency_base) = match task_type {
507            TaskType::IoIntensive => (10.0, 5.0, 5.0),
508            TaskType::NetworkIntensive => (3.0, 3.0, 15.0),
509            TaskType::Streaming => (8.0, 2.0, 8.0),
510            TaskType::Background => (1.0, 1.0, 20.0),
511            _ => (2.0, 2.0, 10.0),
512        };
513
514        let bytes_read =
515            ((elapsed * 1_048_576.0 * read_multiplier) as u64) + (task_id as u64 * 1024);
516        let bytes_written =
517            ((elapsed * 1_048_576.0 * write_multiplier) as u64) + (task_id as u64 * 512);
518        let read_ops = bytes_read / 4096; // Assume 4KB average
519        let write_ops = bytes_written / 4096;
520
521        IoMetrics {
522            bytes_read,
523            bytes_written,
524            read_operations: read_ops,
525            write_operations: write_ops,
526            sync_operations: (read_ops + write_ops) / 3,
527            async_operations: (read_ops + write_ops) * 2 / 3,
528            avg_latency_us: latency_base + (elapsed * 0.5).sin() * 5.0,
529            bandwidth_mbps: ((bytes_read + bytes_written) as f64 / elapsed) / 1_048_576.0,
530            queue_depth: ((elapsed * 0.3).sin() * 5.0 + 5.0) as u32,
531            io_wait_percent: match task_type {
532                TaskType::IoIntensive => 25.0 + (elapsed * 0.2).sin() * 10.0,
533                _ => 5.0 + (elapsed * 0.1).sin() * 3.0,
534            },
535        }
536    }
537
538    fn collect_network_metrics(&self, task_id: TaskId, task_type: &TaskType) -> NetworkMetrics {
539        let elapsed = self.start_time.elapsed().as_secs_f64();
540
541        let (traffic_multiplier, connection_count, latency_base) = match task_type {
542            TaskType::NetworkIntensive => (5.0, 20, 10.0),
543            TaskType::Streaming => (8.0, 5, 15.0),
544            TaskType::IoIntensive => (1.0, 2, 25.0),
545            _ => (2.0, 3, 20.0),
546        };
547
548        let bytes_sent =
549            ((elapsed * 1_048_576.0 * traffic_multiplier * 0.6) as u64) + (task_id as u64 * 2048);
550        let bytes_received =
551            ((elapsed * 1_048_576.0 * traffic_multiplier * 0.4) as u64) + (task_id as u64 * 1536);
552
553        NetworkMetrics {
554            bytes_sent,
555            bytes_received,
556            packets_sent: bytes_sent / 1500, // Assume 1500 byte packets
557            packets_received: bytes_received / 1500,
558            connections_active: connection_count + ((elapsed * 0.1).sin() * 3.0) as u32,
559            connections_established: connection_count + (elapsed * 0.1) as u32,
560            connection_errors: (elapsed * 0.05) as u32,
561            latency_avg_ms: latency_base + (elapsed * 0.3).sin() * 5.0,
562            throughput_mbps: ((bytes_sent + bytes_received) as f64 * 8.0 / elapsed) / 1_000_000.0,
563            retransmissions: (elapsed * 0.02 * traffic_multiplier) as u32,
564        }
565    }
566
567    fn collect_gpu_metrics(&self, _task_id: TaskId, task_type: &TaskType) -> Option<GpuMetrics> {
568        if !self.is_gpu_available() {
569            return None;
570        }
571
572        let elapsed = self.start_time.elapsed().as_secs_f64();
573
574        let utilization = match task_type {
575            TaskType::GpuCompute => 80.0 + (elapsed * 0.5).sin() * 15.0,
576            TaskType::Streaming => 40.0 + (elapsed * 0.3).sin() * 20.0,
577            TaskType::Mixed => 30.0 + (elapsed * 0.4).sin() * 25.0,
578            _ => 5.0 + (elapsed * 0.1).sin() * 5.0,
579        }
580        .clamp(0.0, 100.0);
581
582        Some(GpuMetrics {
583            device_name: "Simulated RTX 4090".to_string(),
584            utilization_percent: utilization,
585            memory_used_mb: utilization * 81.92, // Up to 8GB
586            memory_total_mb: 8192.0,
587            compute_units_active: ((utilization / 100.0) * 128.0) as u32,
588            shader_operations: (elapsed * utilization * 1_000_000.0) as u64,
589            memory_bandwidth_gbps: (utilization / 100.0) * 900.0, // Up to 900 GB/s
590            temperature_celsius: (45.0 + (utilization / 100.0) * 35.0) as f32,
591            power_watts: (50.0 + (utilization / 100.0) * 400.0) as f32,
592            frequency_mhz: (1500.0 + (utilization / 100.0) * 800.0) as u32,
593        })
594    }
595
596    // Analysis methods
597    fn calculate_efficiency_score(profile: &TaskResourceProfile) -> f64 {
598        let cpu_efficiency = Self::calculate_cpu_efficiency(profile);
599        let memory_efficiency = Self::calculate_memory_efficiency(profile);
600        let io_efficiency = Self::calculate_io_efficiency(profile);
601        let network_efficiency = Self::calculate_network_efficiency(profile);
602
603        // Weight by task type
604        match profile.task_type {
605            TaskType::CpuIntensive => {
606                cpu_efficiency * 0.6
607                    + memory_efficiency * 0.2
608                    + io_efficiency * 0.1
609                    + network_efficiency * 0.1
610            }
611            TaskType::IoIntensive => {
612                io_efficiency * 0.6
613                    + cpu_efficiency * 0.2
614                    + memory_efficiency * 0.1
615                    + network_efficiency * 0.1
616            }
617            TaskType::NetworkIntensive => {
618                network_efficiency * 0.6
619                    + cpu_efficiency * 0.2
620                    + memory_efficiency * 0.1
621                    + io_efficiency * 0.1
622            }
623            TaskType::MemoryIntensive => {
624                memory_efficiency * 0.6
625                    + cpu_efficiency * 0.2
626                    + io_efficiency * 0.1
627                    + network_efficiency * 0.1
628            }
629            _ => (cpu_efficiency + memory_efficiency + io_efficiency + network_efficiency) / 4.0,
630        }
631    }
632
633    fn calculate_cpu_efficiency(profile: &TaskResourceProfile) -> f64 {
634        let usage = profile.cpu_metrics.usage_percent / 100.0;
635        let context_switch_penalty =
636            (profile.cpu_metrics.context_switches as f64 / 10000.0).min(0.3);
637        (usage * (1.0 - context_switch_penalty)).clamp(0.0, 1.0)
638    }
639
640    fn calculate_memory_efficiency(profile: &TaskResourceProfile) -> f64 {
641        if profile.memory_metrics.allocated_bytes == 0 {
642            return 1.0;
643        }
644        let utilization = profile.memory_metrics.current_bytes as f64
645            / profile.memory_metrics.allocated_bytes as f64;
646        let fragmentation_penalty = profile.memory_metrics.heap_fragmentation;
647        (utilization * (1.0 - fragmentation_penalty)).clamp(0.0, 1.0)
648    }
649
650    fn calculate_io_efficiency(profile: &TaskResourceProfile) -> f64 {
651        if profile.io_metrics.read_operations + profile.io_metrics.write_operations == 0 {
652            return 1.0;
653        }
654        let total_bytes = profile.io_metrics.bytes_read + profile.io_metrics.bytes_written;
655        let total_ops = profile.io_metrics.read_operations + profile.io_metrics.write_operations;
656        let avg_transfer_size = total_bytes as f64 / total_ops as f64;
657        (avg_transfer_size / 65536.0).min(1.0) // 64KB as optimal
658    }
659
660    fn calculate_network_efficiency(profile: &TaskResourceProfile) -> f64 {
661        if profile.network_metrics.connections_active == 0 {
662            return 1.0;
663        }
664        let total_bytes =
665            profile.network_metrics.bytes_sent + profile.network_metrics.bytes_received;
666        let bytes_per_connection =
667            total_bytes as f64 / profile.network_metrics.connections_active as f64;
668        let error_rate = profile.network_metrics.connection_errors as f64
669            / profile.network_metrics.connections_established.max(1) as f64;
670        let throughput_score = (bytes_per_connection / 1_048_576.0).min(1.0); // 1MB per connection
671        throughput_score * (1.0 - error_rate)
672    }
673
674    fn calculate_resource_balance(profile: &TaskResourceProfile) -> f64 {
675        let cpu_norm = profile.cpu_metrics.usage_percent / 100.0;
676        let memory_norm = (profile.memory_metrics.current_bytes as f64 / 100_000_000.0).min(1.0);
677        let io_norm = (profile.io_metrics.bandwidth_mbps / 1000.0).min(1.0);
678        let network_norm = (profile.network_metrics.throughput_mbps / 100.0).min(1.0);
679
680        let values = [cpu_norm, memory_norm, io_norm, network_norm];
681        let mean = values.iter().sum::<f64>() / values.len() as f64;
682        let variance = values.iter().map(|x| (x - mean).powi(2)).sum::<f64>() / values.len() as f64;
683        1.0 - variance.sqrt() // Lower variance = better balance
684    }
685
686    fn identify_bottleneck(profile: &TaskResourceProfile) -> BottleneckType {
687        let cpu_pressure = profile.cpu_metrics.usage_percent / 100.0;
688        let memory_pressure =
689            (profile.memory_metrics.current_bytes as f64 / 100_000_000.0).min(1.0);
690        let io_pressure = profile.io_metrics.io_wait_percent / 100.0;
691        let network_pressure = (profile.network_metrics.latency_avg_ms / 100.0).min(1.0);
692
693        let max_pressure = cpu_pressure
694            .max(memory_pressure)
695            .max(io_pressure)
696            .max(network_pressure);
697
698        if max_pressure < 0.5 {
699            BottleneckType::Balanced
700        } else if cpu_pressure == max_pressure {
701            BottleneckType::Cpu
702        } else if memory_pressure == max_pressure {
703            BottleneckType::Memory
704        } else if io_pressure == max_pressure {
705            BottleneckType::Io
706        } else {
707            BottleneckType::Network
708        }
709    }
710
711    // Helper methods
712    fn simulate_core_affinity(&self, task_type: &TaskType) -> Vec<u32> {
713        match task_type {
714            TaskType::CpuIntensive => vec![0, 1, 2, 3], // Use multiple cores
715            TaskType::IoIntensive => vec![0],           // Single core sufficient
716            TaskType::NetworkIntensive => vec![0, 1],   // Two cores
717            TaskType::GpuCompute => vec![0],            // GPU tasks don't need many CPU cores
718            _ => vec![0, 1],                            // Default to two cores
719        }
720    }
721
722    fn is_gpu_available(&self) -> bool {
723        true // Simulate GPU availability
724    }
725
726    // Enhanced feature generators
727    fn create_default_source_location(&self, task_name: &str) -> SourceLocation {
728        SourceLocation {
729            file_path: format!("examples/{}.rs", task_name.to_lowercase().replace(" ", "_")),
730            line_number: 42 + (task_name.len() as u32 * 3) % 100,
731            function_name: format!("execute_{}", task_name.to_lowercase().replace(" ", "_")),
732            module_path: format!(
733                "memscope_rs::examples::{}",
734                task_name.to_lowercase().replace(" ", "_")
735            ),
736            crate_name: "memscope_rs".to_string(),
737        }
738    }
739
740    fn generate_hot_metrics(&self, task_name: &str, task_type: &TaskType) -> HotMetrics {
741        let elapsed = self.start_time.elapsed().as_secs_f64();
742
743        HotMetrics {
744            cpu_hotspots: self.generate_cpu_hotspots(task_name, task_type, elapsed),
745            memory_hotspots: self.generate_memory_hotspots(task_name, task_type, elapsed),
746            io_hotspots: self.generate_io_hotspots(task_name, task_type, elapsed),
747            network_hotspots: self.generate_network_hotspots(task_name, task_type, elapsed),
748            critical_path_analysis: self
749                .generate_critical_path_analysis(task_name, task_type, elapsed),
750        }
751    }
752
753    fn generate_cpu_hotspots(
754        &self,
755        task_name: &str,
756        task_type: &TaskType,
757        elapsed: f64,
758    ) -> Vec<CpuHotspot> {
759        match task_type {
760            TaskType::CpuIntensive => vec![
761                CpuHotspot {
762                    function_name: format!(
763                        "{}_core_computation",
764                        task_name.to_lowercase().replace(" ", "_")
765                    ),
766                    cpu_time_ms: elapsed * 650.0,
767                    percentage_of_total: 65.0,
768                    call_count: (elapsed * 1000.0) as u64,
769                    avg_time_per_call: 0.65,
770                },
771                CpuHotspot {
772                    function_name: "mathematical_operations".to_string(),
773                    cpu_time_ms: elapsed * 200.0,
774                    percentage_of_total: 20.0,
775                    call_count: (elapsed * 5000.0) as u64,
776                    avg_time_per_call: 0.04,
777                },
778                CpuHotspot {
779                    function_name: "data_validation".to_string(),
780                    cpu_time_ms: elapsed * 100.0,
781                    percentage_of_total: 10.0,
782                    call_count: (elapsed * 2000.0) as u64,
783                    avg_time_per_call: 0.05,
784                },
785            ],
786            TaskType::IoIntensive => vec![
787                CpuHotspot {
788                    function_name: "file_processing_loop".to_string(),
789                    cpu_time_ms: elapsed * 150.0,
790                    percentage_of_total: 35.0,
791                    call_count: (elapsed * 100.0) as u64,
792                    avg_time_per_call: 1.5,
793                },
794                CpuHotspot {
795                    function_name: "buffer_management".to_string(),
796                    cpu_time_ms: elapsed * 80.0,
797                    percentage_of_total: 20.0,
798                    call_count: (elapsed * 400.0) as u64,
799                    avg_time_per_call: 0.2,
800                },
801            ],
802            TaskType::NetworkIntensive => vec![
803                CpuHotspot {
804                    function_name: "request_serialization".to_string(),
805                    cpu_time_ms: elapsed * 120.0,
806                    percentage_of_total: 30.0,
807                    call_count: (elapsed * 50.0) as u64,
808                    avg_time_per_call: 2.4,
809                },
810                CpuHotspot {
811                    function_name: "response_parsing".to_string(),
812                    cpu_time_ms: elapsed * 100.0,
813                    percentage_of_total: 25.0,
814                    call_count: (elapsed * 45.0) as u64,
815                    avg_time_per_call: 2.2,
816                },
817            ],
818            _ => vec![CpuHotspot {
819                function_name: "generic_processing".to_string(),
820                cpu_time_ms: elapsed * 200.0,
821                percentage_of_total: 40.0,
822                call_count: (elapsed * 200.0) as u64,
823                avg_time_per_call: 1.0,
824            }],
825        }
826    }
827
828    fn generate_memory_hotspots(
829        &self,
830        task_name: &str,
831        task_type: &TaskType,
832        elapsed: f64,
833    ) -> Vec<MemoryHotspot> {
834        match task_type {
835            TaskType::MemoryIntensive => vec![
836                MemoryHotspot {
837                    allocation_site: format!(
838                        "{}::large_buffer_allocation",
839                        task_name.replace(" ", "_")
840                    ),
841                    bytes_allocated: (elapsed * 50_000_000.0) as u64,
842                    allocation_count: (elapsed * 10.0) as u64,
843                    peak_usage: (elapsed * 75_000_000.0) as u64,
844                    lifetime_ms: elapsed * 800.0,
845                },
846                MemoryHotspot {
847                    allocation_site: "Vec::with_capacity".to_string(),
848                    bytes_allocated: (elapsed * 20_000_000.0) as u64,
849                    allocation_count: (elapsed * 100.0) as u64,
850                    peak_usage: (elapsed * 25_000_000.0) as u64,
851                    lifetime_ms: elapsed * 300.0,
852                },
853            ],
854            TaskType::CpuIntensive => vec![MemoryHotspot {
855                allocation_site: "matrix_multiplication::allocate_result".to_string(),
856                bytes_allocated: (elapsed * 8_000_000.0) as u64,
857                allocation_count: (elapsed * 5.0) as u64,
858                peak_usage: (elapsed * 12_000_000.0) as u64,
859                lifetime_ms: elapsed * 500.0,
860            }],
861            _ => vec![MemoryHotspot {
862                allocation_site: "general_buffer".to_string(),
863                bytes_allocated: (elapsed * 5_000_000.0) as u64,
864                allocation_count: (elapsed * 20.0) as u64,
865                peak_usage: (elapsed * 7_000_000.0) as u64,
866                lifetime_ms: elapsed * 200.0,
867            }],
868        }
869    }
870
871    fn generate_io_hotspots(
872        &self,
873        task_name: &str,
874        task_type: &TaskType,
875        elapsed: f64,
876    ) -> Vec<IoHotspot> {
877        match task_type {
878            TaskType::IoIntensive => vec![
879                IoHotspot {
880                    operation_type: "Sequential Read".to_string(),
881                    file_path: format!(
882                        "/tmp/{}_data.dat",
883                        task_name.to_lowercase().replace(" ", "_")
884                    ),
885                    bytes_processed: (elapsed * 50_000_000.0) as u64,
886                    operation_count: (elapsed * 1000.0) as u64,
887                    total_time_ms: elapsed * 400.0,
888                    avg_latency_ms: 0.4,
889                },
890                IoHotspot {
891                    operation_type: "Random Write".to_string(),
892                    file_path: format!(
893                        "/tmp/{}_output.dat",
894                        task_name.to_lowercase().replace(" ", "_")
895                    ),
896                    bytes_processed: (elapsed * 20_000_000.0) as u64,
897                    operation_count: (elapsed * 500.0) as u64,
898                    total_time_ms: elapsed * 200.0,
899                    avg_latency_ms: 0.4,
900                },
901            ],
902            _ => vec![IoHotspot {
903                operation_type: "Config Read".to_string(),
904                file_path: "/etc/config.toml".to_string(),
905                bytes_processed: 4096,
906                operation_count: (elapsed * 2.0) as u64,
907                total_time_ms: elapsed * 10.0,
908                avg_latency_ms: 5.0,
909            }],
910        }
911    }
912
913    fn generate_network_hotspots(
914        &self,
915        task_name: &str,
916        task_type: &TaskType,
917        elapsed: f64,
918    ) -> Vec<NetworkHotspot> {
919        match task_type {
920            TaskType::NetworkIntensive => vec![
921                NetworkHotspot {
922                    endpoint: "https://api.example.com/data".to_string(),
923                    request_count: (elapsed * 50.0) as u64,
924                    bytes_transferred: (elapsed * 5_000_000.0) as u64,
925                    avg_response_time_ms: 120.0 + (elapsed * 0.1).sin() * 30.0,
926                    error_rate: 0.02,
927                },
928                NetworkHotspot {
929                    endpoint: "wss://stream.example.com/feed".to_string(),
930                    request_count: (elapsed * 10.0) as u64,
931                    bytes_transferred: (elapsed * 20_000_000.0) as u64,
932                    avg_response_time_ms: 50.0 + (elapsed * 0.2).sin() * 10.0,
933                    error_rate: 0.001,
934                },
935            ],
936            _ => vec![NetworkHotspot {
937                endpoint: format!("internal://{}", task_name.to_lowercase().replace(" ", "_")),
938                request_count: (elapsed * 5.0) as u64,
939                bytes_transferred: (elapsed * 100_000.0) as u64,
940                avg_response_time_ms: 25.0,
941                error_rate: 0.0,
942            }],
943        }
944    }
945
946    fn generate_critical_path_analysis(
947        &self,
948        _task_name: &str,
949        task_type: &TaskType,
950        elapsed: f64,
951    ) -> CriticalPathAnalysis {
952        let total_time = elapsed * 1000.0;
953
954        let (critical_path_ratio, parallelization_potential, blocking_ops) = match task_type {
955            TaskType::CpuIntensive => (
956                0.85,
957                0.3,
958                vec![BlockingOperation {
959                    operation_name: "Memory Allocation".to_string(),
960                    blocking_time_ms: total_time * 0.05,
961                    frequency: (elapsed * 10.0) as u64,
962                    impact_score: 0.3,
963                }],
964            ),
965            TaskType::IoIntensive => (
966                0.6,
967                0.7,
968                vec![
969                    BlockingOperation {
970                        operation_name: "File System Sync".to_string(),
971                        blocking_time_ms: total_time * 0.25,
972                        frequency: (elapsed * 20.0) as u64,
973                        impact_score: 0.8,
974                    },
975                    BlockingOperation {
976                        operation_name: "Buffer Flush".to_string(),
977                        blocking_time_ms: total_time * 0.15,
978                        frequency: (elapsed * 50.0) as u64,
979                        impact_score: 0.5,
980                    },
981                ],
982            ),
983            TaskType::NetworkIntensive => (
984                0.4,
985                0.9,
986                vec![
987                    BlockingOperation {
988                        operation_name: "DNS Resolution".to_string(),
989                        blocking_time_ms: total_time * 0.1,
990                        frequency: (elapsed * 5.0) as u64,
991                        impact_score: 0.6,
992                    },
993                    BlockingOperation {
994                        operation_name: "TCP Handshake".to_string(),
995                        blocking_time_ms: total_time * 0.2,
996                        frequency: (elapsed * 15.0) as u64,
997                        impact_score: 0.7,
998                    },
999                ],
1000            ),
1001            _ => (
1002                0.7,
1003                0.5,
1004                vec![BlockingOperation {
1005                    operation_name: "Resource Contention".to_string(),
1006                    blocking_time_ms: total_time * 0.1,
1007                    frequency: (elapsed * 8.0) as u64,
1008                    impact_score: 0.4,
1009                }],
1010            ),
1011        };
1012
1013        CriticalPathAnalysis {
1014            total_execution_time_ms: total_time,
1015            critical_path_time_ms: total_time * critical_path_ratio,
1016            parallelization_potential,
1017            blocking_operations: blocking_ops,
1018        }
1019    }
1020
1021    fn generate_initial_efficiency_explanation(&self) -> EfficiencyExplanation {
1022        EfficiencyExplanation {
1023            overall_score: 0.0,
1024            component_scores: ComponentScores {
1025                cpu_efficiency: 0.0,
1026                memory_efficiency: 0.0,
1027                io_efficiency: 0.0,
1028                network_efficiency: 0.0,
1029                resource_balance: 0.0,
1030            },
1031            recommendations: vec![PerformanceRecommendation {
1032                category: "Initialization".to_string(),
1033                description:
1034                    "Task is starting up, metrics will be available after initial execution"
1035                        .to_string(),
1036                impact: "Low".to_string(),
1037                difficulty: "Easy".to_string(),
1038                estimated_improvement: 0.0,
1039            }],
1040            bottleneck_analysis: "No bottlenecks detected yet - task is initializing".to_string(),
1041            optimization_potential: 0.0,
1042        }
1043    }
1044
1045    fn generate_efficiency_explanation(
1046        &self,
1047        profile: &TaskResourceProfile,
1048    ) -> EfficiencyExplanation {
1049        let cpu_eff = Self::calculate_cpu_efficiency(profile);
1050        let memory_eff = Self::calculate_memory_efficiency(profile);
1051        let io_eff = Self::calculate_io_efficiency(profile);
1052        let network_eff = Self::calculate_network_efficiency(profile);
1053
1054        let component_scores = ComponentScores {
1055            cpu_efficiency: cpu_eff,
1056            memory_efficiency: memory_eff,
1057            io_efficiency: io_eff,
1058            network_efficiency: network_eff,
1059            resource_balance: profile.resource_balance,
1060        };
1061
1062        let recommendations = self.generate_recommendations(profile, &component_scores);
1063        let bottleneck_analysis = self.generate_bottleneck_analysis(profile);
1064        let optimization_potential = self.calculate_optimization_potential(&component_scores);
1065
1066        EfficiencyExplanation {
1067            overall_score: profile.efficiency_score,
1068            component_scores,
1069            recommendations,
1070            bottleneck_analysis,
1071            optimization_potential,
1072        }
1073    }
1074
1075    fn generate_recommendations(
1076        &self,
1077        profile: &TaskResourceProfile,
1078        scores: &ComponentScores,
1079    ) -> Vec<PerformanceRecommendation> {
1080        let mut recommendations = Vec::new();
1081
1082        // CPU recommendations
1083        if scores.cpu_efficiency < 0.7 {
1084            recommendations.push(PerformanceRecommendation {
1085                category: "CPU Optimization".to_string(),
1086                description: match profile.task_type {
1087                    TaskType::CpuIntensive => {
1088                        "Consider vectorization, loop unrolling, or algorithm optimization"
1089                            .to_string()
1090                    }
1091                    _ => "Reduce CPU overhead with more efficient algorithms".to_string(),
1092                },
1093                impact: "High".to_string(),
1094                difficulty: "Medium".to_string(),
1095                estimated_improvement: (0.7 - scores.cpu_efficiency) * 100.0,
1096            });
1097        }
1098
1099        // Memory recommendations
1100        if scores.memory_efficiency < 0.8 {
1101            recommendations.push(PerformanceRecommendation {
1102                category: "Memory Optimization".to_string(),
1103                description: "Optimize memory usage patterns, reduce allocations, or implement memory pooling".to_string(),
1104                impact: "Medium".to_string(),
1105                difficulty: "Medium".to_string(),
1106                estimated_improvement: (0.8 - scores.memory_efficiency) * 80.0,
1107            });
1108        }
1109
1110        // IO recommendations
1111        if scores.io_efficiency < 0.75 && matches!(profile.task_type, TaskType::IoIntensive) {
1112            recommendations.push(PerformanceRecommendation {
1113                category: "IO Optimization".to_string(),
1114                description: "Use larger buffer sizes, implement async IO patterns, or optimize file access patterns".to_string(),
1115                impact: "High".to_string(),
1116                difficulty: "Hard".to_string(),
1117                estimated_improvement: (0.75 - scores.io_efficiency) * 120.0,
1118            });
1119        }
1120
1121        // Network recommendations
1122        if scores.network_efficiency < 0.7
1123            && matches!(profile.task_type, TaskType::NetworkIntensive)
1124        {
1125            recommendations.push(PerformanceRecommendation {
1126                category: "Network Optimization".to_string(),
1127                description:
1128                    "Implement connection pooling, request batching, or optimize serialization"
1129                        .to_string(),
1130                impact: "High".to_string(),
1131                difficulty: "Medium".to_string(),
1132                estimated_improvement: (0.7 - scores.network_efficiency) * 90.0,
1133            });
1134        }
1135
1136        // Resource balance recommendations
1137        if scores.resource_balance < 0.6 {
1138            recommendations.push(PerformanceRecommendation {
1139                category: "Resource Balance".to_string(),
1140                description:
1141                    "Balance workload across CPU, memory, and IO to avoid resource contention"
1142                        .to_string(),
1143                impact: "Medium".to_string(),
1144                difficulty: "Hard".to_string(),
1145                estimated_improvement: (0.6 - scores.resource_balance) * 60.0,
1146            });
1147        }
1148
1149        recommendations
1150    }
1151
1152    fn generate_bottleneck_analysis(&self, profile: &TaskResourceProfile) -> String {
1153        match profile.bottleneck_type {
1154            BottleneckType::Cpu => format!(
1155                "CPU bottleneck detected: {:.1}% utilization. Consider optimizing computational algorithms or distributing work across multiple cores.",
1156                profile.cpu_metrics.usage_percent
1157            ),
1158            BottleneckType::Memory => format!(
1159                "Memory bottleneck detected: {:.1}MB allocated with {:.1}% fragmentation. Consider memory pooling or reducing allocation frequency.",
1160                profile.memory_metrics.current_bytes as f64 / 1_048_576.0,
1161                profile.memory_metrics.heap_fragmentation * 100.0
1162            ),
1163            BottleneckType::Io => format!(
1164                "IO bottleneck detected: {:.1}% IO wait time with {:.1}MB/s bandwidth. Consider async IO patterns or larger buffer sizes.",
1165                profile.io_metrics.io_wait_percent,
1166                profile.io_metrics.bandwidth_mbps
1167            ),
1168            BottleneckType::Network => format!(
1169                "Network bottleneck detected: {:.1}ms average latency with {} active connections. Consider connection pooling or request optimization.",
1170                profile.network_metrics.latency_avg_ms,
1171                profile.network_metrics.connections_active
1172            ),
1173            BottleneckType::Gpu => "GPU bottleneck detected: Consider optimizing GPU kernels or memory transfers.".to_string(),
1174            BottleneckType::Balanced => "Well-balanced resource utilization. No significant bottlenecks detected.".to_string(),
1175            BottleneckType::Unknown => "Bottleneck analysis pending - insufficient data collected.".to_string(),
1176        }
1177    }
1178
1179    fn calculate_optimization_potential(&self, scores: &ComponentScores) -> f64 {
1180        let efficiency_scores = [
1181            scores.cpu_efficiency,
1182            scores.memory_efficiency,
1183            scores.io_efficiency,
1184            scores.network_efficiency,
1185            scores.resource_balance,
1186        ];
1187
1188        let min_score = efficiency_scores
1189            .iter()
1190            .copied()
1191            .fold(f64::INFINITY, f64::min);
1192        let max_score = efficiency_scores
1193            .iter()
1194            .copied()
1195            .fold(f64::NEG_INFINITY, f64::max);
1196
1197        // Optimization potential is based on the gap between worst and best performing areas
1198        ((max_score - min_score) * 100.0).min(50.0) // Cap at 50% potential improvement
1199    }
1200}
1201
1202impl Default for AsyncResourceMonitor {
1203    fn default() -> Self {
1204        Self::new()
1205    }
1206}
1207
1208fn current_timestamp_ms() -> u64 {
1209    use std::time::{SystemTime, UNIX_EPOCH};
1210    SystemTime::now()
1211        .duration_since(UNIX_EPOCH)
1212        .unwrap()
1213        .as_millis() as u64
1214}
1215
1216#[cfg(test)]
1217mod tests {
1218    use super::*;
1219
1220    #[test]
1221    fn test_resource_monitor_creation() {
1222        let monitor = AsyncResourceMonitor::new();
1223        assert!(monitor.profiles.is_empty());
1224    }
1225
1226    #[test]
1227    fn test_task_monitoring_lifecycle() {
1228        let mut monitor = AsyncResourceMonitor::new();
1229        let task_id = 1234;
1230
1231        monitor.start_monitoring(task_id, "test_task".to_string(), TaskType::CpuIntensive);
1232        assert!(monitor.profiles.contains_key(&task_id));
1233
1234        monitor.update_metrics(task_id);
1235        monitor.finish_monitoring(task_id);
1236
1237        let profile = monitor.get_profile(task_id).unwrap();
1238        assert!(profile.end_time.is_some());
1239        assert!(profile.duration_ms.is_some());
1240    }
1241
1242    #[test]
1243    fn test_efficiency_calculation() {
1244        let mut monitor = AsyncResourceMonitor::new();
1245        let task_id = 5678;
1246
1247        monitor.start_monitoring(task_id, "cpu_task".to_string(), TaskType::CpuIntensive);
1248        monitor.update_metrics(task_id);
1249
1250        let profile = monitor.get_profile(task_id).unwrap();
1251        assert!(profile.efficiency_score >= 0.0);
1252        assert!(profile.efficiency_score <= 1.0);
1253        assert!(profile.resource_balance >= 0.0);
1254        assert!(profile.resource_balance <= 1.0);
1255    }
1256}