1use std::time::{Duration, Instant};
4use serde::{Serialize, Deserialize};
5use crate::error::ResourceKind;
6use crate::InstanceId;
7
8#[derive(Debug, Clone, Serialize, Deserialize)]
10pub struct DetailedResourceUsage {
11 pub memory: MemoryUsage,
12 pub cpu: CpuUsage,
13 pub io: IoUsage,
14 pub timeline: Vec<ResourceSnapshot>,
15}
16
17#[derive(Debug, Clone, Serialize, Deserialize)]
19pub struct MemoryUsage {
20 pub current_bytes: usize,
21 pub peak_bytes: usize,
22 pub allocations: u64,
23 pub deallocations: u64,
24}
25
26#[derive(Debug, Clone, Serialize, Deserialize)]
28pub struct CpuUsage {
29 pub time_spent: Duration,
30 pub instructions_executed: u64,
31 pub function_calls: u64,
32}
33
34#[derive(Debug, Clone, Serialize, Deserialize)]
36pub struct IoUsage {
37 pub files_opened: u64,
38 pub bytes_read: u64,
39 pub bytes_written: u64,
40 pub network_requests: u64,
41}
42
43#[derive(Debug, Clone, Serialize, Deserialize)]
45pub struct ResourceSnapshot {
46 pub timestamp: u64, pub memory_bytes: usize,
48 pub cpu_time_ms: u64,
49 pub active_handles: u32,
50}
51
52#[derive(Debug)]
54pub struct ResourceMonitor {
55 _instance_id: Option<InstanceId>,
56 start_time: Instant,
57 memory_usage: MemoryUsage,
58 cpu_usage: CpuUsage,
59 io_usage: IoUsage,
60 snapshots: Vec<ResourceSnapshot>,
61 snapshot_interval: Duration,
62 last_snapshot: Instant,
63}
64
65impl ResourceMonitor {
66 pub fn new(instance_id: Option<InstanceId>) -> Self {
68 let now = Instant::now();
69 Self {
70 _instance_id: instance_id,
71 start_time: now,
72 memory_usage: MemoryUsage {
73 current_bytes: 0,
74 peak_bytes: 0,
75 allocations: 0,
76 deallocations: 0,
77 },
78 cpu_usage: CpuUsage {
79 time_spent: Duration::from_millis(0),
80 instructions_executed: 0,
81 function_calls: 0,
82 },
83 io_usage: IoUsage {
84 files_opened: 0,
85 bytes_read: 0,
86 bytes_written: 0,
87 network_requests: 0,
88 },
89 snapshots: Vec::new(),
90 snapshot_interval: Duration::from_secs(1),
91 last_snapshot: now,
92 }
93 }
94
95 pub fn update_memory(&mut self, current_bytes: usize) {
97 self.memory_usage.current_bytes = current_bytes;
98 if current_bytes > self.memory_usage.peak_bytes {
99 self.memory_usage.peak_bytes = current_bytes;
100 }
101 self.take_snapshot_if_needed();
102 }
103
104 pub fn record_allocation(&mut self, _bytes: usize) {
106 self.memory_usage.allocations += 1;
107 }
108
109 pub fn record_deallocation(&mut self, _bytes: usize) {
111 self.memory_usage.deallocations += 1;
112 }
113
114 pub fn update_cpu_time(&mut self, time_spent: Duration) {
116 self.cpu_usage.time_spent = time_spent;
117 self.take_snapshot_if_needed();
118 }
119
120 pub fn record_function_call(&mut self) {
122 self.cpu_usage.function_calls += 1;
123 }
124
125 pub fn record_instructions(&mut self, count: u64) {
127 self.cpu_usage.instructions_executed += count;
128 }
129
130 pub fn record_file_open(&mut self) {
132 self.io_usage.files_opened += 1;
133 }
134
135 pub fn record_file_read(&mut self, bytes: u64) {
137 self.io_usage.bytes_read += bytes;
138 }
139
140 pub fn record_file_write(&mut self, bytes: u64) {
142 self.io_usage.bytes_written += bytes;
143 }
144
145 pub fn record_network_request(&mut self) {
147 self.io_usage.network_requests += 1;
148 }
149
150 fn take_snapshot_if_needed(&mut self) {
152 let now = Instant::now();
153 if now.duration_since(self.last_snapshot) >= self.snapshot_interval {
154 self.take_snapshot();
155 self.last_snapshot = now;
156 }
157 }
158
159 pub fn take_snapshot(&mut self) {
161 let snapshot = ResourceSnapshot {
162 timestamp: std::time::SystemTime::now()
163 .duration_since(std::time::UNIX_EPOCH)
164 .unwrap_or_default()
165 .as_millis() as u64,
166 memory_bytes: self.memory_usage.current_bytes,
167 cpu_time_ms: self.cpu_usage.time_spent.as_millis() as u64,
168 active_handles: (self.io_usage.files_opened - self.io_usage.bytes_written.min(self.io_usage.files_opened)) as u32,
169 };
170
171 self.snapshots.push(snapshot);
172
173 if self.snapshots.len() > 100 {
175 self.snapshots.remove(0);
176 }
177 }
178
179 pub fn get_detailed_usage(&self) -> DetailedResourceUsage {
181 DetailedResourceUsage {
182 memory: self.memory_usage.clone(),
183 cpu: self.cpu_usage.clone(),
184 io: self.io_usage.clone(),
185 timeline: self.snapshots.clone(),
186 }
187 }
188
189 pub fn get_current_usage(&self) -> DetailedResourceUsage {
191 DetailedResourceUsage {
192 memory: self.memory_usage.clone(),
193 cpu: self.cpu_usage.clone(),
194 io: self.io_usage.clone(),
195 timeline: self.snapshots.clone(),
196 }
197 }
198
199 pub fn check_resource_limit(&self, kind: &ResourceKind, limit: u64) -> Option<(u64, String)> {
201 match kind {
202 ResourceKind::Memory => {
203 let used = self.memory_usage.current_bytes as u64;
204 if used > limit {
205 Some((used, format!("Memory usage {} bytes exceeds limit {} bytes", used, limit)))
206 } else {
207 None
208 }
209 },
210 ResourceKind::CpuTime => {
211 let used = self.cpu_usage.time_spent.as_millis() as u64;
212 if used > limit {
213 Some((used, format!("CPU time {} ms exceeds limit {} ms", used, limit)))
214 } else {
215 None
216 }
217 },
218 ResourceKind::ExecutionTime => {
219 let used = Instant::now().duration_since(self.start_time).as_millis() as u64;
220 if used > limit {
221 Some((used, format!("Execution time {} ms exceeds limit {} ms", used, limit)))
222 } else {
223 None
224 }
225 },
226 ResourceKind::FileHandles => {
227 let used = self.io_usage.files_opened;
228 if used > limit {
229 Some((used, format!("File handles {} exceeds limit {}", used, limit)))
230 } else {
231 None
232 }
233 },
234 ResourceKind::NetworkConnections => {
235 let used = self.io_usage.network_requests;
236 if used > limit {
237 Some((used, format!("Network requests {} exceeds limit {}", used, limit)))
238 } else {
239 None
240 }
241 },
242 _ => None,
243 }
244 }
245
246 pub fn get_utilization(&self, kind: &ResourceKind, limit: u64) -> f64 {
248 if limit == 0 {
249 return 0.0;
250 }
251
252 let used = match kind {
253 ResourceKind::Memory => self.memory_usage.current_bytes as u64,
254 ResourceKind::CpuTime => self.cpu_usage.time_spent.as_millis() as u64,
255 ResourceKind::ExecutionTime => Instant::now().duration_since(self.start_time).as_millis() as u64,
256 ResourceKind::FileHandles => self.io_usage.files_opened,
257 ResourceKind::NetworkConnections => self.io_usage.network_requests,
258 _ => 0,
259 };
260
261 (used as f64 / limit as f64 * 100.0).min(100.0)
262 }
263
264 pub fn reset(&mut self) {
266 self.start_time = Instant::now();
267 self.memory_usage = MemoryUsage {
268 current_bytes: 0,
269 peak_bytes: 0,
270 allocations: 0,
271 deallocations: 0,
272 };
273 self.cpu_usage = CpuUsage {
274 time_spent: Duration::from_millis(0),
275 instructions_executed: 0,
276 function_calls: 0,
277 };
278 self.io_usage = IoUsage {
279 files_opened: 0,
280 bytes_read: 0,
281 bytes_written: 0,
282 network_requests: 0,
283 };
284 self.snapshots.clear();
285 self.last_snapshot = Instant::now();
286 }
287}