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        let base_size = (task_id as u64 % 1000) * 1024 * 1024; // Base MB in bytes
488
489        MemoryMetrics {
490            allocated_bytes: base_size + (elapsed * 1_048_576.0) as u64,
491            peak_bytes: base_size + (elapsed * 1_048_576.0 * 1.5) as u64,
492            current_bytes: base_size + (elapsed * 1_048_576.0 * 0.8) as u64,
493            allocation_count: (elapsed * 100.0) as u64 + task_id as u64,
494            deallocation_count: (elapsed * 80.0) as u64 + task_id as u64 / 2,
495            page_faults: (elapsed * 50.0) as u64,
496            heap_fragmentation: (elapsed * 0.1).sin().abs() * 0.3,
497            memory_bandwidth_mbps: 1000.0 + (elapsed * 100.0).sin() * 200.0,
498        }
499    }
500
501    fn collect_io_metrics(&self, task_id: TaskId, task_type: &TaskType) -> IoMetrics {
502        let elapsed = self.start_time.elapsed().as_secs_f64();
503
504        let (read_multiplier, write_multiplier, latency_base) = match task_type {
505            TaskType::IoIntensive => (10.0, 5.0, 5.0),
506            TaskType::NetworkIntensive => (3.0, 3.0, 15.0),
507            TaskType::Streaming => (8.0, 2.0, 8.0),
508            TaskType::Background => (1.0, 1.0, 20.0),
509            _ => (2.0, 2.0, 10.0),
510        };
511
512        let bytes_read =
513            ((elapsed * 1_048_576.0 * read_multiplier) as u64) + (task_id as u64 * 1024);
514        let bytes_written =
515            ((elapsed * 1_048_576.0 * write_multiplier) as u64) + (task_id as u64 * 512);
516        let read_ops = bytes_read / 4096; // Assume 4KB average
517        let write_ops = bytes_written / 4096;
518
519        IoMetrics {
520            bytes_read,
521            bytes_written,
522            read_operations: read_ops,
523            write_operations: write_ops,
524            sync_operations: (read_ops + write_ops) / 3,
525            async_operations: (read_ops + write_ops) * 2 / 3,
526            avg_latency_us: latency_base + (elapsed * 0.5).sin() * 5.0,
527            bandwidth_mbps: ((bytes_read + bytes_written) as f64 / elapsed) / 1_048_576.0,
528            queue_depth: ((elapsed * 0.3).sin() * 5.0 + 5.0) as u32,
529            io_wait_percent: match task_type {
530                TaskType::IoIntensive => 25.0 + (elapsed * 0.2).sin() * 10.0,
531                _ => 5.0 + (elapsed * 0.1).sin() * 3.0,
532            },
533        }
534    }
535
536    fn collect_network_metrics(&self, task_id: TaskId, task_type: &TaskType) -> NetworkMetrics {
537        let elapsed = self.start_time.elapsed().as_secs_f64();
538
539        let (traffic_multiplier, connection_count, latency_base) = match task_type {
540            TaskType::NetworkIntensive => (5.0, 20, 10.0),
541            TaskType::Streaming => (8.0, 5, 15.0),
542            TaskType::IoIntensive => (1.0, 2, 25.0),
543            _ => (2.0, 3, 20.0),
544        };
545
546        let bytes_sent =
547            ((elapsed * 1_048_576.0 * traffic_multiplier * 0.6) as u64) + (task_id as u64 * 2048);
548        let bytes_received =
549            ((elapsed * 1_048_576.0 * traffic_multiplier * 0.4) as u64) + (task_id as u64 * 1536);
550
551        NetworkMetrics {
552            bytes_sent,
553            bytes_received,
554            packets_sent: bytes_sent / 1500, // Assume 1500 byte packets
555            packets_received: bytes_received / 1500,
556            connections_active: connection_count + ((elapsed * 0.1).sin() * 3.0) as u32,
557            connections_established: connection_count + (elapsed * 0.1) as u32,
558            connection_errors: (elapsed * 0.05) as u32,
559            latency_avg_ms: latency_base + (elapsed * 0.3).sin() * 5.0,
560            throughput_mbps: ((bytes_sent + bytes_received) as f64 * 8.0 / elapsed) / 1_000_000.0,
561            retransmissions: (elapsed * 0.02 * traffic_multiplier) as u32,
562        }
563    }
564
565    fn collect_gpu_metrics(&self, _task_id: TaskId, task_type: &TaskType) -> Option<GpuMetrics> {
566        if !self.is_gpu_available() {
567            return None;
568        }
569
570        let elapsed = self.start_time.elapsed().as_secs_f64();
571
572        let utilization = match task_type {
573            TaskType::GpuCompute => 80.0 + (elapsed * 0.5).sin() * 15.0,
574            TaskType::Streaming => 40.0 + (elapsed * 0.3).sin() * 20.0,
575            TaskType::Mixed => 30.0 + (elapsed * 0.4).sin() * 25.0,
576            _ => 5.0 + (elapsed * 0.1).sin() * 5.0,
577        }
578        .clamp(0.0, 100.0);
579
580        Some(GpuMetrics {
581            device_name: "Simulated RTX 4090".to_string(),
582            utilization_percent: utilization,
583            memory_used_mb: utilization * 81.92, // Up to 8GB
584            memory_total_mb: 8192.0,
585            compute_units_active: ((utilization / 100.0) * 128.0) as u32,
586            shader_operations: (elapsed * utilization * 1_000_000.0) as u64,
587            memory_bandwidth_gbps: (utilization / 100.0) * 900.0, // Up to 900 GB/s
588            temperature_celsius: (45.0 + (utilization / 100.0) * 35.0) as f32,
589            power_watts: (50.0 + (utilization / 100.0) * 400.0) as f32,
590            frequency_mhz: (1500.0 + (utilization / 100.0) * 800.0) as u32,
591        })
592    }
593
594    // Analysis methods
595    fn calculate_efficiency_score(profile: &TaskResourceProfile) -> f64 {
596        let cpu_efficiency = Self::calculate_cpu_efficiency(profile);
597        let memory_efficiency = Self::calculate_memory_efficiency(profile);
598        let io_efficiency = Self::calculate_io_efficiency(profile);
599        let network_efficiency = Self::calculate_network_efficiency(profile);
600
601        // Weight by task type
602        match profile.task_type {
603            TaskType::CpuIntensive => {
604                cpu_efficiency * 0.6
605                    + memory_efficiency * 0.2
606                    + io_efficiency * 0.1
607                    + network_efficiency * 0.1
608            }
609            TaskType::IoIntensive => {
610                io_efficiency * 0.6
611                    + cpu_efficiency * 0.2
612                    + memory_efficiency * 0.1
613                    + network_efficiency * 0.1
614            }
615            TaskType::NetworkIntensive => {
616                network_efficiency * 0.6
617                    + cpu_efficiency * 0.2
618                    + memory_efficiency * 0.1
619                    + io_efficiency * 0.1
620            }
621            TaskType::MemoryIntensive => {
622                memory_efficiency * 0.6
623                    + cpu_efficiency * 0.2
624                    + io_efficiency * 0.1
625                    + network_efficiency * 0.1
626            }
627            _ => (cpu_efficiency + memory_efficiency + io_efficiency + network_efficiency) / 4.0,
628        }
629    }
630
631    fn calculate_cpu_efficiency(profile: &TaskResourceProfile) -> f64 {
632        let usage = profile.cpu_metrics.usage_percent / 100.0;
633        let context_switch_penalty =
634            (profile.cpu_metrics.context_switches as f64 / 10000.0).min(0.3);
635        (usage * (1.0 - context_switch_penalty)).clamp(0.0, 1.0)
636    }
637
638    fn calculate_memory_efficiency(profile: &TaskResourceProfile) -> f64 {
639        if profile.memory_metrics.allocated_bytes == 0 {
640            return 1.0;
641        }
642        let utilization = profile.memory_metrics.current_bytes as f64
643            / profile.memory_metrics.allocated_bytes as f64;
644        let fragmentation_penalty = profile.memory_metrics.heap_fragmentation;
645        (utilization * (1.0 - fragmentation_penalty)).clamp(0.0, 1.0)
646    }
647
648    fn calculate_io_efficiency(profile: &TaskResourceProfile) -> f64 {
649        if profile.io_metrics.read_operations + profile.io_metrics.write_operations == 0 {
650            return 1.0;
651        }
652        let total_bytes = profile.io_metrics.bytes_read + profile.io_metrics.bytes_written;
653        let total_ops = profile.io_metrics.read_operations + profile.io_metrics.write_operations;
654        let avg_transfer_size = total_bytes as f64 / total_ops as f64;
655        (avg_transfer_size / 65536.0).min(1.0) // 64KB as optimal
656    }
657
658    fn calculate_network_efficiency(profile: &TaskResourceProfile) -> f64 {
659        if profile.network_metrics.connections_active == 0 {
660            return 1.0;
661        }
662        let total_bytes =
663            profile.network_metrics.bytes_sent + profile.network_metrics.bytes_received;
664        let bytes_per_connection =
665            total_bytes as f64 / profile.network_metrics.connections_active as f64;
666        let error_rate = profile.network_metrics.connection_errors as f64
667            / profile.network_metrics.connections_established.max(1) as f64;
668        let throughput_score = (bytes_per_connection / 1_048_576.0).min(1.0); // 1MB per connection
669        throughput_score * (1.0 - error_rate)
670    }
671
672    fn calculate_resource_balance(profile: &TaskResourceProfile) -> f64 {
673        let cpu_norm = profile.cpu_metrics.usage_percent / 100.0;
674        let memory_norm = (profile.memory_metrics.current_bytes as f64 / 100_000_000.0).min(1.0);
675        let io_norm = (profile.io_metrics.bandwidth_mbps / 1000.0).min(1.0);
676        let network_norm = (profile.network_metrics.throughput_mbps / 100.0).min(1.0);
677
678        let values = [cpu_norm, memory_norm, io_norm, network_norm];
679        let mean = values.iter().sum::<f64>() / values.len() as f64;
680        let variance = values.iter().map(|x| (x - mean).powi(2)).sum::<f64>() / values.len() as f64;
681        1.0 - variance.sqrt() // Lower variance = better balance
682    }
683
684    fn identify_bottleneck(profile: &TaskResourceProfile) -> BottleneckType {
685        let cpu_pressure = profile.cpu_metrics.usage_percent / 100.0;
686        let memory_pressure =
687            (profile.memory_metrics.current_bytes as f64 / 100_000_000.0).min(1.0);
688        let io_pressure = profile.io_metrics.io_wait_percent / 100.0;
689        let network_pressure = (profile.network_metrics.latency_avg_ms / 100.0).min(1.0);
690
691        let max_pressure = cpu_pressure
692            .max(memory_pressure)
693            .max(io_pressure)
694            .max(network_pressure);
695
696        if max_pressure < 0.5 {
697            BottleneckType::Balanced
698        } else if cpu_pressure == max_pressure {
699            BottleneckType::Cpu
700        } else if memory_pressure == max_pressure {
701            BottleneckType::Memory
702        } else if io_pressure == max_pressure {
703            BottleneckType::Io
704        } else {
705            BottleneckType::Network
706        }
707    }
708
709    // Helper methods
710    fn simulate_core_affinity(&self, task_type: &TaskType) -> Vec<u32> {
711        match task_type {
712            TaskType::CpuIntensive => vec![0, 1, 2, 3], // Use multiple cores
713            TaskType::IoIntensive => vec![0],           // Single core sufficient
714            TaskType::NetworkIntensive => vec![0, 1],   // Two cores
715            TaskType::GpuCompute => vec![0],            // GPU tasks don't need many CPU cores
716            _ => vec![0, 1],                            // Default to two cores
717        }
718    }
719
720    fn is_gpu_available(&self) -> bool {
721        true // Simulate GPU availability
722    }
723
724    // Enhanced feature generators
725    fn create_default_source_location(&self, task_name: &str) -> SourceLocation {
726        SourceLocation {
727            file_path: format!("examples/{}.rs", task_name.to_lowercase().replace(" ", "_")),
728            line_number: 42 + (task_name.len() as u32 * 3) % 100,
729            function_name: format!("execute_{}", task_name.to_lowercase().replace(" ", "_")),
730            module_path: format!(
731                "memscope_rs::examples::{}",
732                task_name.to_lowercase().replace(" ", "_")
733            ),
734            crate_name: "memscope_rs".to_string(),
735        }
736    }
737
738    fn generate_hot_metrics(&self, task_name: &str, task_type: &TaskType) -> HotMetrics {
739        let elapsed = self.start_time.elapsed().as_secs_f64();
740
741        HotMetrics {
742            cpu_hotspots: self.generate_cpu_hotspots(task_name, task_type, elapsed),
743            memory_hotspots: self.generate_memory_hotspots(task_name, task_type, elapsed),
744            io_hotspots: self.generate_io_hotspots(task_name, task_type, elapsed),
745            network_hotspots: self.generate_network_hotspots(task_name, task_type, elapsed),
746            critical_path_analysis: self
747                .generate_critical_path_analysis(task_name, task_type, elapsed),
748        }
749    }
750
751    fn generate_cpu_hotspots(
752        &self,
753        task_name: &str,
754        task_type: &TaskType,
755        elapsed: f64,
756    ) -> Vec<CpuHotspot> {
757        match task_type {
758            TaskType::CpuIntensive => vec![
759                CpuHotspot {
760                    function_name: format!(
761                        "{}_core_computation",
762                        task_name.to_lowercase().replace(" ", "_")
763                    ),
764                    cpu_time_ms: elapsed * 650.0,
765                    percentage_of_total: 65.0,
766                    call_count: (elapsed * 1000.0) as u64,
767                    avg_time_per_call: 0.65,
768                },
769                CpuHotspot {
770                    function_name: "mathematical_operations".to_string(),
771                    cpu_time_ms: elapsed * 200.0,
772                    percentage_of_total: 20.0,
773                    call_count: (elapsed * 5000.0) as u64,
774                    avg_time_per_call: 0.04,
775                },
776                CpuHotspot {
777                    function_name: "data_validation".to_string(),
778                    cpu_time_ms: elapsed * 100.0,
779                    percentage_of_total: 10.0,
780                    call_count: (elapsed * 2000.0) as u64,
781                    avg_time_per_call: 0.05,
782                },
783            ],
784            TaskType::IoIntensive => vec![
785                CpuHotspot {
786                    function_name: "file_processing_loop".to_string(),
787                    cpu_time_ms: elapsed * 150.0,
788                    percentage_of_total: 35.0,
789                    call_count: (elapsed * 100.0) as u64,
790                    avg_time_per_call: 1.5,
791                },
792                CpuHotspot {
793                    function_name: "buffer_management".to_string(),
794                    cpu_time_ms: elapsed * 80.0,
795                    percentage_of_total: 20.0,
796                    call_count: (elapsed * 400.0) as u64,
797                    avg_time_per_call: 0.2,
798                },
799            ],
800            TaskType::NetworkIntensive => vec![
801                CpuHotspot {
802                    function_name: "request_serialization".to_string(),
803                    cpu_time_ms: elapsed * 120.0,
804                    percentage_of_total: 30.0,
805                    call_count: (elapsed * 50.0) as u64,
806                    avg_time_per_call: 2.4,
807                },
808                CpuHotspot {
809                    function_name: "response_parsing".to_string(),
810                    cpu_time_ms: elapsed * 100.0,
811                    percentage_of_total: 25.0,
812                    call_count: (elapsed * 45.0) as u64,
813                    avg_time_per_call: 2.2,
814                },
815            ],
816            _ => vec![CpuHotspot {
817                function_name: "generic_processing".to_string(),
818                cpu_time_ms: elapsed * 200.0,
819                percentage_of_total: 40.0,
820                call_count: (elapsed * 200.0) as u64,
821                avg_time_per_call: 1.0,
822            }],
823        }
824    }
825
826    fn generate_memory_hotspots(
827        &self,
828        task_name: &str,
829        task_type: &TaskType,
830        elapsed: f64,
831    ) -> Vec<MemoryHotspot> {
832        match task_type {
833            TaskType::MemoryIntensive => vec![
834                MemoryHotspot {
835                    allocation_site: format!(
836                        "{}::large_buffer_allocation",
837                        task_name.replace(" ", "_")
838                    ),
839                    bytes_allocated: (elapsed * 50_000_000.0) as u64,
840                    allocation_count: (elapsed * 10.0) as u64,
841                    peak_usage: (elapsed * 75_000_000.0) as u64,
842                    lifetime_ms: elapsed * 800.0,
843                },
844                MemoryHotspot {
845                    allocation_site: "Vec::with_capacity".to_string(),
846                    bytes_allocated: (elapsed * 20_000_000.0) as u64,
847                    allocation_count: (elapsed * 100.0) as u64,
848                    peak_usage: (elapsed * 25_000_000.0) as u64,
849                    lifetime_ms: elapsed * 300.0,
850                },
851            ],
852            TaskType::CpuIntensive => vec![MemoryHotspot {
853                allocation_site: "matrix_multiplication::allocate_result".to_string(),
854                bytes_allocated: (elapsed * 8_000_000.0) as u64,
855                allocation_count: (elapsed * 5.0) as u64,
856                peak_usage: (elapsed * 12_000_000.0) as u64,
857                lifetime_ms: elapsed * 500.0,
858            }],
859            _ => vec![MemoryHotspot {
860                allocation_site: "general_buffer".to_string(),
861                bytes_allocated: (elapsed * 5_000_000.0) as u64,
862                allocation_count: (elapsed * 20.0) as u64,
863                peak_usage: (elapsed * 7_000_000.0) as u64,
864                lifetime_ms: elapsed * 200.0,
865            }],
866        }
867    }
868
869    fn generate_io_hotspots(
870        &self,
871        task_name: &str,
872        task_type: &TaskType,
873        elapsed: f64,
874    ) -> Vec<IoHotspot> {
875        match task_type {
876            TaskType::IoIntensive => vec![
877                IoHotspot {
878                    operation_type: "Sequential Read".to_string(),
879                    file_path: format!(
880                        "/tmp/{}_data.dat",
881                        task_name.to_lowercase().replace(" ", "_")
882                    ),
883                    bytes_processed: (elapsed * 50_000_000.0) as u64,
884                    operation_count: (elapsed * 1000.0) as u64,
885                    total_time_ms: elapsed * 400.0,
886                    avg_latency_ms: 0.4,
887                },
888                IoHotspot {
889                    operation_type: "Random Write".to_string(),
890                    file_path: format!(
891                        "/tmp/{}_output.dat",
892                        task_name.to_lowercase().replace(" ", "_")
893                    ),
894                    bytes_processed: (elapsed * 20_000_000.0) as u64,
895                    operation_count: (elapsed * 500.0) as u64,
896                    total_time_ms: elapsed * 200.0,
897                    avg_latency_ms: 0.4,
898                },
899            ],
900            _ => vec![IoHotspot {
901                operation_type: "Config Read".to_string(),
902                file_path: "/etc/config.toml".to_string(),
903                bytes_processed: 4096,
904                operation_count: (elapsed * 2.0) as u64,
905                total_time_ms: elapsed * 10.0,
906                avg_latency_ms: 5.0,
907            }],
908        }
909    }
910
911    fn generate_network_hotspots(
912        &self,
913        task_name: &str,
914        task_type: &TaskType,
915        elapsed: f64,
916    ) -> Vec<NetworkHotspot> {
917        match task_type {
918            TaskType::NetworkIntensive => vec![
919                NetworkHotspot {
920                    endpoint: "https://api.example.com/data".to_string(),
921                    request_count: (elapsed * 50.0) as u64,
922                    bytes_transferred: (elapsed * 5_000_000.0) as u64,
923                    avg_response_time_ms: 120.0 + (elapsed * 0.1).sin() * 30.0,
924                    error_rate: 0.02,
925                },
926                NetworkHotspot {
927                    endpoint: "wss://stream.example.com/feed".to_string(),
928                    request_count: (elapsed * 10.0) as u64,
929                    bytes_transferred: (elapsed * 20_000_000.0) as u64,
930                    avg_response_time_ms: 50.0 + (elapsed * 0.2).sin() * 10.0,
931                    error_rate: 0.001,
932                },
933            ],
934            _ => vec![NetworkHotspot {
935                endpoint: format!("internal://{}", task_name.to_lowercase().replace(" ", "_")),
936                request_count: (elapsed * 5.0) as u64,
937                bytes_transferred: (elapsed * 100_000.0) as u64,
938                avg_response_time_ms: 25.0,
939                error_rate: 0.0,
940            }],
941        }
942    }
943
944    fn generate_critical_path_analysis(
945        &self,
946        _task_name: &str,
947        task_type: &TaskType,
948        elapsed: f64,
949    ) -> CriticalPathAnalysis {
950        let total_time = elapsed * 1000.0;
951
952        let (critical_path_ratio, parallelization_potential, blocking_ops) = match task_type {
953            TaskType::CpuIntensive => (
954                0.85,
955                0.3,
956                vec![BlockingOperation {
957                    operation_name: "Memory Allocation".to_string(),
958                    blocking_time_ms: total_time * 0.05,
959                    frequency: (elapsed * 10.0) as u64,
960                    impact_score: 0.3,
961                }],
962            ),
963            TaskType::IoIntensive => (
964                0.6,
965                0.7,
966                vec![
967                    BlockingOperation {
968                        operation_name: "File System Sync".to_string(),
969                        blocking_time_ms: total_time * 0.25,
970                        frequency: (elapsed * 20.0) as u64,
971                        impact_score: 0.8,
972                    },
973                    BlockingOperation {
974                        operation_name: "Buffer Flush".to_string(),
975                        blocking_time_ms: total_time * 0.15,
976                        frequency: (elapsed * 50.0) as u64,
977                        impact_score: 0.5,
978                    },
979                ],
980            ),
981            TaskType::NetworkIntensive => (
982                0.4,
983                0.9,
984                vec![
985                    BlockingOperation {
986                        operation_name: "DNS Resolution".to_string(),
987                        blocking_time_ms: total_time * 0.1,
988                        frequency: (elapsed * 5.0) as u64,
989                        impact_score: 0.6,
990                    },
991                    BlockingOperation {
992                        operation_name: "TCP Handshake".to_string(),
993                        blocking_time_ms: total_time * 0.2,
994                        frequency: (elapsed * 15.0) as u64,
995                        impact_score: 0.7,
996                    },
997                ],
998            ),
999            _ => (
1000                0.7,
1001                0.5,
1002                vec![BlockingOperation {
1003                    operation_name: "Resource Contention".to_string(),
1004                    blocking_time_ms: total_time * 0.1,
1005                    frequency: (elapsed * 8.0) as u64,
1006                    impact_score: 0.4,
1007                }],
1008            ),
1009        };
1010
1011        CriticalPathAnalysis {
1012            total_execution_time_ms: total_time,
1013            critical_path_time_ms: total_time * critical_path_ratio,
1014            parallelization_potential,
1015            blocking_operations: blocking_ops,
1016        }
1017    }
1018
1019    fn generate_initial_efficiency_explanation(&self) -> EfficiencyExplanation {
1020        EfficiencyExplanation {
1021            overall_score: 0.0,
1022            component_scores: ComponentScores {
1023                cpu_efficiency: 0.0,
1024                memory_efficiency: 0.0,
1025                io_efficiency: 0.0,
1026                network_efficiency: 0.0,
1027                resource_balance: 0.0,
1028            },
1029            recommendations: vec![PerformanceRecommendation {
1030                category: "Initialization".to_string(),
1031                description:
1032                    "Task is starting up, metrics will be available after initial execution"
1033                        .to_string(),
1034                impact: "Low".to_string(),
1035                difficulty: "Easy".to_string(),
1036                estimated_improvement: 0.0,
1037            }],
1038            bottleneck_analysis: "No bottlenecks detected yet - task is initializing".to_string(),
1039            optimization_potential: 0.0,
1040        }
1041    }
1042
1043    fn generate_efficiency_explanation(
1044        &self,
1045        profile: &TaskResourceProfile,
1046    ) -> EfficiencyExplanation {
1047        let cpu_eff = Self::calculate_cpu_efficiency(profile);
1048        let memory_eff = Self::calculate_memory_efficiency(profile);
1049        let io_eff = Self::calculate_io_efficiency(profile);
1050        let network_eff = Self::calculate_network_efficiency(profile);
1051
1052        let component_scores = ComponentScores {
1053            cpu_efficiency: cpu_eff,
1054            memory_efficiency: memory_eff,
1055            io_efficiency: io_eff,
1056            network_efficiency: network_eff,
1057            resource_balance: profile.resource_balance,
1058        };
1059
1060        let recommendations = self.generate_recommendations(profile, &component_scores);
1061        let bottleneck_analysis = self.generate_bottleneck_analysis(profile);
1062        let optimization_potential = self.calculate_optimization_potential(&component_scores);
1063
1064        EfficiencyExplanation {
1065            overall_score: profile.efficiency_score,
1066            component_scores,
1067            recommendations,
1068            bottleneck_analysis,
1069            optimization_potential,
1070        }
1071    }
1072
1073    fn generate_recommendations(
1074        &self,
1075        profile: &TaskResourceProfile,
1076        scores: &ComponentScores,
1077    ) -> Vec<PerformanceRecommendation> {
1078        let mut recommendations = Vec::new();
1079
1080        // CPU recommendations
1081        if scores.cpu_efficiency < 0.7 {
1082            recommendations.push(PerformanceRecommendation {
1083                category: "CPU Optimization".to_string(),
1084                description: match profile.task_type {
1085                    TaskType::CpuIntensive => {
1086                        "Consider vectorization, loop unrolling, or algorithm optimization"
1087                            .to_string()
1088                    }
1089                    _ => "Reduce CPU overhead with more efficient algorithms".to_string(),
1090                },
1091                impact: "High".to_string(),
1092                difficulty: "Medium".to_string(),
1093                estimated_improvement: (0.7 - scores.cpu_efficiency) * 100.0,
1094            });
1095        }
1096
1097        // Memory recommendations
1098        if scores.memory_efficiency < 0.8 {
1099            recommendations.push(PerformanceRecommendation {
1100                category: "Memory Optimization".to_string(),
1101                description: "Optimize memory usage patterns, reduce allocations, or implement memory pooling".to_string(),
1102                impact: "Medium".to_string(),
1103                difficulty: "Medium".to_string(),
1104                estimated_improvement: (0.8 - scores.memory_efficiency) * 80.0,
1105            });
1106        }
1107
1108        // IO recommendations
1109        if scores.io_efficiency < 0.75 && matches!(profile.task_type, TaskType::IoIntensive) {
1110            recommendations.push(PerformanceRecommendation {
1111                category: "IO Optimization".to_string(),
1112                description: "Use larger buffer sizes, implement async IO patterns, or optimize file access patterns".to_string(),
1113                impact: "High".to_string(),
1114                difficulty: "Hard".to_string(),
1115                estimated_improvement: (0.75 - scores.io_efficiency) * 120.0,
1116            });
1117        }
1118
1119        // Network recommendations
1120        if scores.network_efficiency < 0.7
1121            && matches!(profile.task_type, TaskType::NetworkIntensive)
1122        {
1123            recommendations.push(PerformanceRecommendation {
1124                category: "Network Optimization".to_string(),
1125                description:
1126                    "Implement connection pooling, request batching, or optimize serialization"
1127                        .to_string(),
1128                impact: "High".to_string(),
1129                difficulty: "Medium".to_string(),
1130                estimated_improvement: (0.7 - scores.network_efficiency) * 90.0,
1131            });
1132        }
1133
1134        // Resource balance recommendations
1135        if scores.resource_balance < 0.6 {
1136            recommendations.push(PerformanceRecommendation {
1137                category: "Resource Balance".to_string(),
1138                description:
1139                    "Balance workload across CPU, memory, and IO to avoid resource contention"
1140                        .to_string(),
1141                impact: "Medium".to_string(),
1142                difficulty: "Hard".to_string(),
1143                estimated_improvement: (0.6 - scores.resource_balance) * 60.0,
1144            });
1145        }
1146
1147        recommendations
1148    }
1149
1150    fn generate_bottleneck_analysis(&self, profile: &TaskResourceProfile) -> String {
1151        match profile.bottleneck_type {
1152            BottleneckType::Cpu => format!(
1153                "CPU bottleneck detected: {:.1}% utilization. Consider optimizing computational algorithms or distributing work across multiple cores.",
1154                profile.cpu_metrics.usage_percent
1155            ),
1156            BottleneckType::Memory => format!(
1157                "Memory bottleneck detected: {:.1}MB allocated with {:.1}% fragmentation. Consider memory pooling or reducing allocation frequency.",
1158                profile.memory_metrics.current_bytes as f64 / 1_048_576.0,
1159                profile.memory_metrics.heap_fragmentation * 100.0
1160            ),
1161            BottleneckType::Io => format!(
1162                "IO bottleneck detected: {:.1}% IO wait time with {:.1}MB/s bandwidth. Consider async IO patterns or larger buffer sizes.",
1163                profile.io_metrics.io_wait_percent,
1164                profile.io_metrics.bandwidth_mbps
1165            ),
1166            BottleneckType::Network => format!(
1167                "Network bottleneck detected: {:.1}ms average latency with {} active connections. Consider connection pooling or request optimization.",
1168                profile.network_metrics.latency_avg_ms,
1169                profile.network_metrics.connections_active
1170            ),
1171            BottleneckType::Gpu => "GPU bottleneck detected: Consider optimizing GPU kernels or memory transfers.".to_string(),
1172            BottleneckType::Balanced => "Well-balanced resource utilization. No significant bottlenecks detected.".to_string(),
1173            BottleneckType::Unknown => "Bottleneck analysis pending - insufficient data collected.".to_string(),
1174        }
1175    }
1176
1177    fn calculate_optimization_potential(&self, scores: &ComponentScores) -> f64 {
1178        let efficiency_scores = [
1179            scores.cpu_efficiency,
1180            scores.memory_efficiency,
1181            scores.io_efficiency,
1182            scores.network_efficiency,
1183            scores.resource_balance,
1184        ];
1185
1186        let min_score = efficiency_scores
1187            .iter()
1188            .copied()
1189            .fold(f64::INFINITY, f64::min);
1190        let max_score = efficiency_scores
1191            .iter()
1192            .copied()
1193            .fold(f64::NEG_INFINITY, f64::max);
1194
1195        // Optimization potential is based on the gap between worst and best performing areas
1196        ((max_score - min_score) * 100.0).min(50.0) // Cap at 50% potential improvement
1197    }
1198}
1199
1200impl Default for AsyncResourceMonitor {
1201    fn default() -> Self {
1202        Self::new()
1203    }
1204}
1205
1206fn current_timestamp_ms() -> u64 {
1207    use std::time::{SystemTime, UNIX_EPOCH};
1208    SystemTime::now()
1209        .duration_since(UNIX_EPOCH)
1210        .unwrap()
1211        .as_millis() as u64
1212}
1213
1214#[cfg(test)]
1215mod tests {
1216    use super::*;
1217
1218    #[test]
1219    fn test_resource_monitor_creation() {
1220        let monitor = AsyncResourceMonitor::new();
1221        assert!(monitor.profiles.is_empty());
1222    }
1223
1224    #[test]
1225    fn test_task_monitoring_lifecycle() {
1226        let mut monitor = AsyncResourceMonitor::new();
1227        let task_id = 1234;
1228
1229        monitor.start_monitoring(task_id, "test_task".to_string(), TaskType::CpuIntensive);
1230        assert!(monitor.profiles.contains_key(&task_id));
1231
1232        monitor.update_metrics(task_id);
1233        monitor.finish_monitoring(task_id);
1234
1235        let profile = monitor.get_profile(task_id).unwrap();
1236        assert!(profile.end_time.is_some());
1237        assert!(profile.duration_ms.is_some());
1238    }
1239
1240    #[test]
1241    fn test_efficiency_calculation() {
1242        let mut monitor = AsyncResourceMonitor::new();
1243        let task_id = 5678;
1244
1245        monitor.start_monitoring(task_id, "cpu_task".to_string(), TaskType::CpuIntensive);
1246        monitor.update_metrics(task_id);
1247
1248        let profile = monitor.get_profile(task_id).unwrap();
1249        assert!(profile.efficiency_score >= 0.0);
1250        assert!(profile.efficiency_score <= 1.0);
1251        assert!(profile.resource_balance >= 0.0);
1252        assert!(profile.resource_balance <= 1.0);
1253    }
1254}