1use std::sync::atomic::{AtomicU64, Ordering as AtomicOrdering};
4
5#[derive(Debug)]
7pub struct HnswPerformanceStats {
8 pub total_searches: AtomicU64,
9 pub total_insertions: AtomicU64,
10 pub total_deletions: AtomicU64,
11 pub total_updates: AtomicU64,
12 pub avg_search_time_us: AtomicU64, pub avg_distance_calculations: AtomicU64, pub cache_hits: AtomicU64,
15 pub cache_misses: AtomicU64,
16 pub simd_operations: AtomicU64,
17 pub parallel_searches: AtomicU64,
18 pub parallel_operations: AtomicU64,
19 pub prefetch_operations: AtomicU64,
20 pub memory_allocations: AtomicU64,
21 pub lock_contentions: AtomicU64,
22}
23
24impl Default for HnswPerformanceStats {
25 fn default() -> Self {
26 Self {
27 total_searches: AtomicU64::new(0),
28 total_insertions: AtomicU64::new(0),
29 total_deletions: AtomicU64::new(0),
30 total_updates: AtomicU64::new(0),
31 avg_search_time_us: AtomicU64::new(0),
32 avg_distance_calculations: AtomicU64::new(0),
33 cache_hits: AtomicU64::new(0),
34 cache_misses: AtomicU64::new(0),
35 simd_operations: AtomicU64::new(0),
36 parallel_searches: AtomicU64::new(0),
37 parallel_operations: AtomicU64::new(0),
38 prefetch_operations: AtomicU64::new(0),
39 memory_allocations: AtomicU64::new(0),
40 lock_contentions: AtomicU64::new(0),
41 }
42 }
43}
44
45impl Clone for HnswPerformanceStats {
46 fn clone(&self) -> Self {
47 Self {
48 total_searches: AtomicU64::new(self.total_searches.load(AtomicOrdering::Relaxed)),
49 total_insertions: AtomicU64::new(self.total_insertions.load(AtomicOrdering::Relaxed)),
50 total_deletions: AtomicU64::new(self.total_deletions.load(AtomicOrdering::Relaxed)),
51 total_updates: AtomicU64::new(self.total_updates.load(AtomicOrdering::Relaxed)),
52 avg_search_time_us: AtomicU64::new(
53 self.avg_search_time_us.load(AtomicOrdering::Relaxed),
54 ),
55 avg_distance_calculations: AtomicU64::new(
56 self.avg_distance_calculations.load(AtomicOrdering::Relaxed),
57 ),
58 cache_hits: AtomicU64::new(self.cache_hits.load(AtomicOrdering::Relaxed)),
59 cache_misses: AtomicU64::new(self.cache_misses.load(AtomicOrdering::Relaxed)),
60 simd_operations: AtomicU64::new(self.simd_operations.load(AtomicOrdering::Relaxed)),
61 parallel_searches: AtomicU64::new(self.parallel_searches.load(AtomicOrdering::Relaxed)),
62 parallel_operations: AtomicU64::new(
63 self.parallel_operations.load(AtomicOrdering::Relaxed),
64 ),
65 prefetch_operations: AtomicU64::new(
66 self.prefetch_operations.load(AtomicOrdering::Relaxed),
67 ),
68 memory_allocations: AtomicU64::new(
69 self.memory_allocations.load(AtomicOrdering::Relaxed),
70 ),
71 lock_contentions: AtomicU64::new(self.lock_contentions.load(AtomicOrdering::Relaxed)),
72 }
73 }
74}
75
76impl HnswPerformanceStats {
77 pub fn get_total_searches(&self) -> u64 {
79 self.total_searches.load(AtomicOrdering::Relaxed)
80 }
81
82 pub fn get_avg_search_time_us(&self) -> f64 {
84 self.avg_search_time_us.load(AtomicOrdering::Relaxed) as f64
85 }
86
87 pub fn get_avg_distance_calculations(&self) -> f64 {
89 self.avg_distance_calculations.load(AtomicOrdering::Relaxed) as f64
90 }
91
92 pub fn cache_hit_ratio(&self) -> f64 {
94 let hits = self.cache_hits.load(AtomicOrdering::Relaxed);
95 let misses = self.cache_misses.load(AtomicOrdering::Relaxed);
96 if hits + misses == 0 {
97 0.0
98 } else {
99 hits as f64 / (hits + misses) as f64
100 }
101 }
102
103 pub fn avg_search_time(&self) -> u64 {
105 self.avg_search_time_us.load(AtomicOrdering::Relaxed)
106 }
107
108 pub fn parallel_efficiency(&self) -> f64 {
110 let total = self.total_searches.load(AtomicOrdering::Relaxed);
111 let parallel = self.parallel_operations.load(AtomicOrdering::Relaxed);
112 if total == 0 {
113 0.0
114 } else {
115 parallel as f64 / total as f64
116 }
117 }
118}