eryon_rt/types/
performance.rs

1/*
2    Appellation: performance <module>
3    Contrib: @FL03
4*/
5use crate::types::ResourceMetrics;
6use num_traits::{FromPrimitive, Num};
7use scsys::Timestamp;
8use std::collections::{HashMap, VecDeque};
9
10/// Maximum number of historical metrics to keep
11const MAX_HISTORY_LENGTH: usize = 100;
12
13/// Tracks performance metrics over time to identify trends
14#[doc(hidden)]
15#[derive(Clone, Debug, Default)]
16pub struct PerformanceTracker<T = f32> {
17    // Time series of system metrics
18    metrics_history: VecDeque<(Timestamp<u64>, ResourceMetrics<T>)>,
19    // Time series of specific performance indicators
20    indicators: HashMap<String, VecDeque<(Timestamp<u64>, T)>>,
21    // Event log for significant performance events
22    events: VecDeque<(Timestamp<u64>, String, Option<T>)>,
23}
24
25impl<T> PerformanceTracker<T> {
26    /// Create a new performance tracker
27    pub fn new() -> Self
28    where
29        T: Default,
30    {
31        Self::default()
32    }
33
34    /// Record a new set of metrics
35    pub fn record_metrics(&mut self, metrics: ResourceMetrics<T>)
36    where
37        T: Clone + FromPrimitive,
38    {
39        let timestamp = Timestamp::<u64>::now();
40
41        // Add to history
42        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        // Extract key indicators
49        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    /// Record an individual indicator
56    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    /// Record a significant performance event
66    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    /// Get the trend for a specific indicator
76    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        // Calculate simple linear trend
86        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    /// Get the full history of an indicator
92    pub fn get_indicator_history(&self, indicator: &str) -> Option<&VecDeque<(Timestamp<u64>, T)>> {
93        self.indicators.get(indicator)
94    }
95
96    /// Get the most recent metrics
97    pub fn latest_metrics(&self) -> Option<&ResourceMetrics<T>> {
98        self.metrics_history.back().map(|(_, metrics)| metrics)
99    }
100
101    /// Get recent performance events
102    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    /// Generate a performance trend report
110    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}