1use serde::{Deserialize, Serialize};
7
8#[derive(Debug, Clone, Serialize, Deserialize)]
10pub struct ResourceRanking {
11 pub task_id: u64,
13 pub task_name: String,
15 pub task_type: String,
17 pub cpu_usage: f64,
19 pub memory_usage_mb: f64,
21 pub io_usage_mb: f64,
23 pub network_usage_mb: f64,
25 pub gpu_usage: f64,
27 pub overall_score: f64,
29 pub efficiency_scores: EfficiencyScores,
31 pub recommendations: Vec<String>,
33}
34
35#[derive(Debug, Clone, Serialize, Deserialize)]
37pub struct EfficiencyScores {
38 pub cpu_efficiency: f64,
40 pub memory_efficiency: f64,
42 pub io_efficiency: f64,
44 pub network_efficiency: f64,
46 pub gpu_efficiency: f64,
48}
49
50#[derive(Debug, Clone, Serialize, Deserialize)]
55pub struct TaskResourceMetrics {
56 pub task_id: u64,
58 pub task_name: String,
60 pub task_type: String,
72 pub cpu_usage: f64,
74 pub memory_usage_mb: f64,
76 pub io_usage_mb: f64,
78 pub network_usage_mb: f64,
80 pub gpu_usage: f64,
82}
83
84struct ResourceUsage {
86 cpu: f64,
87 memory: f64,
88 io: f64,
89 network: f64,
90 gpu: f64,
91}
92
93impl EfficiencyScores {
94 pub fn new(cpu: f64, memory: f64, io: f64, network: f64, gpu: f64) -> Self {
96 Self {
97 cpu_efficiency: cpu,
98 memory_efficiency: memory,
99 io_efficiency: io,
100 network_efficiency: network,
101 gpu_efficiency: gpu,
102 }
103 }
104
105 pub fn overall_score(&self, config: &RankingConfig) -> f64 {
107 let weighted_sum = self.cpu_efficiency * config.cpu_weight
108 + self.memory_efficiency * config.memory_weight
109 + self.io_efficiency * config.io_weight
110 + self.network_efficiency * config.network_weight
111 + self.gpu_efficiency * config.gpu_weight;
112
113 let total_weight = config.cpu_weight
114 + config.memory_weight
115 + config.io_weight
116 + config.network_weight
117 + config.gpu_weight;
118
119 if total_weight <= 0.0 {
120 0.0
121 } else {
122 weighted_sum / total_weight
123 }
124 }
125}
126
127#[derive(Debug, Clone, Serialize, Deserialize)]
129pub struct RankingConfig {
130 pub cpu_weight: f64,
132 pub memory_weight: f64,
134 pub io_weight: f64,
136 pub network_weight: f64,
138 pub gpu_weight: f64,
140 pub enable_recommendations: bool,
142 pub min_efficiency_threshold: f64,
144}
145
146impl Default for RankingConfig {
147 fn default() -> Self {
148 Self {
149 cpu_weight: 0.3,
150 memory_weight: 0.3,
151 io_weight: 0.2,
152 network_weight: 0.1,
153 gpu_weight: 0.1,
154 enable_recommendations: true,
155 min_efficiency_threshold: 0.6,
156 }
157 }
158}
159
160pub struct ResourceRankingAnalyzer {
162 config: RankingConfig,
163 rankings: Vec<ResourceRanking>,
164}
165
166impl ResourceRankingAnalyzer {
167 pub fn new() -> Self {
169 Self {
170 config: RankingConfig::default(),
171 rankings: Vec::new(),
172 }
173 }
174
175 pub fn with_config(config: RankingConfig) -> Self {
177 Self {
178 config,
179 rankings: Vec::new(),
180 }
181 }
182
183 pub fn analyze_task(&mut self, metrics: &TaskResourceMetrics) -> ResourceRanking {
185 let efficiency_scores = EfficiencyScores::new(
186 self.calculate_cpu_efficiency(metrics.cpu_usage),
187 self.calculate_memory_efficiency(metrics.memory_usage_mb),
188 self.calculate_io_efficiency(metrics.io_usage_mb),
189 self.calculate_network_efficiency(metrics.network_usage_mb),
190 self.calculate_gpu_efficiency(metrics.gpu_usage),
191 );
192
193 let overall_score = self.calculate_overall_score(
194 metrics.cpu_usage,
195 metrics.memory_usage_mb,
196 metrics.io_usage_mb,
197 metrics.network_usage_mb,
198 metrics.gpu_usage,
199 );
200
201 let recommendations = if self.config.enable_recommendations {
202 self.generate_recommendations(
203 &efficiency_scores,
204 overall_score,
205 ResourceUsage {
206 cpu: metrics.cpu_usage,
207 memory: metrics.memory_usage_mb,
208 io: metrics.io_usage_mb,
209 network: metrics.network_usage_mb,
210 gpu: metrics.gpu_usage,
211 },
212 )
213 } else {
214 Vec::new()
215 };
216
217 let ranking = ResourceRanking {
218 task_id: metrics.task_id,
219 task_name: metrics.task_name.clone(),
220 task_type: metrics.task_type.clone(),
221 cpu_usage: metrics.cpu_usage,
222 memory_usage_mb: metrics.memory_usage_mb,
223 io_usage_mb: metrics.io_usage_mb,
224 network_usage_mb: metrics.network_usage_mb,
225 gpu_usage: metrics.gpu_usage,
226 overall_score,
227 efficiency_scores,
228 recommendations,
229 };
230
231 self.rankings.push(ranking.clone());
232 ranking
233 }
234
235 fn calculate_cpu_efficiency(&self, cpu_usage: f64) -> f64 {
237 if cpu_usage <= 0.0 {
238 return 0.0;
239 }
240
241 if cpu_usage <= 50.0 {
242 1.0
243 } else if cpu_usage <= 75.0 {
244 0.8
245 } else if cpu_usage <= 90.0 {
246 0.6
247 } else {
248 0.4
249 }
250 }
251
252 fn calculate_memory_efficiency(&self, memory_mb: f64) -> f64 {
254 if memory_mb <= 0.0 {
255 return 0.0;
256 }
257
258 if memory_mb <= 100.0 {
259 1.0
260 } else if memory_mb <= 500.0 {
261 0.8
262 } else if memory_mb <= 1000.0 {
263 0.6
264 } else {
265 0.4
266 }
267 }
268
269 fn calculate_io_efficiency(&self, io_mb: f64) -> f64 {
271 if io_mb <= 0.0 {
272 return 0.0;
273 }
274
275 if io_mb <= 10.0 {
276 1.0
277 } else if io_mb <= 100.0 {
278 0.8
279 } else if io_mb <= 500.0 {
280 0.6
281 } else {
282 0.4
283 }
284 }
285
286 fn calculate_network_efficiency(&self, network_mb: f64) -> f64 {
288 if network_mb <= 0.0 {
289 return 0.0;
290 }
291
292 if network_mb <= 10.0 {
293 1.0
294 } else if network_mb <= 100.0 {
295 0.8
296 } else if network_mb <= 500.0 {
297 0.6
298 } else {
299 0.4
300 }
301 }
302
303 fn calculate_gpu_efficiency(&self, gpu_usage: f64) -> f64 {
305 if gpu_usage <= 0.0 {
306 return 0.0;
307 }
308
309 if gpu_usage <= 50.0 {
310 1.0
311 } else if gpu_usage <= 75.0 {
312 0.8
313 } else if gpu_usage <= 90.0 {
314 0.6
315 } else {
316 0.4
317 }
318 }
319
320 fn calculate_overall_score(
322 &self,
323 cpu_usage: f64,
324 memory_mb: f64,
325 io_mb: f64,
326 network_mb: f64,
327 gpu_usage: f64,
328 ) -> f64 {
329 let cpu_score = self.calculate_cpu_efficiency(cpu_usage);
330 let memory_score = self.calculate_memory_efficiency(memory_mb);
331 let io_score = self.calculate_io_efficiency(io_mb);
332 let network_score = self.calculate_network_efficiency(network_mb);
333 let gpu_score = self.calculate_gpu_efficiency(gpu_usage);
334
335 let weighted_sum = cpu_score * self.config.cpu_weight
336 + memory_score * self.config.memory_weight
337 + io_score * self.config.io_weight
338 + network_score * self.config.network_weight
339 + gpu_score * self.config.gpu_weight;
340
341 let total_weight = self.config.cpu_weight
342 + self.config.memory_weight
343 + self.config.io_weight
344 + self.config.network_weight
345 + self.config.gpu_weight;
346
347 weighted_sum / total_weight
348 }
349
350 fn generate_recommendations(
352 &self,
353 efficiency: &EfficiencyScores,
354 overall_score: f64,
355 usage: ResourceUsage,
356 ) -> Vec<String> {
357 let mut recommendations = Vec::new();
358
359 if overall_score < self.config.min_efficiency_threshold {
360 recommendations.push(
361 "Overall efficiency is below threshold. Consider reviewing resource usage patterns.".to_string()
362 );
363 }
364
365 if efficiency.cpu_efficiency < 0.6 {
366 if usage.cpu > 90.0 {
367 recommendations.push(
368 "CPU usage is critical (>90%). Consider parallelizing work or optimizing algorithms.".to_string()
369 );
370 } else if usage.cpu > 75.0 {
371 recommendations.push(
372 "CPU usage is high (>75%). Profile hot paths and optimize critical sections."
373 .to_string(),
374 );
375 }
376 }
377
378 if efficiency.memory_efficiency < 0.6 {
379 if usage.memory > 1000.0 {
380 recommendations.push(
381 "Memory usage is high (>1GB). Implement memory pooling or reduce footprint."
382 .to_string(),
383 );
384 } else if usage.memory > 500.0 {
385 recommendations.push(
386 "Memory usage is moderate (>500MB). Consider optimizing data structures."
387 .to_string(),
388 );
389 }
390 }
391
392 if efficiency.io_efficiency < 0.6 {
393 if usage.io > 500.0 {
394 recommendations.push(
395 "I/O usage is high (>500MB). Implement buffering or async I/O.".to_string(),
396 );
397 } else if usage.io > 100.0 {
398 recommendations.push(
399 "I/O usage is moderate (>100MB). Consider batching operations.".to_string(),
400 );
401 }
402 }
403
404 if efficiency.network_efficiency < 0.6 {
405 if usage.network > 500.0 {
406 recommendations.push(
407 "Network usage is high (>500MB). Implement compression or connection pooling."
408 .to_string(),
409 );
410 } else if usage.network > 100.0 {
411 recommendations.push(
412 "Network usage is moderate (>100MB). Consider caching or batching requests."
413 .to_string(),
414 );
415 }
416 }
417
418 if efficiency.gpu_efficiency < 0.6 {
419 if usage.gpu > 90.0 {
420 recommendations.push(
421 "GPU usage is critical (>90%). Optimize kernel execution or reduce workload."
422 .to_string(),
423 );
424 } else if usage.gpu > 75.0 {
425 recommendations.push(
426 "GPU usage is high (>75%). Review compute kernel efficiency.".to_string(),
427 );
428 }
429 }
430
431 recommendations
432 }
433
434 pub fn get_rankings(&self) -> Vec<&ResourceRanking> {
436 let mut rankings: Vec<&ResourceRanking> = self.rankings.iter().collect();
437 rankings.sort_by(|a, b| {
438 b.overall_score
439 .partial_cmp(&a.overall_score)
440 .unwrap_or(std::cmp::Ordering::Equal)
441 });
442 rankings
443 }
444
445 pub fn get_top_rankings(&self, n: usize) -> Vec<&ResourceRanking> {
447 let mut rankings = self.get_rankings();
448 rankings.truncate(n);
449 rankings
450 }
451
452 pub fn get_bottom_rankings(&self, n: usize) -> Vec<&ResourceRanking> {
454 let mut rankings: Vec<&ResourceRanking> = self.rankings.iter().collect();
455 rankings.sort_by(|a, b| {
456 a.overall_score
457 .partial_cmp(&b.overall_score)
458 .unwrap_or(std::cmp::Ordering::Equal)
459 });
460 rankings.truncate(n);
461 rankings
462 }
463
464 pub fn get_rankings_by_type(&self, task_type: &str) -> Vec<&ResourceRanking> {
466 self.rankings
467 .iter()
468 .filter(|r| r.task_type == task_type)
469 .collect()
470 }
471
472 pub fn config(&self) -> &RankingConfig {
474 &self.config
475 }
476
477 pub fn set_config(&mut self, config: RankingConfig) {
479 self.config = config;
480 }
481
482 pub fn clear(&mut self) {
484 self.rankings.clear();
485 }
486
487 pub fn get_statistics(&self) -> RankingStatistics {
489 if self.rankings.is_empty() {
490 return RankingStatistics::default();
491 }
492
493 let overall_scores: Vec<f64> = self.rankings.iter().map(|r| r.overall_score).collect();
494 let avg_score = overall_scores.iter().sum::<f64>() / overall_scores.len() as f64;
495 let max_score = overall_scores
496 .iter()
497 .cloned()
498 .fold(f64::NEG_INFINITY, f64::max);
499 let min_score = overall_scores.iter().cloned().fold(f64::INFINITY, f64::min);
500
501 let cpu_scores: Vec<f64> = self
502 .rankings
503 .iter()
504 .map(|r| r.efficiency_scores.cpu_efficiency)
505 .collect();
506 let avg_cpu = cpu_scores.iter().sum::<f64>() / cpu_scores.len() as f64;
507
508 let memory_scores: Vec<f64> = self
509 .rankings
510 .iter()
511 .map(|r| r.efficiency_scores.memory_efficiency)
512 .collect();
513 let avg_memory = memory_scores.iter().sum::<f64>() / memory_scores.len() as f64;
514
515 RankingStatistics {
516 total_tasks: self.rankings.len(),
517 average_overall_score: avg_score,
518 max_overall_score: max_score,
519 min_overall_score: min_score,
520 average_cpu_efficiency: avg_cpu,
521 average_memory_efficiency: avg_memory,
522 }
523 }
524}
525
526impl Default for ResourceRankingAnalyzer {
527 fn default() -> Self {
528 Self::new()
529 }
530}
531
532#[derive(Debug, Clone, Serialize, Deserialize)]
534pub struct RankingStatistics {
535 pub total_tasks: usize,
537 pub average_overall_score: f64,
539 pub max_overall_score: f64,
541 pub min_overall_score: f64,
543 pub average_cpu_efficiency: f64,
545 pub average_memory_efficiency: f64,
547}
548
549impl Default for RankingStatistics {
550 fn default() -> Self {
551 Self {
552 total_tasks: 0,
553 average_overall_score: 0.0,
554 max_overall_score: 0.0,
555 min_overall_score: 0.0,
556 average_cpu_efficiency: 0.0,
557 average_memory_efficiency: 0.0,
558 }
559 }
560}
561
562#[cfg(test)]
563mod tests {
564 use super::*;
565
566 #[test]
567 fn test_efficiency_scores_creation() {
568 let scores = EfficiencyScores::new(0.8, 0.7, 0.9, 0.6, 0.5);
569 assert_eq!(scores.cpu_efficiency, 0.8);
570 assert_eq!(scores.memory_efficiency, 0.7);
571 assert_eq!(scores.io_efficiency, 0.9);
572 assert_eq!(scores.network_efficiency, 0.6);
573 assert_eq!(scores.gpu_efficiency, 0.5);
574 }
575
576 #[test]
577 fn test_efficiency_scores_overall() {
578 let scores = EfficiencyScores::new(0.8, 0.7, 0.9, 0.6, 0.5);
579 let config = RankingConfig::default();
580 let overall = scores.overall_score(&config);
581 let expected = (0.8 * 0.3 + 0.7 * 0.3 + 0.9 * 0.2 + 0.6 * 0.1 + 0.5 * 0.1) / 1.0;
582 assert!((overall - expected).abs() < 0.01);
583 }
584
585 #[test]
586 fn test_resource_ranking_analyzer_creation() {
587 let analyzer = ResourceRankingAnalyzer::new();
588 assert!(analyzer.rankings.is_empty());
589 }
590
591 #[test]
592 fn test_analyze_task() {
593 let mut analyzer = ResourceRankingAnalyzer::new();
594 let metrics = TaskResourceMetrics {
595 task_id: 1,
596 task_name: "test_task".to_string(),
597 task_type: "CpuIntensive".to_string(),
598 cpu_usage: 60.0,
599 memory_usage_mb: 200.0,
600 io_usage_mb: 50.0,
601 network_usage_mb: 30.0,
602 gpu_usage: 40.0,
603 };
604 let ranking = analyzer.analyze_task(&metrics);
605
606 assert_eq!(ranking.task_id, 1);
607 assert_eq!(ranking.task_name, "test_task");
608 assert!(ranking.overall_score > 0.0);
609 }
610
611 #[test]
612 fn test_get_rankings() {
613 let mut analyzer = ResourceRankingAnalyzer::new();
614 let metrics1 = TaskResourceMetrics {
615 task_id: 1,
616 task_name: "task1".to_string(),
617 task_type: "CpuIntensive".to_string(),
618 cpu_usage: 80.0,
619 memory_usage_mb: 200.0,
620 io_usage_mb: 50.0,
621 network_usage_mb: 30.0,
622 gpu_usage: 40.0,
623 };
624 let metrics2 = TaskResourceMetrics {
625 task_id: 2,
626 task_name: "task2".to_string(),
627 task_type: "CpuIntensive".to_string(),
628 cpu_usage: 40.0,
629 memory_usage_mb: 100.0,
630 io_usage_mb: 30.0,
631 network_usage_mb: 20.0,
632 gpu_usage: 30.0,
633 };
634 analyzer.analyze_task(&metrics1);
635 analyzer.analyze_task(&metrics2);
636
637 let rankings = analyzer.get_rankings();
638 assert_eq!(rankings.len(), 2);
639 assert!(rankings[0].overall_score >= rankings[1].overall_score);
640 }
641
642 #[test]
643 fn test_get_top_rankings() {
644 let mut analyzer = ResourceRankingAnalyzer::new();
645 let metrics1 = TaskResourceMetrics {
646 task_id: 1,
647 task_name: "task1".to_string(),
648 task_type: "CpuIntensive".to_string(),
649 cpu_usage: 80.0,
650 memory_usage_mb: 200.0,
651 io_usage_mb: 50.0,
652 network_usage_mb: 30.0,
653 gpu_usage: 40.0,
654 };
655 let metrics2 = TaskResourceMetrics {
656 task_id: 2,
657 task_name: "task2".to_string(),
658 task_type: "CpuIntensive".to_string(),
659 cpu_usage: 40.0,
660 memory_usage_mb: 100.0,
661 io_usage_mb: 30.0,
662 network_usage_mb: 20.0,
663 gpu_usage: 30.0,
664 };
665 let metrics3 = TaskResourceMetrics {
666 task_id: 3,
667 task_name: "task3".to_string(),
668 task_type: "CpuIntensive".to_string(),
669 cpu_usage: 60.0,
670 memory_usage_mb: 150.0,
671 io_usage_mb: 40.0,
672 network_usage_mb: 25.0,
673 gpu_usage: 35.0,
674 };
675 analyzer.analyze_task(&metrics1);
676 analyzer.analyze_task(&metrics2);
677 analyzer.analyze_task(&metrics3);
678
679 let top = analyzer.get_top_rankings(2);
680 assert_eq!(top.len(), 2);
681 }
682
683 #[test]
684 fn test_get_rankings_by_type() {
685 let mut analyzer = ResourceRankingAnalyzer::new();
686 let metrics1 = TaskResourceMetrics {
687 task_id: 1,
688 task_name: "task1".to_string(),
689 task_type: "CpuIntensive".to_string(),
690 cpu_usage: 60.0,
691 memory_usage_mb: 200.0,
692 io_usage_mb: 50.0,
693 network_usage_mb: 30.0,
694 gpu_usage: 40.0,
695 };
696 let metrics2 = TaskResourceMetrics {
697 task_id: 2,
698 task_name: "task2".to_string(),
699 task_type: "IoIntensive".to_string(),
700 cpu_usage: 40.0,
701 memory_usage_mb: 100.0,
702 io_usage_mb: 80.0,
703 network_usage_mb: 20.0,
704 gpu_usage: 30.0,
705 };
706 analyzer.analyze_task(&metrics1);
707 analyzer.analyze_task(&metrics2);
708
709 let cpu_rankings = analyzer.get_rankings_by_type("CpuIntensive");
710 assert_eq!(cpu_rankings.len(), 1);
711 }
712
713 #[test]
714 fn test_custom_config() {
715 let config = RankingConfig {
716 cpu_weight: 0.5,
717 memory_weight: 0.3,
718 io_weight: 0.1,
719 network_weight: 0.05,
720 gpu_weight: 0.05,
721 ..Default::default()
722 };
723 let analyzer = ResourceRankingAnalyzer::with_config(config);
724
725 assert_eq!(analyzer.config().cpu_weight, 0.5);
726 assert_eq!(analyzer.config().memory_weight, 0.3);
727 }
728
729 #[test]
730 fn test_clear() {
731 let mut analyzer = ResourceRankingAnalyzer::new();
732 let metrics = TaskResourceMetrics {
733 task_id: 1,
734 task_name: "task1".to_string(),
735 task_type: "CpuIntensive".to_string(),
736 cpu_usage: 60.0,
737 memory_usage_mb: 200.0,
738 io_usage_mb: 50.0,
739 network_usage_mb: 30.0,
740 gpu_usage: 40.0,
741 };
742 analyzer.analyze_task(&metrics);
743 analyzer.clear();
744
745 assert!(analyzer.rankings.is_empty());
746 }
747
748 #[test]
749 fn test_get_statistics() {
750 let mut analyzer = ResourceRankingAnalyzer::new();
751 let metrics1 = TaskResourceMetrics {
752 task_id: 1,
753 task_name: "task1".to_string(),
754 task_type: "CpuIntensive".to_string(),
755 cpu_usage: 60.0,
756 memory_usage_mb: 200.0,
757 io_usage_mb: 50.0,
758 network_usage_mb: 30.0,
759 gpu_usage: 40.0,
760 };
761 let metrics2 = TaskResourceMetrics {
762 task_id: 2,
763 task_name: "task2".to_string(),
764 task_type: "CpuIntensive".to_string(),
765 cpu_usage: 40.0,
766 memory_usage_mb: 100.0,
767 io_usage_mb: 30.0,
768 network_usage_mb: 20.0,
769 gpu_usage: 30.0,
770 };
771 analyzer.analyze_task(&metrics1);
772 analyzer.analyze_task(&metrics2);
773
774 let stats = analyzer.get_statistics();
775 assert_eq!(stats.total_tasks, 2);
776 assert!(stats.average_overall_score > 0.0);
777 }
778
779 #[test]
780 fn test_recommendations_generation() {
781 let mut analyzer = ResourceRankingAnalyzer::new();
782 let metrics = TaskResourceMetrics {
783 task_id: 1,
784 task_name: "test_task".to_string(),
785 task_type: "CpuIntensive".to_string(),
786 cpu_usage: 95.0,
787 memory_usage_mb: 1200.0,
788 io_usage_mb: 600.0,
789 network_usage_mb: 600.0,
790 gpu_usage: 95.0,
791 };
792 let ranking = analyzer.analyze_task(&metrics);
793
794 assert!(!ranking.recommendations.is_empty());
795 }
796}