1use serde::{Deserialize, Serialize};
6use std::collections::HashMap;
7use std::time::Duration;
8
9#[derive(Debug, Clone, Serialize, Deserialize)]
11pub struct PlatformResourceMetrics {
12 pub timestamp: u64,
13 pub cpu_metrics: CpuResourceMetrics,
14 pub gpu_metrics: Option<GpuResourceMetrics>, pub io_metrics: IoResourceMetrics, pub thread_metrics: HashMap<u64, ThreadResourceMetrics>,
17}
18
19#[derive(Debug, Clone, Serialize, Deserialize)]
21pub struct CpuResourceMetrics {
22 pub overall_usage_percent: f32,
23 pub per_core_usage: Vec<f32>,
24 pub frequency_mhz: Vec<u32>,
25 pub temperature_celsius: Vec<f32>,
26 pub context_switches_per_sec: u64,
27 pub interrupts_per_sec: u64,
28 pub load_average: (f64, f64, f64), }
30
31#[derive(Debug, Clone, Serialize, Deserialize)]
33pub struct GpuResourceMetrics {
34 pub device_name: String,
35 pub vendor: GpuVendor,
36 pub compute_usage_percent: f32,
37 pub memory_usage_percent: f32,
38 pub memory_used_bytes: u64,
39 pub memory_total_bytes: u64,
40 pub temperature_celsius: f32,
41 pub power_usage_watts: f32,
42 pub frequency_mhz: u32,
43}
44
45#[derive(Debug, Clone, Serialize, Deserialize)]
47pub enum GpuVendor {
48 Nvidia,
49 Amd,
50 Intel,
51 Apple,
52 Unknown,
53}
54
55#[derive(Debug, Clone, Serialize, Deserialize, Default)]
57pub struct IoResourceMetrics {
58 pub disk_read_bytes_per_sec: u64,
59 pub disk_write_bytes_per_sec: u64,
60 pub disk_read_ops_per_sec: u64,
61 pub disk_write_ops_per_sec: u64,
62 pub network_rx_bytes_per_sec: u64,
63 pub network_tx_bytes_per_sec: u64,
64 pub network_rx_packets_per_sec: u64,
65 pub network_tx_packets_per_sec: u64,
66}
67
68#[derive(Debug, Clone, Serialize, Deserialize)]
70pub struct ThreadResourceMetrics {
71 pub thread_id: u64,
72 pub thread_name: Option<String>,
73 pub cpu_usage_percent: f32,
74 pub memory_resident_bytes: u64,
75 pub memory_virtual_bytes: u64,
76 pub io_read_bytes: u64,
77 pub io_write_bytes: u64,
78 pub cpu_time_user_ns: u64,
79 pub cpu_time_kernel_ns: u64,
80}
81
82pub struct PlatformResourceCollector {
84 cpu_count: usize,
85}
86
87impl PlatformResourceCollector {
88 pub fn new() -> Result<Self, Box<dyn std::error::Error>> {
90 Ok(Self {
91 cpu_count: num_cpus::get(),
92 })
93 }
94
95 pub fn collect_metrics(
97 &mut self,
98 ) -> Result<PlatformResourceMetrics, Box<dyn std::error::Error>> {
99 let timestamp = std::time::SystemTime::now()
100 .duration_since(std::time::UNIX_EPOCH)?
101 .as_millis() as u64;
102
103 let cpu_metrics = self.collect_basic_cpu_metrics();
104
105 Ok(PlatformResourceMetrics {
106 timestamp,
107 cpu_metrics,
108 gpu_metrics: None, io_metrics: IoResourceMetrics::default(), thread_metrics: self.collect_basic_thread_metrics(),
111 })
112 }
113
114 pub fn get_optimal_collection_interval(&self) -> Duration {
116 Duration::from_millis(100) }
118
119 fn collect_basic_cpu_metrics(&self) -> CpuResourceMetrics {
120 let usage = self.estimate_cpu_usage();
122
123 CpuResourceMetrics {
124 overall_usage_percent: usage,
125 per_core_usage: vec![usage / self.cpu_count as f32; self.cpu_count],
126 frequency_mhz: vec![0; self.cpu_count], temperature_celsius: Vec::new(), context_switches_per_sec: 0, interrupts_per_sec: 0, load_average: self.get_load_average(),
131 }
132 }
133
134 fn estimate_cpu_usage(&self) -> f32 {
135 #[cfg(unix)]
137 {
138 if let Ok(uptime) = std::fs::read_to_string("/proc/uptime") {
139 let parts: Vec<&str> = uptime.split_whitespace().collect();
140 if parts.len() >= 2 {
141 let total = parts[0].parse::<f64>().unwrap_or(1.0);
142 let idle = parts[1].parse::<f64>().unwrap_or(0.0);
143 return ((total - idle) / total * 100.0).clamp(0.0, 100.0) as f32;
144 }
145 }
146 }
147
148 25.0
150 }
151
152 fn get_load_average(&self) -> (f64, f64, f64) {
153 #[cfg(unix)]
154 {
155 let mut load_avg: [f64; 3] = [0.0; 3];
156 unsafe {
157 if libc::getloadavg(load_avg.as_mut_ptr(), 3) != -1 {
158 return (load_avg[0], load_avg[1], load_avg[2]);
159 }
160 }
161 }
162
163 (0.0, 0.0, 0.0)
164 }
165
166 fn collect_basic_thread_metrics(&self) -> HashMap<u64, ThreadResourceMetrics> {
167 let mut metrics = HashMap::new();
168
169 let thread_id = 1u64; metrics.insert(
172 thread_id,
173 ThreadResourceMetrics {
174 thread_id,
175 thread_name: std::thread::current().name().map(String::from),
176 cpu_usage_percent: 0.0,
177 memory_resident_bytes: 0, memory_virtual_bytes: 0, io_read_bytes: 0,
180 io_write_bytes: 0,
181 cpu_time_user_ns: 0,
182 cpu_time_kernel_ns: 0,
183 },
184 );
185
186 metrics
187 }
188}
189
190impl Default for CpuResourceMetrics {
191 fn default() -> Self {
192 Self {
193 overall_usage_percent: 0.0,
194 per_core_usage: Vec::new(),
195 frequency_mhz: Vec::new(),
196 temperature_celsius: Vec::new(),
197 context_switches_per_sec: 0,
198 interrupts_per_sec: 0,
199 load_average: (0.0, 0.0, 0.0),
200 }
201 }
202}
203
204#[cfg(test)]
205mod tests {
206 use super::*;
207
208 #[test]
209 fn test_simplified_platform_resource_collector_creation() {
210 let result = PlatformResourceCollector::new();
211 assert!(result.is_ok());
212 }
213
214 #[test]
215 fn test_simplified_resource_metrics_collection() {
216 if let Ok(mut collector) = PlatformResourceCollector::new() {
217 let result = collector.collect_metrics();
218 assert!(result.is_ok());
219
220 let metrics = result.unwrap();
221 assert!(metrics.timestamp > 0);
222 assert!(metrics.gpu_metrics.is_none()); }
225 }
226
227 #[test]
228 fn test_resource_metrics_serialization() {
229 let metrics = PlatformResourceMetrics {
230 timestamp: 12345,
231 cpu_metrics: CpuResourceMetrics::default(),
232 gpu_metrics: None,
233 io_metrics: IoResourceMetrics::default(),
234 thread_metrics: HashMap::new(),
235 };
236
237 let serialized = serde_json::to_string(&metrics).expect("Failed to serialize metrics");
238 let _deserialized: PlatformResourceMetrics =
239 serde_json::from_str(&serialized).expect("Failed to deserialize metrics");
240 }
241
242 #[test]
243 fn test_optimal_collection_interval() {
244 if let Ok(collector) = PlatformResourceCollector::new() {
245 let interval = collector.get_optimal_collection_interval();
246 assert!(interval >= Duration::from_millis(50)); assert!(interval <= Duration::from_secs(1)); }
249 }
250}