linkrs_storage/edge/mutable_csr/
stats.rs1use super::super::{ColdStamps, HotNbr};
2use super::MutableCsr;
3use crate::edge::FragmentationStats;
4
5impl MutableCsr {
6 pub fn overflow_chunk_allocs(&self) -> u64 {
7 self.overflow_chunk_allocs
8 }
9
10 pub fn primary_block_allocs(&self) -> u64 {
11 self.primary_block_allocs
12 }
13
14 pub fn repack_count(&self) -> u64 {
15 self.repack_count
16 }
17
18 pub fn tombstone_reuse_count(&self) -> u64 {
19 self.tombstone_reuse_count
20 }
21
22 pub fn tombstone_reuse_hint_hits(&self) -> u64 {
23 self.tombstone_reuse_hint_hits
24 }
25
26 pub fn tombstone_reuse_hint_misses(&self) -> u64 {
27 self.tombstone_reuse_hint_misses
28 }
29
30 pub fn tombstone_reuse_hint_hit_rate(&self) -> f32 {
31 let hits = self.tombstone_reuse_hint_hits as f64;
32 let misses = self.tombstone_reuse_hint_misses as f64;
33 if hits + misses == 0.0 {
34 0.0
35 } else {
36 (hits / (hits + misses)) as f32
37 }
38 }
39
40 pub fn live_set_rebuild_count(&self) -> u64 {
41 self.live_set_rebuild_count
42 }
43
44 pub fn reset_baseline_counters(&mut self) {
45 self.overflow_chunk_allocs = 0;
46 self.primary_block_allocs = 0;
47 self.repack_count = 0;
48 self.tombstone_reuse_count = 0;
49 self.live_set_rebuild_count = 0;
50 self.tombstone_reuse_hint_hits = 0;
51 self.tombstone_reuse_hint_misses = 0;
52 }
53}
54
55impl MutableCsr {
56 pub fn used_memory_size(&self) -> usize {
64 let slot_bytes = std::mem::size_of::<HotNbr>() + std::mem::size_of::<ColdStamps>();
65 let arrays = self.hot_list.capacity() * std::mem::size_of::<HotNbr>()
66 + self.cold_list.capacity() * std::mem::size_of::<ColdStamps>()
67 + self.rows.adj_offsets.capacity() * std::mem::size_of::<u32>()
68 + self.rows.degrees.capacity() * std::mem::size_of::<u32>()
69 + self.rows.primary_capacities.capacity() * std::mem::size_of::<u32>()
70 + self.primary_sorted.capacity() * std::mem::size_of::<bool>();
71 let overflow_reserved: usize = self
72 .overflow_chunks
73 .iter()
74 .map(|(_, chunks)| chunks.iter().map(|chunk| chunk.capacity()).sum::<usize>())
75 .sum();
76 let live_heap: usize = self.live_sets.heap_bytes_total();
77 let live_sets = self.live_sets.index_bytes() + live_heap;
78 arrays
79 + overflow_reserved * slot_bytes
80 + self.overflow_chunks.index_bytes()
81 + live_sets
82 + std::mem::size_of::<Self>()
83 }
84
85 pub fn fragmentation_ratio(&self) -> f32 {
92 if self.total_edge_capacity == 0 {
93 return 0.0;
94 }
95 let active_edges = self.edge_count as usize;
96 self.total_edge_capacity.saturating_sub(active_edges) as f32
97 / self.total_edge_capacity as f32
98 }
99
100 pub(crate) fn wasted_bytes_estimate(&self) -> usize {
102 let active_edges = self.edge_count as usize;
103 let slot_bytes = std::mem::size_of::<HotNbr>() + std::mem::size_of::<ColdStamps>();
104 self.total_edge_capacity.saturating_sub(active_edges) * slot_bytes
105 }
106
107 pub fn get_fragmentation_stats(&self) -> FragmentationStats {
114 let live_edges = self.edge_count as usize;
115
116 let mut physical_entries = 0usize;
117 for vid in 0..self.vertex_capacity() {
118 physical_entries += self.rows.degrees[vid] as usize;
119 }
120 for (_, chunks) in self.overflow_chunks.iter() {
121 for chunk in chunks {
122 physical_entries += chunk.len();
123 }
124 }
125
126 let dead_entries = physical_entries.saturating_sub(live_edges);
127 let wasted_capacity = self.total_edge_capacity.saturating_sub(live_edges);
128
129 FragmentationStats::with_dead_info(
130 self.total_edge_capacity,
131 live_edges,
132 dead_entries,
133 wasted_capacity,
134 )
135 }
136}