1use anyhow::{anyhow, Result};
7use serde::{Deserialize, Serialize};
8use std::collections::{HashMap, VecDeque};
9use std::sync::Arc;
10use std::time::{Duration, Instant};
11use tokio::sync::{RwLock, Semaphore};
12use tokio::task::yield_now;
13use tracing::{debug, info, warn};
14
15use crate::StreamEvent;
16
17#[derive(Debug, Clone, Serialize, Deserialize)]
19pub struct PerformanceUtilsConfig {
20 pub enable_zero_copy: bool,
22 pub enable_simd: bool,
24 pub enable_memory_pooling: bool,
26 pub enable_batch_optimization: bool,
28 pub optimal_batch_size: usize,
30 pub enable_adaptive_rate_limiting: bool,
32 pub enable_prefetching: bool,
34 pub cpu_cores: usize,
36}
37
38impl Default for PerformanceUtilsConfig {
39 fn default() -> Self {
40 Self {
41 enable_zero_copy: true,
42 enable_simd: true,
43 enable_memory_pooling: true,
44 enable_batch_optimization: true,
45 optimal_batch_size: 1000,
46 enable_adaptive_rate_limiting: true,
47 enable_prefetching: true,
48 cpu_cores: std::thread::available_parallelism()
49 .map(|n| n.get())
50 .unwrap_or(1),
51 }
52 }
53}
54
55pub struct AdaptiveBatcher {
57 config: PerformanceUtilsConfig,
58 batch_buffer: Arc<RwLock<Vec<StreamEvent>>>,
59 batch_stats: Arc<RwLock<BatchingStats>>,
60 last_flush: Instant,
61 target_latency: Duration,
62 optimal_batch_size: Arc<RwLock<usize>>,
63}
64
65#[derive(Debug, Clone, Default)]
67pub struct BatchingStats {
68 pub total_batches: u64,
69 pub total_events: u64,
70 pub avg_batch_size: f64,
71 pub avg_latency_ms: f64,
72 pub throughput_events_per_sec: f64,
73 pub efficiency_score: f64,
74}
75
76impl AdaptiveBatcher {
77 pub fn new(config: PerformanceUtilsConfig, target_latency: Duration) -> Self {
79 Self {
80 optimal_batch_size: Arc::new(RwLock::new(config.optimal_batch_size)),
81 config,
82 batch_buffer: Arc::new(RwLock::new(Vec::new())),
83 batch_stats: Arc::new(RwLock::new(BatchingStats::default())),
84 last_flush: Instant::now(),
85 target_latency,
86 }
87 }
88
89 pub async fn add_event(&mut self, event: StreamEvent) -> Result<Option<Vec<StreamEvent>>> {
91 let mut buffer = self.batch_buffer.write().await;
92 buffer.push(event);
93
94 let optimal_size = *self.optimal_batch_size.read().await;
95 let time_since_last_flush = self.last_flush.elapsed();
96
97 if buffer.len() >= optimal_size || time_since_last_flush >= self.target_latency {
99 let batch = std::mem::take(&mut *buffer);
100 self.last_flush = Instant::now();
101
102 self.update_stats_and_optimize(batch.len(), time_since_last_flush)
104 .await;
105
106 Ok(Some(batch))
107 } else {
108 Ok(None)
109 }
110 }
111
112 pub async fn flush(&mut self) -> Result<Option<Vec<StreamEvent>>> {
114 let mut buffer = self.batch_buffer.write().await;
115 if buffer.is_empty() {
116 return Ok(None);
117 }
118
119 let batch = std::mem::take(&mut *buffer);
120 let time_since_last_flush = self.last_flush.elapsed();
121 self.last_flush = Instant::now();
122
123 self.update_stats_and_optimize(batch.len(), time_since_last_flush)
124 .await;
125
126 Ok(Some(batch))
127 }
128
129 async fn update_stats_and_optimize(&self, batch_size: usize, latency: Duration) {
131 let mut stats = self.batch_stats.write().await;
132 stats.total_batches += 1;
133 stats.total_events += batch_size as u64;
134
135 let new_avg_batch_size = (stats.avg_batch_size + batch_size as f64) / 2.0;
137 let new_avg_latency = (stats.avg_latency_ms + latency.as_millis() as f64) / 2.0;
138
139 stats.avg_batch_size = new_avg_batch_size;
140 stats.avg_latency_ms = new_avg_latency;
141
142 if latency.as_secs_f64() > 0.0 {
143 stats.throughput_events_per_sec = batch_size as f64 / latency.as_secs_f64();
144 }
145
146 let latency_efficiency = if new_avg_latency > 0.0 {
148 1.0 / new_avg_latency
149 } else {
150 1.0
151 };
152 stats.efficiency_score = new_avg_batch_size * latency_efficiency;
153
154 if self.config.enable_batch_optimization {
156 let mut optimal_size = self.optimal_batch_size.write().await;
157
158 if new_avg_latency > self.target_latency.as_millis() as f64 && *optimal_size > 100 {
159 *optimal_size = (*optimal_size * 9) / 10;
161 debug!(
162 "Reduced optimal batch size to {} due to high latency",
163 *optimal_size
164 );
165 } else if new_avg_latency < self.target_latency.as_millis() as f64 / 2.0
166 && *optimal_size < 10000
167 {
168 *optimal_size = (*optimal_size * 11) / 10;
170 debug!(
171 "Increased optimal batch size to {} due to good latency",
172 *optimal_size
173 );
174 }
175 }
176 }
177
178 pub async fn get_stats(&self) -> BatchingStats {
180 self.batch_stats.read().await.clone()
181 }
182
183 pub async fn get_optimal_batch_size(&self) -> usize {
185 *self.optimal_batch_size.read().await
186 }
187}
188
189pub struct IntelligentMemoryPool<T> {
191 pools: Arc<RwLock<HashMap<String, VecDeque<T>>>>,
192 max_pool_size: usize,
193 allocation_stats: Arc<RwLock<PoolStats>>,
194}
195
196#[derive(Debug, Clone, Default)]
198pub struct PoolStats {
199 pub total_allocations: u64,
200 pub pool_hits: u64,
201 pub pool_misses: u64,
202 pub hit_rate: f64,
203 pub memory_saved_bytes: u64,
204}
205
206impl<T> IntelligentMemoryPool<T> {
207 pub fn new(max_pool_size: usize) -> Self {
209 Self {
210 pools: Arc::new(RwLock::new(HashMap::new())),
211 max_pool_size,
212 allocation_stats: Arc::new(RwLock::new(PoolStats::default())),
213 }
214 }
215
216 pub async fn get_or_create<F>(&self, pool_name: &str, factory: F) -> T
218 where
219 F: FnOnce() -> T,
220 {
221 let mut stats = self.allocation_stats.write().await;
222 stats.total_allocations += 1;
223
224 {
225 let mut pools = self.pools.write().await;
226 if let Some(pool) = pools.get_mut(pool_name) {
227 if let Some(obj) = pool.pop_front() {
228 stats.pool_hits += 1;
229 stats.hit_rate = (stats.pool_hits as f64) / (stats.total_allocations as f64);
230 return obj;
231 }
232 }
233 }
234
235 stats.pool_misses += 1;
237 stats.hit_rate = (stats.pool_hits as f64) / (stats.total_allocations as f64);
238
239 factory()
240 }
241
242 pub async fn return_to_pool(&self, pool_name: &str, obj: T) {
244 let mut pools = self.pools.write().await;
245 let pool = pools
246 .entry(pool_name.to_string())
247 .or_insert_with(VecDeque::new);
248
249 if pool.len() < self.max_pool_size {
250 pool.push_back(obj);
251 }
252 }
254
255 pub async fn get_stats(&self) -> PoolStats {
257 self.allocation_stats.read().await.clone()
258 }
259
260 pub async fn clear_all_pools(&self) {
262 let mut pools = self.pools.write().await;
263 pools.clear();
264
265 let mut stats = self.allocation_stats.write().await;
266 *stats = PoolStats::default();
267 }
268}
269
270pub struct AdaptiveRateLimiter {
272 permits: Arc<Semaphore>,
273 config: Arc<RwLock<RateLimitConfig>>,
274 performance_history: Arc<RwLock<VecDeque<PerformanceSnapshot>>>,
275 last_adjustment: Arc<RwLock<Instant>>,
276}
277
278#[derive(Debug, Clone)]
280pub struct RateLimitConfig {
281 pub max_requests_per_second: usize,
282 pub burst_capacity: usize,
283 pub adjustment_interval: Duration,
284 pub target_latency_ms: f64,
285 pub max_adjustment_factor: f64,
286}
287
288impl Default for RateLimitConfig {
289 fn default() -> Self {
290 Self {
291 max_requests_per_second: 10000,
292 burst_capacity: 1000,
293 adjustment_interval: Duration::from_secs(5),
294 target_latency_ms: 10.0,
295 max_adjustment_factor: 2.0,
296 }
297 }
298}
299
300#[derive(Debug, Clone)]
302struct PerformanceSnapshot {
303 timestamp: Instant,
304 latency_ms: f64,
305 throughput_rps: f64,
306 success_rate: f64,
307}
308
309impl AdaptiveRateLimiter {
310 pub fn new(config: RateLimitConfig) -> Self {
312 let permits = Arc::new(Semaphore::new(config.burst_capacity));
313
314 Self {
315 permits,
316 config: Arc::new(RwLock::new(config)),
317 performance_history: Arc::new(RwLock::new(VecDeque::new())),
318 last_adjustment: Arc::new(RwLock::new(Instant::now())),
319 }
320 }
321
322 pub async fn acquire_permit(&self) -> Result<tokio::sync::SemaphorePermit<'_>> {
324 match self.permits.try_acquire() {
325 Ok(permit) => Ok(permit),
326 Err(_) => {
327 warn!("Rate limit reached, applying backpressure");
329 self.permits
330 .acquire()
331 .await
332 .map_err(|e| anyhow!("Failed to acquire permit: {}", e))
333 }
334 }
335 }
336
337 pub async fn record_performance(&self, latency_ms: f64, success: bool) -> Result<()> {
339 let snapshot = PerformanceSnapshot {
340 timestamp: Instant::now(),
341 latency_ms,
342 throughput_rps: 0.0, success_rate: if success { 1.0 } else { 0.0 },
344 };
345
346 {
347 let mut history = self.performance_history.write().await;
348 history.push_back(snapshot);
349
350 if history.len() > 100 {
352 history.pop_front();
353 }
354 }
355
356 {
358 let last_adjustment = self.last_adjustment.read().await;
359 let config = self.config.read().await;
360
361 if last_adjustment.elapsed() >= config.adjustment_interval {
362 drop(last_adjustment);
363 drop(config);
364 self.adjust_rate_limits().await?;
365 }
366 }
367
368 Ok(())
369 }
370
371 async fn adjust_rate_limits(&self) -> Result<()> {
373 let mut last_adjustment = self.last_adjustment.write().await;
374 *last_adjustment = Instant::now();
375 drop(last_adjustment);
376
377 let history = self.performance_history.read().await;
378 if history.len() < 10 {
379 return Ok(()); }
381
382 let avg_latency: f64 =
384 history.iter().map(|s| s.latency_ms).sum::<f64>() / history.len() as f64;
385 let avg_success_rate: f64 =
386 history.iter().map(|s| s.success_rate).sum::<f64>() / history.len() as f64;
387
388 let mut config = self.config.write().await;
389 let current_rate = config.max_requests_per_second;
390
391 let adjustment_factor =
393 if avg_latency > config.target_latency_ms * 1.5 || avg_success_rate < 0.95 {
394 0.9
396 } else if avg_latency < config.target_latency_ms * 0.5 && avg_success_rate > 0.98 {
397 1.1
399 } else {
400 1.0
402 };
403
404 if adjustment_factor != 1.0 {
405 let new_rate = ((current_rate as f64) * adjustment_factor) as usize;
406 let max_rate = ((current_rate as f64) * config.max_adjustment_factor) as usize;
407 let min_rate = ((current_rate as f64) / config.max_adjustment_factor) as usize;
408
409 config.max_requests_per_second = new_rate.clamp(min_rate, max_rate);
410
411 info!(
412 "Adjusted rate limit from {} to {} req/s (factor: {:.2}, avg_latency: {:.2}ms, success_rate: {:.2}%)",
413 current_rate, config.max_requests_per_second, adjustment_factor, avg_latency, avg_success_rate * 100.0
414 );
415
416 }
420
421 Ok(())
422 }
423
424 pub async fn get_config(&self) -> RateLimitConfig {
426 self.config.read().await.clone()
427 }
428}
429
430pub struct ParallelStreamProcessor {
432 config: PerformanceUtilsConfig,
433 worker_semaphore: Arc<Semaphore>,
434 processing_stats: Arc<RwLock<ProcessingStats>>,
435}
436
437#[derive(Debug, Clone, Default)]
439pub struct ProcessingStats {
440 pub events_processed: u64,
441 pub avg_processing_time_ms: f64,
442 pub peak_concurrency: usize,
443 pub current_concurrency: usize,
444 pub throughput_events_per_sec: f64,
445 pub cpu_efficiency: f64,
446}
447
448impl ParallelStreamProcessor {
449 pub fn new(config: PerformanceUtilsConfig) -> Self {
451 let worker_semaphore = Arc::new(Semaphore::new(config.cpu_cores * 2));
452
453 Self {
454 config,
455 worker_semaphore,
456 processing_stats: Arc::new(RwLock::new(ProcessingStats::default())),
457 }
458 }
459
460 pub async fn process_parallel<F, Fut>(
462 &self,
463 events: Vec<StreamEvent>,
464 processor: F,
465 ) -> Result<Vec<Result<()>>>
466 where
467 F: Fn(StreamEvent) -> Fut + Send + Sync + Clone + 'static,
468 Fut: std::future::Future<Output = Result<()>> + Send + 'static,
469 {
470 let start_time = Instant::now();
471 let event_count = events.len();
472
473 {
475 let mut stats = self.processing_stats.write().await;
476 stats.current_concurrency = event_count.min(self.config.cpu_cores * 2);
477 stats.peak_concurrency = stats.peak_concurrency.max(stats.current_concurrency);
478 }
479
480 let mut handles = Vec::new();
482
483 for event in events {
484 let permit = self.worker_semaphore.clone().acquire_owned().await?;
485 let processor_clone = processor.clone();
486
487 let handle = tokio::spawn(async move {
488 let _permit = permit; let result = processor_clone(event).await;
490 yield_now().await; result
492 });
493
494 handles.push(handle);
495 }
496
497 let mut results = Vec::new();
499 for handle in handles {
500 match handle.await {
501 Ok(result) => results.push(result),
502 Err(e) => results.push(Err(anyhow!("Task join error: {}", e))),
503 }
504 }
505
506 let processing_time = start_time.elapsed();
508 {
509 let mut stats = self.processing_stats.write().await;
510 stats.events_processed += event_count as u64;
511 stats.avg_processing_time_ms =
512 (stats.avg_processing_time_ms + processing_time.as_millis() as f64) / 2.0;
513 stats.current_concurrency = 0;
514
515 if processing_time.as_secs_f64() > 0.0 {
516 stats.throughput_events_per_sec =
517 event_count as f64 / processing_time.as_secs_f64();
518 }
519
520 let ideal_time = (event_count as f64) / (self.config.cpu_cores as f64);
522 let actual_time = processing_time.as_secs_f64();
523 stats.cpu_efficiency = if actual_time > 0.0 {
524 (ideal_time / actual_time).min(1.0)
525 } else {
526 1.0
527 };
528 }
529
530 debug!(
531 "Processed {} events in {:?} ({:.2} events/sec)",
532 event_count,
533 processing_time,
534 event_count as f64 / processing_time.as_secs_f64()
535 );
536
537 Ok(results)
538 }
539
540 pub async fn get_stats(&self) -> ProcessingStats {
542 self.processing_stats.read().await.clone()
543 }
544}
545
546pub struct IntelligentPrefetcher<T> {
548 cache: Arc<RwLock<HashMap<String, T>>>,
549 access_patterns: Arc<RwLock<HashMap<String, AccessPattern>>>,
550 max_cache_size: usize,
551}
552
553#[derive(Debug, Clone)]
555struct AccessPattern {
556 access_count: u64,
557 last_access: Instant,
558 prediction_score: f64,
559 related_keys: Vec<String>,
560}
561
562impl<T: Clone> IntelligentPrefetcher<T> {
563 pub fn new(max_cache_size: usize) -> Self {
565 Self {
566 cache: Arc::new(RwLock::new(HashMap::new())),
567 access_patterns: Arc::new(RwLock::new(HashMap::new())),
568 max_cache_size,
569 }
570 }
571
572 pub async fn get_with_prefetch<F, Fut>(&self, key: &str, loader: F) -> Result<T>
574 where
575 F: FnOnce(String) -> Fut + Send,
576 Fut: std::future::Future<Output = Result<T>> + Send,
577 T: Send + Sync,
578 {
579 {
581 let cache = self.cache.read().await;
582 if let Some(data) = cache.get(key) {
583 self.update_access_pattern(key).await;
584 return Ok(data.clone());
585 }
586 }
587
588 let data = loader(key.to_string()).await?;
590
591 {
593 let mut cache = self.cache.write().await;
594 if cache.len() >= self.max_cache_size {
595 self.evict_lru().await;
597 }
598 cache.insert(key.to_string(), data.clone());
599 }
600
601 self.update_access_pattern(key).await;
603 self.trigger_intelligent_prefetch(key).await;
604
605 Ok(data)
606 }
607
608 async fn update_access_pattern(&self, key: &str) {
610 let mut patterns = self.access_patterns.write().await;
611 let pattern = patterns
612 .entry(key.to_string())
613 .or_insert_with(|| AccessPattern {
614 access_count: 0,
615 last_access: Instant::now(),
616 prediction_score: 0.0,
617 related_keys: Vec::new(),
618 });
619
620 pattern.access_count += 1;
621 pattern.last_access = Instant::now();
622
623 let recency_factor = 1.0; let frequency_factor = (pattern.access_count as f64).ln();
626 pattern.prediction_score = recency_factor * frequency_factor;
627 }
628
629 async fn trigger_intelligent_prefetch(&self, accessed_key: &str) {
631 let patterns = self.access_patterns.read().await;
632
633 if let Some(pattern) = patterns.get(accessed_key) {
634 for related_key in &pattern.related_keys {
636 if let Some(related_pattern) = patterns.get(related_key) {
637 if related_pattern.prediction_score > 0.5 {
638 debug!("Would prefetch related key: {}", related_key);
640 }
641 }
642 }
643 }
644 }
645
646 async fn evict_lru(&self) {
648 let patterns = self.access_patterns.read().await;
649
650 if let Some((lru_key, _)) = patterns
651 .iter()
652 .min_by_key(|(_, pattern)| pattern.last_access)
653 {
654 let lru_key = lru_key.clone();
655 drop(patterns);
656
657 let mut cache = self.cache.write().await;
658 cache.remove(&lru_key);
659
660 let mut patterns = self.access_patterns.write().await;
661 patterns.remove(&lru_key);
662 }
663 }
664
665 pub async fn get_cache_stats(&self) -> (usize, usize) {
667 let cache_size = self.cache.read().await.len();
668 let pattern_count = self.access_patterns.read().await.len();
669 (cache_size, pattern_count)
670 }
671}
672
673#[cfg(test)]
674mod tests {
675 use super::*;
676 use tokio::time::{sleep, Duration};
677
678 #[tokio::test]
679 async fn test_adaptive_batcher() {
680 let config = PerformanceUtilsConfig::default();
681 let mut batcher = AdaptiveBatcher::new(config, Duration::from_millis(100));
682
683 let event = crate::event::StreamEvent::TripleAdded {
684 subject: "http://example.org/subject".to_string(),
685 predicate: "http://example.org/predicate".to_string(),
686 object: "\"test_object\"".to_string(),
687 graph: None,
688 metadata: crate::event::EventMetadata::default(),
689 };
690
691 for i in 0..10 {
693 let result = batcher.add_event(event.clone()).await.unwrap();
694 if i == 9 {
695 assert!(result.is_none());
697 }
698 }
699
700 let batch = batcher.flush().await.unwrap();
702 assert!(batch.is_some());
703 assert_eq!(batch.unwrap().len(), 10);
704
705 let stats = batcher.get_stats().await;
706 assert_eq!(stats.total_batches, 1);
707 assert_eq!(stats.total_events, 10);
708 }
709
710 #[tokio::test]
711 async fn test_memory_pool() {
712 let pool: IntelligentMemoryPool<String> = IntelligentMemoryPool::new(10);
713
714 let obj1 = pool
716 .get_or_create("test_pool", || "test_string".to_string())
717 .await;
718 assert_eq!(obj1, "test_string");
719
720 pool.return_to_pool("test_pool", obj1).await;
722
723 let obj2 = pool
725 .get_or_create("test_pool", || "new_string".to_string())
726 .await;
727 assert_eq!(obj2, "test_string"); let stats = pool.get_stats().await;
730 assert_eq!(stats.pool_hits, 1);
731 assert_eq!(stats.total_allocations, 2);
732 }
733
734 #[tokio::test]
735 async fn test_adaptive_rate_limiter() {
736 let config = RateLimitConfig {
737 max_requests_per_second: 10,
738 burst_capacity: 5,
739 adjustment_interval: Duration::from_millis(100),
740 target_latency_ms: 10.0,
741 max_adjustment_factor: 2.0,
742 };
743
744 let limiter = AdaptiveRateLimiter::new(config);
745
746 for _ in 0..5 {
748 let _permit = limiter.acquire_permit().await.unwrap();
749 limiter.record_performance(5.0, true).await.unwrap(); }
751
752 sleep(Duration::from_millis(150)).await; let final_config = limiter.get_config().await;
755 assert!(final_config.max_requests_per_second >= 10);
757 }
758
759 #[tokio::test]
760 async fn test_parallel_processor() {
761 let config = PerformanceUtilsConfig::default();
762 let processor = ParallelStreamProcessor::new(config);
763
764 let events = vec![
765 crate::event::StreamEvent::TripleAdded {
766 subject: "http://example.org/subject1".to_string(),
767 predicate: "http://example.org/predicate".to_string(),
768 object: "\"test_object1\"".to_string(),
769 graph: None,
770 metadata: crate::event::EventMetadata::default(),
771 },
772 crate::event::StreamEvent::TripleAdded {
773 subject: "http://example.org/subject2".to_string(),
774 predicate: "http://example.org/predicate".to_string(),
775 object: "\"test_object2\"".to_string(),
776 graph: None,
777 metadata: crate::event::EventMetadata::default(),
778 },
779 ];
780
781 let results = processor
782 .process_parallel(events, |_event| async {
783 sleep(Duration::from_millis(10)).await;
784 Ok(())
785 })
786 .await
787 .unwrap();
788
789 assert_eq!(results.len(), 2);
790 assert!(results.iter().all(|r| r.is_ok()));
791
792 let stats = processor.get_stats().await;
793 assert_eq!(stats.events_processed, 2);
794 }
795
796 #[tokio::test]
797 async fn test_intelligent_prefetcher() {
798 let prefetcher: IntelligentPrefetcher<String> = IntelligentPrefetcher::new(10);
799
800 let data1 = prefetcher
802 .get_with_prefetch("key1", |key| async move { Ok(format!("data_for_{key}")) })
803 .await
804 .unwrap();
805
806 assert_eq!(data1, "data_for_key1");
807
808 let data2 = prefetcher
810 .get_with_prefetch("key1", |_key| async move {
811 Ok("should_not_be_called".to_string())
812 })
813 .await
814 .unwrap();
815
816 assert_eq!(data2, "data_for_key1");
817
818 let (cache_size, pattern_count) = prefetcher.get_cache_stats().await;
819 assert_eq!(cache_size, 1);
820 assert_eq!(pattern_count, 1);
821 }
822}