Skip to main content

memscope_rs/capture/backends/
efficiency_scoring.rs

1//! Efficiency scoring for task-level memory profiling
2//!
3//! This module provides comprehensive efficiency scoring algorithms
4//! for different task types based on CPU, memory, IO, and network usage.
5
6use serde::{Deserialize, Serialize};
7
8/// Efficiency scoring configuration
9#[derive(Debug, Clone)]
10pub struct EfficiencyConfig {
11    /// Enable CPU efficiency calculation
12    pub enable_cpu_efficiency: bool,
13    /// Enable memory efficiency calculation
14    pub enable_memory_efficiency: bool,
15    /// Enable IO efficiency calculation
16    pub enable_io_efficiency: bool,
17    /// Enable network efficiency calculation
18    pub enable_network_efficiency: bool,
19    /// Custom weights for task types
20    pub custom_weights: Option<EfficiencyWeights>,
21}
22
23impl Default for EfficiencyConfig {
24    fn default() -> Self {
25        Self {
26            enable_cpu_efficiency: true,
27            enable_memory_efficiency: true,
28            enable_io_efficiency: true,
29            enable_network_efficiency: true,
30            custom_weights: None,
31        }
32    }
33}
34
35impl EfficiencyConfig {
36    /// Create configuration for minimal scoring
37    pub fn minimal() -> Self {
38        Self {
39            enable_cpu_efficiency: true,
40            enable_memory_efficiency: true,
41            enable_io_efficiency: false,
42            enable_network_efficiency: false,
43            custom_weights: None,
44        }
45    }
46
47    /// Create configuration for comprehensive scoring
48    pub fn comprehensive() -> Self {
49        Self {
50            enable_cpu_efficiency: true,
51            enable_memory_efficiency: true,
52            enable_io_efficiency: true,
53            enable_network_efficiency: true,
54            custom_weights: None,
55        }
56    }
57}
58
59/// Custom weights for different task types
60#[derive(Debug, Clone)]
61pub struct EfficiencyWeights {
62    /// CPU weight
63    pub cpu_weight: f64,
64    /// Memory weight
65    pub memory_weight: f64,
66    /// IO weight
67    pub io_weight: f64,
68    /// Network weight
69    pub network_weight: f64,
70}
71
72impl Default for EfficiencyWeights {
73    fn default() -> Self {
74        Self {
75            cpu_weight: 0.25,
76            memory_weight: 0.25,
77            io_weight: 0.25,
78            network_weight: 0.25,
79        }
80    }
81}
82
83/// Component efficiency scores
84#[derive(Debug, Clone, Serialize, Deserialize)]
85pub struct ComponentScores {
86    /// CPU efficiency score (0.0 to 1.0)
87    pub cpu_efficiency: f64,
88    /// Memory efficiency score (0.0 to 1.0)
89    pub memory_efficiency: f64,
90    /// IO efficiency score (0.0 to 1.0)
91    pub io_efficiency: f64,
92    /// Network efficiency score (0.0 to 1.0)
93    pub network_efficiency: f64,
94}
95
96impl Default for ComponentScores {
97    fn default() -> Self {
98        Self {
99            cpu_efficiency: 0.0,
100            memory_efficiency: 0.0,
101            io_efficiency: 0.0,
102            network_efficiency: 0.0,
103        }
104    }
105}
106
107impl ComponentScores {
108    /// Calculate overall efficiency score
109    pub fn overall(&self) -> f64 {
110        let sum = self.cpu_efficiency
111            + self.memory_efficiency
112            + self.io_efficiency
113            + self.network_efficiency;
114
115        let count = if self.cpu_efficiency > 0.0 { 1 } else { 0 }
116            + if self.memory_efficiency > 0.0 { 1 } else { 0 }
117            + if self.io_efficiency > 0.0 { 1 } else { 0 }
118            + if self.network_efficiency > 0.0 { 1 } else { 0 };
119
120        if count > 0 {
121            sum / count as f64
122        } else {
123            0.0
124        }
125    }
126}
127
128/// Efficiency scorer for task-level memory profiling
129pub struct EfficiencyScorer {
130    config: EfficiencyConfig,
131}
132
133impl EfficiencyScorer {
134    /// Create new efficiency scorer with default configuration
135    pub fn new() -> Self {
136        Self {
137            config: EfficiencyConfig::default(),
138        }
139    }
140
141    /// Create new efficiency scorer with custom configuration
142    pub fn with_config(config: EfficiencyConfig) -> Self {
143        Self { config }
144    }
145
146    /// Calculate efficiency score for a task profile
147    pub fn calculate_efficiency(
148        &self,
149        profile: &crate::capture::backends::task_profile::TaskMemoryProfile,
150        cpu_usage_percent: f64,
151        io_bytes_processed: u64,
152        network_bytes_transferred: u64,
153    ) -> ComponentScores {
154        let cpu_efficiency = if self.config.enable_cpu_efficiency {
155            self.calculate_cpu_efficiency(cpu_usage_percent)
156        } else {
157            0.0
158        };
159
160        let memory_efficiency = if self.config.enable_memory_efficiency {
161            self.calculate_memory_efficiency(profile)
162        } else {
163            0.0
164        };
165
166        let io_efficiency = if self.config.enable_io_efficiency {
167            self.calculate_io_efficiency(io_bytes_processed)
168        } else {
169            0.0
170        };
171
172        let network_efficiency = if self.config.enable_network_efficiency {
173            self.calculate_network_efficiency(network_bytes_transferred)
174        } else {
175            0.0
176        };
177
178        ComponentScores {
179            cpu_efficiency,
180            memory_efficiency,
181            io_efficiency,
182            network_efficiency,
183        }
184    }
185
186    /// Calculate CPU efficiency score
187    fn calculate_cpu_efficiency(&self, usage_percent: f64) -> f64 {
188        let usage = (usage_percent / 100.0).clamp(0.0, 1.0);
189
190        if usage <= 0.0 {
191            return 0.0;
192        }
193
194        let efficiency = if usage <= 0.5 {
195            usage * 2.0
196        } else if usage <= 0.8 {
197            0.5 + usage * 0.625
198        } else {
199            1.0
200        };
201
202        efficiency.clamp(0.0, 1.0)
203    }
204
205    /// Calculate memory efficiency score
206    fn calculate_memory_efficiency(
207        &self,
208        task_profile: &crate::capture::backends::task_profile::TaskMemoryProfile,
209    ) -> f64 {
210        if task_profile.total_bytes == 0 {
211            return 1.0;
212        }
213
214        let utilization = task_profile.current_memory as f64 / task_profile.total_bytes as f64;
215        let efficiency = 1.0 - utilization;
216
217        efficiency.clamp(0.0, 1.0)
218    }
219
220    /// Calculate IO efficiency score
221    fn calculate_io_efficiency(&self, bytes_processed: u64) -> f64 {
222        if bytes_processed == 0 {
223            return 0.0;
224        }
225
226        let optimal_size = 65536.0;
227        let efficiency = (bytes_processed as f64 / optimal_size).min(1.0);
228
229        efficiency.clamp(0.0, 1.0)
230    }
231
232    /// Calculate network efficiency score
233    fn calculate_network_efficiency(&self, bytes_transferred: u64) -> f64 {
234        if bytes_transferred == 0 {
235            return 0.0;
236        }
237
238        // Optimal network throughput threshold (1 MB)
239        let optimal_throughput = 1_048_576.0;
240        let efficiency = (bytes_transferred as f64 / optimal_throughput).min(1.0);
241
242        efficiency.clamp(0.0, 1.0)
243    }
244
245    /// Calculate weighted efficiency score based on task type
246    pub fn calculate_weighted_efficiency(
247        &self,
248        task_type: &crate::capture::backends::task_profile::TaskType,
249        component_scores: &ComponentScores,
250    ) -> f64 {
251        let weights = self.config.custom_weights.as_ref().map_or_else(
252            || Self::default_weights_for_task_type(task_type),
253            |w| w.clone(),
254        );
255
256        let weighted_score = component_scores.cpu_efficiency * weights.cpu_weight
257            + component_scores.memory_efficiency * weights.memory_weight
258            + component_scores.io_efficiency * weights.io_weight
259            + component_scores.network_efficiency * weights.network_weight;
260
261        weighted_score.clamp(0.0, 1.0)
262    }
263
264    /// Get default weights for a task type
265    fn default_weights_for_task_type(
266        task_type: &crate::capture::backends::task_profile::TaskType,
267    ) -> EfficiencyWeights {
268        match task_type {
269            crate::capture::backends::task_profile::TaskType::CpuIntensive => EfficiencyWeights {
270                cpu_weight: 0.6,
271                memory_weight: 0.2,
272                io_weight: 0.1,
273                network_weight: 0.1,
274            },
275            crate::capture::backends::task_profile::TaskType::IoIntensive => EfficiencyWeights {
276                cpu_weight: 0.2,
277                memory_weight: 0.1,
278                io_weight: 0.6,
279                network_weight: 0.1,
280            },
281            crate::capture::backends::task_profile::TaskType::NetworkIntensive => {
282                EfficiencyWeights {
283                    cpu_weight: 0.2,
284                    memory_weight: 0.1,
285                    io_weight: 0.1,
286                    network_weight: 0.6,
287                }
288            }
289            crate::capture::backends::task_profile::TaskType::MemoryIntensive => {
290                EfficiencyWeights {
291                    cpu_weight: 0.2,
292                    memory_weight: 0.6,
293                    io_weight: 0.1,
294                    network_weight: 0.1,
295                }
296            }
297            crate::capture::backends::task_profile::TaskType::GpuCompute => EfficiencyWeights {
298                cpu_weight: 0.5,
299                memory_weight: 0.2,
300                io_weight: 0.1,
301                network_weight: 0.2,
302            },
303            _ => EfficiencyWeights::default(),
304        }
305    }
306}
307
308impl Default for EfficiencyScorer {
309    fn default() -> Self {
310        Self::new()
311    }
312}
313
314#[cfg(test)]
315mod tests {
316    use super::*;
317
318    #[test]
319    fn test_efficiency_config_default() {
320        let config = EfficiencyConfig::default();
321        assert!(config.enable_cpu_efficiency);
322        assert!(config.enable_memory_efficiency);
323        assert!(config.enable_io_efficiency);
324        assert!(config.enable_network_efficiency);
325    }
326
327    #[test]
328    fn test_efficiency_config_minimal() {
329        let config = EfficiencyConfig::minimal();
330        assert!(config.enable_cpu_efficiency);
331        assert!(config.enable_memory_efficiency);
332        assert!(!config.enable_io_efficiency);
333        assert!(!config.enable_network_efficiency);
334    }
335
336    #[test]
337    fn test_task_type_weights_default() {
338        let weights = EfficiencyWeights::default();
339        assert_eq!(weights.cpu_weight, 0.25);
340        assert_eq!(weights.memory_weight, 0.25);
341        assert_eq!(weights.io_weight, 0.25);
342        assert_eq!(weights.network_weight, 0.25);
343    }
344
345    #[test]
346    fn test_component_scores_default() {
347        let scores = ComponentScores::default();
348        assert_eq!(scores.cpu_efficiency, 0.0);
349        assert_eq!(scores.memory_efficiency, 0.0);
350        assert_eq!(scores.io_efficiency, 0.0);
351        assert_eq!(scores.network_efficiency, 0.0);
352    }
353
354    #[test]
355    fn test_component_scores_overall() {
356        let scores = ComponentScores {
357            cpu_efficiency: 0.8,
358            memory_efficiency: 0.6,
359            io_efficiency: 0.4,
360            network_efficiency: 0.2,
361        };
362
363        let overall = scores.overall();
364        assert!(
365            (overall - 0.5).abs() < f64::EPSILON,
366            "Expected overall score to be 0.5, got {}",
367            overall
368        );
369    }
370
371    #[test]
372    fn test_cpu_efficiency_calculation() {
373        let scorer = EfficiencyScorer::new();
374
375        let efficiency = scorer.calculate_cpu_efficiency(0.0);
376        assert_eq!(efficiency, 0.0);
377
378        let efficiency = scorer.calculate_cpu_efficiency(50.0);
379        assert_eq!(efficiency, 1.0);
380
381        let efficiency = scorer.calculate_cpu_efficiency(100.0);
382        assert_eq!(efficiency, 1.0);
383    }
384
385    #[test]
386    fn test_memory_efficiency_calculation() {
387        let scorer = EfficiencyScorer::new();
388
389        let mut profile = crate::capture::backends::task_profile::TaskMemoryProfile::new(
390            1,
391            "test".to_string(),
392            crate::capture::backends::task_profile::TaskType::default(),
393        );
394
395        let efficiency = scorer.calculate_memory_efficiency(&profile);
396        assert_eq!(efficiency, 1.0);
397
398        profile.total_bytes = 1000;
399        profile.current_memory = 500;
400        let efficiency = scorer.calculate_memory_efficiency(&profile);
401        assert_eq!(efficiency, 0.5);
402    }
403
404    #[test]
405    fn test_io_efficiency_calculation() {
406        let scorer = EfficiencyScorer::new();
407
408        let efficiency = scorer.calculate_io_efficiency(0);
409        assert_eq!(efficiency, 0.0);
410
411        let efficiency = scorer.calculate_io_efficiency(65536);
412        assert_eq!(efficiency, 1.0);
413    }
414
415    #[test]
416    fn test_network_efficiency_calculation() {
417        let scorer = EfficiencyScorer::new();
418
419        let efficiency = scorer.calculate_network_efficiency(0);
420        assert_eq!(efficiency, 0.0);
421
422        let efficiency = scorer.calculate_network_efficiency(1_048_576); // 1 MB
423        assert!((efficiency - 1.0).abs() < f64::EPSILON);
424    }
425
426    #[test]
427    fn test_weighted_efficiency_cpu_intensive() {
428        let scorer = EfficiencyScorer::new();
429
430        let task_type = crate::capture::backends::task_profile::TaskType::CpuIntensive;
431        let component_scores = ComponentScores {
432            cpu_efficiency: 0.8,
433            memory_efficiency: 0.6,
434            io_efficiency: 0.4,
435            network_efficiency: 0.2,
436        };
437
438        let weighted = scorer.calculate_weighted_efficiency(&task_type, &component_scores);
439        assert!((weighted - 0.66).abs() < f64::EPSILON);
440    }
441
442    #[test]
443    fn test_weighted_efficiency_io_intensive() {
444        let scorer = EfficiencyScorer::new();
445
446        let task_type = crate::capture::backends::task_profile::TaskType::IoIntensive;
447        let component_scores = ComponentScores {
448            cpu_efficiency: 0.6,
449            memory_efficiency: 0.4,
450            io_efficiency: 0.8,
451            network_efficiency: 0.2,
452        };
453
454        let weighted = scorer.calculate_weighted_efficiency(&task_type, &component_scores);
455        // IOIntensive weights: cpu=0.2, memory=0.1, io=0.6, network=0.1
456        // 0.6*0.2 + 0.4*0.1 + 0.8*0.6 + 0.2*0.1 = 0.12 + 0.04 + 0.48 + 0.02 = 0.66
457        assert!((weighted - 0.66).abs() < f64::EPSILON);
458    }
459
460    #[test]
461    fn test_weighted_efficiency_memory_intensive() {
462        let scorer = EfficiencyScorer::new();
463
464        let task_type = crate::capture::backends::task_profile::TaskType::MemoryIntensive;
465        let component_scores = ComponentScores {
466            cpu_efficiency: 0.6,
467            memory_efficiency: 0.8,
468            io_efficiency: 0.4,
469            network_efficiency: 0.2,
470        };
471
472        let weighted = scorer.calculate_weighted_efficiency(&task_type, &component_scores);
473        // MemoryIntensive weights: cpu=0.2, memory=0.6, io=0.1, network=0.1
474        // 0.6*0.2 + 0.8*0.6 + 0.4*0.1 + 0.2*0.1 = 0.12 + 0.48 + 0.04 + 0.02 = 0.66
475        assert!((weighted - 0.66).abs() < f64::EPSILON);
476    }
477
478    #[test]
479    fn test_weighted_efficiency_network_intensive() {
480        let scorer = EfficiencyScorer::new();
481
482        let task_type = crate::capture::backends::task_profile::TaskType::NetworkIntensive;
483        let component_scores = ComponentScores {
484            cpu_efficiency: 0.6,
485            memory_efficiency: 0.4,
486            io_efficiency: 0.2,
487            network_efficiency: 0.8,
488        };
489
490        let weighted = scorer.calculate_weighted_efficiency(&task_type, &component_scores);
491        // NetworkIntensive weights: cpu=0.2, memory=0.1, io=0.1, network=0.6
492        // 0.6*0.2 + 0.4*0.1 + 0.2*0.1 + 0.8*0.6 = 0.12 + 0.04 + 0.02 + 0.48 = 0.66
493        assert!((weighted - 0.66).abs() < f64::EPSILON);
494    }
495}