pub mod parallel_gc;
pub mod generation;
pub mod allocator;
pub mod collector;
pub use parallel_gc::{
ParallelGc,
ParallelGcConfig,
CollectionPhase,
GcStatistics,
SafepointCoordinator,
AdaptiveTuningParams,
CollectionRequest,
};
pub use generation::{
GenerationManager,
YoungGeneration,
OldGeneration,
Generation,
ObjectHeader,
GenerationId,
GenerationStatistics,
CollectionResult,
MemoryRegion,
HeapStatistics,
};
pub use allocator::{
AllocationCoordinator,
TlabManager,
Tlab,
AllocationSampler,
AllocationSample,
AllocationStatistics,
TlabStatistics,
};
pub use collector::{
CopyingCollector,
MarkSweepCollector,
IncrementalCollector,
RootSet,
WriteBarrier,
ObjectMarker,
};
pub type GcResult<T> = Result<T, String>;
pub struct GcConfigBuilder {
config: ParallelGcConfig,
}
impl GcConfigBuilder {
pub fn new() -> Self {
GcConfigBuilder {
config: ParallelGcConfig::default(),
}
}
pub fn collector_threads(mut self, threads: usize) -> Self {
self.config.max_collector_threads = threads;
self
}
pub fn young_generation_mb(mut self, mb: usize) -> Self {
self.config.young_generation_size = mb * 1024 * 1024;
self
}
pub fn old_generation_mb(mut self, mb: usize) -> Self {
self.config.old_generation_size = mb * 1024 * 1024;
self
}
pub fn large_object_threshold_kb(mut self, kb: usize) -> Self {
self.config.large_object_threshold = kb * 1024;
self
}
pub fn target_minor_pause_ms(mut self, ms: u64) -> Self {
self.config.target_minor_pause_ms = ms;
self
}
pub fn target_major_pause_ms(mut self, ms: u64) -> Self {
self.config.target_major_pause_ms = ms;
self
}
pub fn numa_aware(mut self, enabled: bool) -> Self {
self.config.numa_aware = enabled;
self
}
pub fn adaptive_tuning(mut self, enabled: bool) -> Self {
self.config.adaptive_tuning = enabled;
self
}
pub fn build(self) -> ParallelGcConfig {
self.config
}
}
impl Default for GcConfigBuilder {
fn default() -> Self {
Self::new()
}
}
pub struct GcSystem {
pub parallel_gc: ParallelGc,
pub generation_manager: Arc<GenerationManager>,
pub allocation_coordinator: Arc<AllocationCoordinator>,
pub copying_collector: Arc<CopyingCollector>,
pub mark_sweep_collector: Arc<MarkSweepCollector>,
pub incremental_collector: Arc<IncrementalCollector>,
pub root_set: Arc<RootSet>,
}
use std::sync::Arc;
impl GcSystem {
pub fn new(config: ParallelGcConfig) -> GcResult<Self> {
let generation_manager = Arc::new(GenerationManager::new(
config.young_generation_size,
config.old_generation_size,
)?);
let allocation_coordinator = Arc::new(AllocationCoordinator::new(
Arc::clone(&generation_manager),
32 * 1024, 128 * 1024, config.large_object_threshold,
));
let root_set = Arc::new(RootSet::new());
let parallel_gc = ParallelGc::new(config);
let safepoint = Arc::new(SafepointCoordinator::new());
let statistics = Arc::new(GcStatistics::new());
let copying_collector = Arc::new(CopyingCollector::new(
Arc::clone(&safepoint),
Arc::clone(&root_set),
Arc::clone(&statistics),
));
let mark_sweep_collector = Arc::new(MarkSweepCollector::new(
Arc::clone(&root_set),
Arc::clone(&statistics),
));
let incremental_collector = Arc::new(IncrementalCollector::new(
Arc::clone(©ing_collector),
Arc::clone(&mark_sweep_collector),
1000, ));
Ok(GcSystem {
parallel_gc,
generation_manager,
allocation_coordinator,
copying_collector,
mark_sweep_collector,
incremental_collector,
root_set,
})
}
pub fn initialize(&mut self, jit_metrics: Option<Arc<std::sync::RwLock<crate::jit::metrics::JitMetrics>>>) -> GcResult<()> {
self.parallel_gc.initialize(jit_metrics)
}
pub fn collect_minor(&self) -> GcResult<CollectionResult> {
self.copying_collector.collect()
}
pub fn collect_major(&self, concurrent: bool) -> GcResult<CollectionResult> {
self.mark_sweep_collector.collect(concurrent)
}
pub fn collect_incremental_step(&self) -> GcResult<bool> {
self.incremental_collector.perform_incremental_step()
}
pub fn allocate(&self, value: crate::eval::value::Value, size: usize) -> GcResult<Arc<ObjectHeader>> {
self.allocation_coordinator.allocate(value, size)
}
pub fn register_mutator_thread(&self) {
self.parallel_gc.register_mutator_thread();
}
pub fn unregister_mutator_thread(&self) {
self.parallel_gc.unregister_mutator_thread();
}
pub fn get_statistics(&self) -> GcSystemStatistics {
let gc_stats = self.parallel_gc.get_statistics();
let heap_stats = self.generation_manager.get_heap_statistics();
let allocation_stats = self.allocation_coordinator.get_statistics();
let tlab_stats = self.allocation_coordinator.get_tlab_statistics();
GcSystemStatistics {
minor_collections: gc_stats.minor_collections.load(std::sync::atomic::Ordering::Relaxed),
major_collections: gc_stats.major_collections.load(std::sync::atomic::Ordering::Relaxed),
avg_minor_pause_ms: gc_stats.avg_minor_pause_ns.load(std::sync::atomic::Ordering::Relaxed) as f64 / 1_000_000.0,
avg_major_pause_ms: gc_stats.avg_major_pause_ns.load(std::sync::atomic::Ordering::Relaxed) as f64 / 1_000_000.0,
total_allocations: heap_stats.total_allocations,
total_allocated_bytes: heap_stats.total_allocated_bytes,
young_utilization: heap_stats.young_utilization,
old_utilization: heap_stats.old_utilization,
allocation_rate: self.allocation_coordinator.allocation_rate(),
failure_rate: allocation_stats.failure_rate(),
tlab_utilization: tlab_stats.average_utilization(),
tlab_waste_percentage: tlab_stats.waste_percentage(),
}
}
pub fn shutdown(self) -> GcResult<()> {
self.parallel_gc.shutdown()
}
}
#[derive(Debug)]
pub struct GcSystemStatistics {
pub minor_collections: u64,
pub major_collections: u64,
pub avg_minor_pause_ms: f64,
pub avg_major_pause_ms: f64,
pub total_allocations: u64,
pub total_allocated_bytes: u64,
pub young_utilization: f64,
pub old_utilization: f64,
pub allocation_rate: f64,
pub failure_rate: f64,
pub tlab_utilization: f64,
pub tlab_waste_percentage: f64,
}
impl GcSystemStatistics {
pub fn is_healthy(&self) -> bool {
self.avg_minor_pause_ms < 15.0 && self.avg_major_pause_ms < 75.0 && self.failure_rate < 1.0 && self.tlab_utilization > 70.0 && self.young_utilization < 95.0 && self.old_utilization < 90.0 }
pub fn performance_score(&self) -> f64 {
let pause_score = 1.0 - (self.avg_minor_pause_ms / 50.0).min(1.0); let utilization_score = (self.tlab_utilization / 100.0).min(1.0);
let failure_score = 1.0 - (self.failure_rate / 10.0).min(1.0); let allocation_score = if self.allocation_rate > 0.0 { 1.0 } else { 0.0 };
(pause_score + utilization_score + failure_score + allocation_score) / 4.0
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::eval::value::Value;
use crate::ast::Literal;
#[test]
fn test_gc_config_builder() {
let config = GcConfigBuilder::new()
.young_generation_mb(32)
.old_generation_mb(128)
.target_minor_pause_ms(8)
.adaptive_tuning(true)
.build();
assert_eq!(config.young_generation_size, 32 * 1024 * 1024);
assert_eq!(config.old_generation_size, 128 * 1024 * 1024);
assert_eq!(config.target_minor_pause_ms, 8);
assert!(config.adaptive_tuning);
}
#[test]
fn test_gc_system_creation() {
let config = ParallelGcConfig::default();
let gc_system = GcSystem::new(config);
assert!(gc_system.is_ok());
}
#[test]
fn test_basic_allocation() {
let config = GcConfigBuilder::new()
.young_generation_mb(16)
.old_generation_mb(64)
.build();
let gc_system = GcSystem::new(config).unwrap();
let value = Value::Literal(Literal::Number(42.0));
let result = gc_system.allocate(value, 64);
assert!(result.is_ok());
let header = result.unwrap();
assert_eq!(header.size, 64);
assert_eq!(header.generation, GenerationId::Young);
}
#[test]
fn test_statistics_health_check() {
let stats = GcSystemStatistics {
minor_collections: 100,
major_collections: 10,
avg_minor_pause_ms: 8.5,
avg_major_pause_ms: 45.0,
total_allocations: 10000,
total_allocated_bytes: 1024 * 1024,
young_utilization: 75.0,
old_utilization: 60.0,
allocation_rate: 1000.0,
failure_rate: 0.1,
tlab_utilization: 85.0,
tlab_waste_percentage: 5.0,
};
assert!(stats.is_healthy());
assert!(stats.performance_score() > 0.8);
}
}