rez_lsp_server/performance/
mod.rs1pub mod cache;
4pub mod metrics;
5pub mod profiler;
6
7pub use cache::{CacheManager, CacheStats};
8pub use metrics::{MetricsCollector, PerformanceMetrics};
9pub use profiler::{Profiler, ProfilerGuard};
10
11use std::time::{Duration, Instant};
12
13#[derive(Debug, Clone)]
15pub struct PerformanceConfig {
16 pub enable_monitoring: bool,
18 pub enable_caching: bool,
20 pub cache_size_mb: usize,
22 pub cache_ttl_seconds: u64,
24 pub enable_profiling: bool,
26 pub max_metrics_history: usize,
28}
29
30impl Default for PerformanceConfig {
31 fn default() -> Self {
32 Self {
33 enable_monitoring: true,
34 enable_caching: true,
35 cache_size_mb: 100,
36 cache_ttl_seconds: 300, enable_profiling: false, max_metrics_history: 1000,
39 }
40 }
41}
42
43pub struct Timer {
45 start: Instant,
46 name: String,
47}
48
49impl Timer {
50 pub fn new(name: impl Into<String>) -> Self {
52 Self {
53 start: Instant::now(),
54 name: name.into(),
55 }
56 }
57
58 pub fn elapsed(&self) -> Duration {
60 self.start.elapsed()
61 }
62
63 pub fn elapsed_ms(&self) -> u64 {
65 self.elapsed().as_millis() as u64
66 }
67
68 pub fn name(&self) -> &str {
70 &self.name
71 }
72}
73
74impl Drop for Timer {
75 fn drop(&mut self) {
76 let elapsed = self.elapsed_ms();
77 if elapsed > 100 {
78 tracing::warn!("Slow operation '{}' took {}ms", self.name, elapsed);
80 } else {
81 tracing::debug!("Operation '{}' took {}ms", self.name, elapsed);
82 }
83 }
84}
85
86#[macro_export]
88macro_rules! time_operation {
89 ($name:expr, $block:block) => {{
90 let _timer = $crate::performance::Timer::new($name);
91 $block
92 }};
93}
94
95#[macro_export]
97macro_rules! time_async_operation {
98 ($name:expr, $block:block) => {{
99 let _timer = $crate::performance::Timer::new($name);
100 $block
101 }};
102}
103
104#[derive(Debug, Clone)]
106pub enum OptimizationHint {
107 Cache { key: String, ttl_seconds: u64 },
109 Parallelize { max_concurrency: usize },
111 Incremental { checkpoint_interval: usize },
113 Debounce { delay_ms: u64 },
115}
116
117#[derive(Debug, Clone)]
119pub struct SystemPerformanceStats {
120 pub total_operations: u64,
122 pub avg_operation_time_ms: f64,
124 pub cache_hits: u64,
126 pub cache_misses: u64,
128 pub cache_hit_ratio: f64,
130 pub memory_usage_mb: f64,
132 pub active_profiles: usize,
134}
135
136impl SystemPerformanceStats {
137 pub fn new() -> Self {
139 Self {
140 total_operations: 0,
141 avg_operation_time_ms: 0.0,
142 cache_hits: 0,
143 cache_misses: 0,
144 cache_hit_ratio: 0.0,
145 memory_usage_mb: 0.0,
146 active_profiles: 0,
147 }
148 }
149
150 pub fn update_cache_stats(&mut self, hits: u64, misses: u64) {
152 self.cache_hits = hits;
153 self.cache_misses = misses;
154 let total = hits + misses;
155 self.cache_hit_ratio = if total > 0 {
156 hits as f64 / total as f64
157 } else {
158 0.0
159 };
160 }
161
162 pub fn update_operation_stats(&mut self, total_ops: u64, avg_time_ms: f64) {
164 self.total_operations = total_ops;
165 self.avg_operation_time_ms = avg_time_ms;
166 }
167
168 pub fn update_memory_usage(&mut self, usage_mb: f64) {
170 self.memory_usage_mb = usage_mb;
171 }
172
173 pub fn update_active_profiles(&mut self, count: usize) {
175 self.active_profiles = count;
176 }
177}
178
179impl Default for SystemPerformanceStats {
180 fn default() -> Self {
181 Self::new()
182 }
183}
184
185#[cfg(test)]
186mod tests {
187 use super::*;
188 use std::thread;
189 use std::time::Duration;
190
191 #[test]
192 fn test_timer_creation() {
193 let timer = Timer::new("test_operation");
194 assert_eq!(timer.name(), "test_operation");
195 assert!(timer.elapsed().as_nanos() > 0);
196 }
197
198 #[test]
199 fn test_timer_elapsed() {
200 let timer = Timer::new("test");
201 thread::sleep(Duration::from_millis(10));
202 assert!(timer.elapsed_ms() >= 10);
203 }
204
205 #[test]
206 fn test_performance_config_default() {
207 let config = PerformanceConfig::default();
208 assert!(config.enable_monitoring);
209 assert!(config.enable_caching);
210 assert_eq!(config.cache_size_mb, 100);
211 assert_eq!(config.cache_ttl_seconds, 300);
212 assert!(!config.enable_profiling);
213 assert_eq!(config.max_metrics_history, 1000);
214 }
215
216 #[test]
217 fn test_system_performance_stats() {
218 let mut stats = SystemPerformanceStats::new();
219
220 stats.update_cache_stats(80, 20);
221 assert_eq!(stats.cache_hits, 80);
222 assert_eq!(stats.cache_misses, 20);
223 assert_eq!(stats.cache_hit_ratio, 0.8);
224
225 stats.update_operation_stats(1000, 25.5);
226 assert_eq!(stats.total_operations, 1000);
227 assert_eq!(stats.avg_operation_time_ms, 25.5);
228
229 stats.update_memory_usage(150.5);
230 assert_eq!(stats.memory_usage_mb, 150.5);
231
232 stats.update_active_profiles(3);
233 assert_eq!(stats.active_profiles, 3);
234 }
235
236 #[test]
237 fn test_cache_hit_ratio_calculation() {
238 let mut stats = SystemPerformanceStats::new();
239
240 stats.update_cache_stats(0, 0);
242 assert_eq!(stats.cache_hit_ratio, 0.0);
243
244 stats.update_cache_stats(100, 0);
246 assert_eq!(stats.cache_hit_ratio, 1.0);
247
248 stats.update_cache_stats(0, 100);
250 assert_eq!(stats.cache_hit_ratio, 0.0);
251
252 stats.update_cache_stats(75, 25);
254 assert_eq!(stats.cache_hit_ratio, 0.75);
255 }
256
257 #[tokio::test]
258 async fn test_time_operation_macro() {
259 let result = time_operation!("test_macro", {
260 thread::sleep(Duration::from_millis(1));
261 42
262 });
263 assert_eq!(result, 42);
264 }
265
266 #[tokio::test]
267 async fn test_time_async_operation_macro() {
268 let result = time_async_operation!("test_async_macro", {
269 tokio::time::sleep(Duration::from_millis(1)).await;
270 "hello"
271 });
272 assert_eq!(result, "hello");
273 }
274}