eryon_rt/types/
performance.rs1use crate::types::ResourceMetrics;
6use num_traits::{FromPrimitive, Num};
7use scsys::Timestamp;
8use std::collections::{HashMap, VecDeque};
9
10const MAX_HISTORY_LENGTH: usize = 100;
12
13#[doc(hidden)]
15#[derive(Clone, Debug, Default)]
16pub struct PerformanceTracker<T = f32> {
17 metrics_history: VecDeque<(Timestamp<u64>, ResourceMetrics<T>)>,
19 indicators: HashMap<String, VecDeque<(Timestamp<u64>, T)>>,
21 events: VecDeque<(Timestamp<u64>, String, Option<T>)>,
23}
24
25impl<T> PerformanceTracker<T> {
26 pub fn new() -> Self
28 where
29 T: Default,
30 {
31 Self::default()
32 }
33
34 pub fn record_metrics(&mut self, metrics: ResourceMetrics<T>)
36 where
37 T: Clone + FromPrimitive,
38 {
39 let timestamp = Timestamp::<u64>::now();
40
41 self.metrics_history.push_back((timestamp, metrics.clone()));
43 if self.metrics_history.len() > MAX_HISTORY_LENGTH {
44 self.metrics_history.pop_front();
45 }
46 let queued = T::from_usize(metrics.queued_tasks()).unwrap();
47 let learning = T::from_usize(metrics.learning_nodes()).unwrap();
48 self.record_indicator("cpu_usage", timestamp, metrics.cpu_usage().clone());
50 self.record_indicator("memory_usage", timestamp, metrics.memory_usage().clone());
51 self.record_indicator("task_backlog", timestamp, queued);
52 self.record_indicator("learning_nodes", timestamp, learning);
53 }
54
55 pub fn record_indicator(&mut self, name: &str, timestamp: Timestamp<u64>, value: T) {
57 let entry = self.indicators.entry(name.to_string()).or_default();
58 entry.push_back((timestamp, value));
59
60 if entry.len() > MAX_HISTORY_LENGTH {
61 entry.pop_front();
62 }
63 }
64
65 pub fn record_event(&mut self, event: &str, value: Option<T>) {
67 let timestamp = Timestamp::<u64>::now();
68 self.events.push_back((timestamp, event.to_string(), value));
69
70 if self.events.len() > MAX_HISTORY_LENGTH {
71 self.events.pop_front();
72 }
73 }
74
75 pub fn get_trend(&self, indicator: &str) -> Option<T>
77 where
78 T: Copy + FromPrimitive + Num,
79 {
80 let values = self.indicators.get(indicator)?;
81 if values.len() < 3 {
82 return None;
83 }
84
85 let recent = values.iter().rev().take(3).collect::<Vec<_>>();
87 let trend = (recent[0].1 - recent[2].1) / T::from_usize(2).unwrap();
88 Some(trend)
89 }
90
91 pub fn get_indicator_history(&self, indicator: &str) -> Option<&VecDeque<(Timestamp<u64>, T)>> {
93 self.indicators.get(indicator)
94 }
95
96 pub fn latest_metrics(&self) -> Option<&ResourceMetrics<T>> {
98 self.metrics_history.back().map(|(_, metrics)| metrics)
99 }
100
101 pub fn recent_events(&self, count: usize) -> Vec<(Timestamp<u64>, String, Option<T>)>
103 where
104 T: Clone,
105 {
106 self.events.iter().rev().take(count).cloned().collect()
107 }
108
109 pub fn generate_trend_report(&self) -> String
111 where
112 T: Copy
113 + FromPrimitive
114 + Num
115 + PartialOrd
116 + core::fmt::Display
117 + core::ops::Neg<Output = T>,
118 {
119 let mut report = String::new();
120 report.push_str("PERFORMANCE TRENDS\n");
121 report.push_str("-----------------\n");
122
123 let limit = T::from_f32(0.05).unwrap();
124
125 for indicator in [
126 "cpu_usage",
127 "memory_usage",
128 "task_backlog",
129 "learning_nodes",
130 ] {
131 if let Some(trend) = self.get_trend(indicator) {
132 let direction = if trend > limit {
133 "INCREASING"
134 } else if trend < -limit {
135 "DECREASING"
136 } else {
137 "STABLE"
138 };
139
140 report.push_str(&format!("{}: {} ({:+.2})\n", indicator, direction, trend));
141 }
142 }
143
144 report
145 }
146}