#[derive(Debug, Clone, Default)]
pub struct GCStats {
pub collection_count: usize,
pub marked_objects: usize,
pub collected_objects: usize,
pub collected_bytes: usize,
pub last_collection_time_us: u64,
pub total_collection_time_us: u64,
pub fragmentation_ratio: f64,
pub average_object_size: usize,
pub young_gen_collections: usize,
pub old_gen_collections: usize,
pub promoted_objects: usize,
pub promoted_bytes: usize,
pub parallel_mark_time_us: u64,
pub parallel_sweep_time_us: u64,
pub allocation_count: usize,
pub allocation_bytes: usize,
pub max_pause_time_us: u64,
pub min_pause_time_us: u64,
}
impl GCStats {
pub fn record_collection(&mut self, duration_us: u64, marked: usize, collected: usize, bytes: usize) {
self.collection_count += 1;
self.marked_objects += marked;
self.collected_objects += collected;
self.collected_bytes += bytes;
self.last_collection_time_us = duration_us;
self.total_collection_time_us += duration_us;
if collected > 0 {
self.average_object_size = bytes / collected;
}
if self.max_pause_time_us < duration_us {
self.max_pause_time_us = duration_us;
}
if self.min_pause_time_us == 0 || self.min_pause_time_us > duration_us {
self.min_pause_time_us = duration_us;
}
}
pub fn record_young_gen_collection(
&mut self,
duration_us: u64,
marked: usize,
collected: usize,
bytes: usize,
promoted: usize,
promoted_bytes: usize,
) {
self.young_gen_collections += 1;
self.record_collection(duration_us, marked, collected, bytes);
self.promoted_objects += promoted;
self.promoted_bytes += promoted_bytes;
}
pub fn record_old_gen_collection(&mut self, duration_us: u64, marked: usize, collected: usize, bytes: usize) {
self.old_gen_collections += 1;
self.record_collection(duration_us, marked, collected, bytes);
}
pub fn record_allocation(&mut self, size: usize) {
self.allocation_count += 1;
self.allocation_bytes += size;
}
pub fn record_parallel_mark_time(&mut self, duration_us: u64) {
self.parallel_mark_time_us += duration_us;
}
pub fn record_parallel_sweep_time(&mut self, duration_us: u64) {
self.parallel_sweep_time_us += duration_us;
}
pub fn average_collection_time_us(&self) -> u64 {
if self.collection_count == 0 { 0 } else { self.total_collection_time_us / self.collection_count as u64 }
}
pub fn average_young_gen_time_us(&self) -> u64 {
if self.young_gen_collections == 0 { 0 } else { self.total_collection_time_us / self.young_gen_collections as u64 }
}
pub fn average_promotion_rate(&self) -> f64 {
if self.young_gen_collections == 0 { 0.0 } else { self.promoted_objects as f64 / self.young_gen_collections as f64 }
}
pub fn update_fragmentation(&mut self, used: usize, total: usize) {
if total > 0 {
self.fragmentation_ratio = (total - used) as f64 / total as f64;
}
}
pub fn reset(&mut self) {
*self = Self::default();
}
pub fn report(&self) -> String {
format!(
"GC Statistics:\n\
- Collection count: {}\n\
- Young gen collections: {}\n\
- Old gen collections: {}\n\
- Total collection time: {} us\n\
- Average collection time: {} us\n\
- Max pause time: {} us\n\
- Min pause time: {} us\n\
- Collected objects: {}\n\
- Collected bytes: {}\n\
- Promoted objects: {}\n\
- Promoted bytes: {}\n\
- Average promotion rate: {:.2}\n\
- Fragmentation ratio: {:.2}%\n\
- Allocation count: {}\n\
- Allocation bytes: {}",
self.collection_count,
self.young_gen_collections,
self.old_gen_collections,
self.total_collection_time_us,
self.average_collection_time_us(),
self.max_pause_time_us,
self.min_pause_time_us,
self.collected_objects,
self.collected_bytes,
self.promoted_objects,
self.promoted_bytes,
self.average_promotion_rate(),
self.fragmentation_ratio * 100.0,
self.allocation_count,
self.allocation_bytes,
)
}
}