nerve/integration/
performance.rs1use std::sync::atomic::{AtomicU64, Ordering};
6use std::sync::Arc;
7use std::time::{Duration, Instant};
8
9#[derive(Debug)]
11pub struct SystemPerformance {
12 messages_processed: AtomicU64,
14 errors_encountered: AtomicU64,
16 total_processing_time: AtomicU64,
18 memory_usage: AtomicU64,
20 thread_utilization: AtomicU64,
22}
23
24impl SystemPerformance {
25 pub fn new() -> Arc<Self> {
27 Arc::new(Self {
28 messages_processed: AtomicU64::new(0),
29 errors_encountered: AtomicU64::new(0),
30 total_processing_time: AtomicU64::new(0),
31 memory_usage: AtomicU64::new(0),
32 thread_utilization: AtomicU64::new(0),
33 })
34 }
35
36 pub fn record_message_processed(&self, processing_time: Duration) {
38 self.messages_processed.fetch_add(1, Ordering::Relaxed);
39 self.total_processing_time.fetch_add(
40 processing_time.as_nanos() as u64,
41 Ordering::Relaxed,
42 );
43 }
44
45 pub fn record_error(&self) {
47 self.errors_encountered.fetch_add(1, Ordering::Relaxed);
48 }
49
50 pub fn update_memory_usage(&self, usage_bytes: u64) {
52 self.memory_usage.store(usage_bytes, Ordering::Relaxed);
53 }
54
55 pub fn update_thread_utilization(&self, utilization_percent: u64) {
57 self.thread_utilization.store(utilization_percent, Ordering::Relaxed);
58 }
59
60 pub fn get_statistics(&self) -> SystemStatistics {
62 let messages = self.messages_processed.load(Ordering::Relaxed);
63 let errors = self.errors_encountered.load(Ordering::Relaxed);
64 let total_time = self.total_processing_time.load(Ordering::Relaxed);
65 let memory = self.memory_usage.load(Ordering::Relaxed);
66 let threads = self.thread_utilization.load(Ordering::Relaxed);
67
68 let avg_processing_time = if messages > 0 {
69 Duration::from_nanos(total_time / messages)
70 } else {
71 Duration::from_nanos(0)
72 };
73
74 let error_rate = if messages > 0 {
75 (errors as f64 / messages as f64) * 100.0
76 } else {
77 0.0
78 };
79
80 SystemStatistics {
81 messages_processed: messages,
82 errors_encountered: errors,
83 average_processing_time: avg_processing_time,
84 error_rate_percent: error_rate,
85 memory_usage_bytes: memory,
86 thread_utilization_percent: threads,
87 }
88 }
89}
90
91#[derive(Debug, Clone)]
93pub struct SystemStatistics {
94 pub messages_processed: u64,
96 pub errors_encountered: u64,
98 pub average_processing_time: Duration,
100 pub error_rate_percent: f64,
102 pub memory_usage_bytes: u64,
104 pub thread_utilization_percent: u64,
106}
107
108impl SystemStatistics {
109 pub fn is_healthy(&self) -> bool {
111 self.error_rate_percent < 1.0
116 && self.memory_usage_bytes < 1_000_000_000
117 && self.thread_utilization_percent >= 10
118 && self.thread_utilization_percent <= 90
119 }
120
121 pub fn health_status(&self) -> SystemHealth {
123 if self.is_healthy() {
124 SystemHealth::Healthy
125 } else if self.error_rate_percent > 5.0 || self.memory_usage_bytes > 2_000_000_000 {
126 SystemHealth::Critical
127 } else {
128 SystemHealth::Warning
129 }
130 }
131}
132
133#[derive(Debug, Clone, PartialEq)]
135pub enum SystemHealth {
136 Healthy,
138 Warning,
140 Critical,
142}
143
144pub struct PerformanceTimer {
146 start_time: Instant,
147 performance_monitor: Arc<SystemPerformance>,
148}
149
150impl PerformanceTimer {
151 pub fn start(performance_monitor: Arc<SystemPerformance>) -> Self {
153 Self {
154 start_time: Instant::now(),
155 performance_monitor,
156 }
157 }
158
159 pub fn record(self) {
161 let elapsed = self.start_time.elapsed();
162 self.performance_monitor.record_message_processed(elapsed);
163 }
164}
165
166impl Drop for PerformanceTimer {
167 fn drop(&mut self) {
168 if !std::thread::panicking() {
169 let elapsed = self.start_time.elapsed();
172 self.performance_monitor.record_message_processed(elapsed);
173 }
174 }
175}