use super::config::{
ConfigRecommendation, FragmentationTrend, OptimizationOpportunity, PerformanceTier,
};
use std::collections::HashMap;
use std::time::{Duration, Instant};
#[derive(Debug, Clone)]
pub struct ScirS2AllocatorStats {
pub name: String,
pub total_allocations: u64,
pub total_deallocations: u64,
pub current_allocated: usize,
pub peak_allocated: usize,
pub allocation_failures: u64,
pub avg_allocation_time: Duration,
pub memory_efficiency: f64,
pub advanced_metrics: AllocatorAdvancedMetrics,
pub performance_profile: AllocatorPerformanceProfile,
pub last_update: Instant,
}
#[derive(Debug, Clone)]
pub struct AllocatorAdvancedMetrics {
pub size_distribution: SizeDistribution,
pub latency_percentiles: LatencyPercentiles,
pub fragmentation_metrics: AllocatorFragmentationMetrics,
pub cache_performance: AllocatorCachePerformance,
pub contention_metrics: ContentionMetrics,
}
#[derive(Debug, Clone)]
pub struct SizeDistribution {
pub small_count: u64,
pub medium_count: u64,
pub large_count: u64,
pub average_size: usize,
pub size_variance: f64,
pub common_sizes: Vec<(usize, u64)>,
}
#[derive(Debug, Clone)]
pub struct LatencyPercentiles {
pub p50: Duration,
pub p90: Duration,
pub p95: Duration,
pub p99: Duration,
pub p999: Duration,
pub max: Duration,
}
#[derive(Debug, Clone)]
pub struct AllocatorFragmentationMetrics {
pub internal_fragmentation: f64,
pub external_fragmentation: f64,
pub free_block_count: usize,
pub largest_free_block: usize,
pub fragmentation_trend: FragmentationTrend,
}
#[derive(Debug, Clone)]
pub struct AllocatorCachePerformance {
pub allocation_cache_hit_rate: f64,
pub free_list_efficiency: f64,
pub cache_warming_effectiveness: f64,
pub cache_pollution_level: f64,
}
#[derive(Debug, Clone)]
pub struct ContentionMetrics {
pub lock_contention_time: Duration,
pub avg_contention_per_alloc: Duration,
pub peak_concurrent_allocations: usize,
pub contention_hotspots: Vec<String>,
}
#[derive(Debug, Clone)]
pub struct AllocatorPerformanceProfile {
pub performance_tier: PerformanceTier,
pub optimization_opportunities: Vec<OptimizationOpportunity>,
pub recommended_config: Vec<ConfigRecommendation>,
pub performance_score: f64,
}
#[derive(Debug, Clone)]
pub struct PerformanceSnapshot {
pub timestamp: Instant,
pub allocation_latency: Duration,
pub bandwidth_utilization: f64,
pub cache_hit_rate: f64,
pub cpu_utilization: f64,
}
#[derive(Debug, Clone)]
pub struct MemoryStateSnapshot {
pub total_allocated: usize,
pub available_memory: usize,
pub fragmentation_level: f64,
pub active_allocations: usize,
}
#[derive(Debug, Clone)]
pub struct AllocationUsageStats {
pub total_accesses: u64,
pub read_write_ratio: f64,
pub access_pattern: String,
pub cache_efficiency: f64,
}
impl ScirS2AllocatorStats {
pub fn new(name: String) -> Self {
Self {
name,
total_allocations: 0,
total_deallocations: 0,
current_allocated: 0,
peak_allocated: 0,
allocation_failures: 0,
avg_allocation_time: Duration::from_secs(0),
memory_efficiency: 1.0,
advanced_metrics: AllocatorAdvancedMetrics::default(),
performance_profile: AllocatorPerformanceProfile::default(),
last_update: Instant::now(),
}
}
pub fn record_allocation(&mut self, size: usize, duration: Duration) {
self.total_allocations += 1;
self.current_allocated += size;
self.peak_allocated = self.peak_allocated.max(self.current_allocated);
let new_avg = if self.total_allocations == 1 {
duration
} else {
let total_time =
self.avg_allocation_time * (self.total_allocations - 1) as u32 + duration;
total_time / self.total_allocations as u32
};
self.avg_allocation_time = new_avg;
self.advanced_metrics
.size_distribution
.record_allocation(size);
self.advanced_metrics
.latency_percentiles
.record_latency(duration);
self.last_update = Instant::now();
}
pub fn record_deallocation(&mut self, size: usize) {
self.total_deallocations += 1;
self.current_allocated = self.current_allocated.saturating_sub(size);
self.update_memory_efficiency();
self.last_update = Instant::now();
}
pub fn record_allocation_failure(&mut self) {
self.allocation_failures += 1;
self.last_update = Instant::now();
}
pub fn update_memory_efficiency(&mut self) {
if self.peak_allocated > 0 {
self.memory_efficiency = self.current_allocated as f64 / self.peak_allocated as f64;
}
}
pub fn allocation_rate(&self) -> f64 {
let elapsed = self.last_update.duration_since(
Instant::now() - Duration::from_secs(60), );
if elapsed.as_secs() > 0 {
self.total_allocations as f64 / elapsed.as_secs() as f64
} else {
0.0
}
}
pub fn deallocation_rate(&self) -> f64 {
let elapsed = self.last_update.duration_since(
Instant::now() - Duration::from_secs(60), );
if elapsed.as_secs() > 0 {
self.total_deallocations as f64 / elapsed.as_secs() as f64
} else {
0.0
}
}
pub fn failure_rate(&self) -> f64 {
if self.total_allocations > 0 {
self.allocation_failures as f64 / self.total_allocations as f64
} else {
0.0
}
}
pub fn is_healthy(&self) -> bool {
self.failure_rate() < 0.01 && self.memory_efficiency > 0.7 && self.avg_allocation_time < Duration::from_millis(1) }
}
impl Default for AllocatorAdvancedMetrics {
fn default() -> Self {
Self {
size_distribution: SizeDistribution::default(),
latency_percentiles: LatencyPercentiles::default(),
fragmentation_metrics: AllocatorFragmentationMetrics::default(),
cache_performance: AllocatorCachePerformance::default(),
contention_metrics: ContentionMetrics::default(),
}
}
}
impl Default for SizeDistribution {
fn default() -> Self {
Self {
small_count: 0,
medium_count: 0,
large_count: 0,
average_size: 0,
size_variance: 0.0,
common_sizes: Vec::new(),
}
}
}
impl SizeDistribution {
pub fn record_allocation(&mut self, size: usize) {
match size {
s if s < 1024 => self.small_count += 1,
s if s <= 1024 * 1024 => self.medium_count += 1,
_ => self.large_count += 1,
}
let total_allocations = self.small_count + self.medium_count + self.large_count;
if total_allocations == 1 {
self.average_size = size;
} else {
self.average_size = (self.average_size * (total_allocations - 1) as usize + size)
/ total_allocations as usize;
}
}
}
impl Default for LatencyPercentiles {
fn default() -> Self {
Self {
p50: Duration::from_secs(0),
p90: Duration::from_secs(0),
p95: Duration::from_secs(0),
p99: Duration::from_secs(0),
p999: Duration::from_secs(0),
max: Duration::from_secs(0),
}
}
}
impl LatencyPercentiles {
pub fn record_latency(&mut self, latency: Duration) {
self.max = self.max.max(latency);
if self.p50 == Duration::from_secs(0) || latency < self.p50 {
self.p50 = latency;
}
}
}
impl Default for AllocatorFragmentationMetrics {
fn default() -> Self {
Self {
internal_fragmentation: 0.0,
external_fragmentation: 0.0,
free_block_count: 0,
largest_free_block: 0,
fragmentation_trend: FragmentationTrend::Unknown,
}
}
}
impl Default for AllocatorCachePerformance {
fn default() -> Self {
Self {
allocation_cache_hit_rate: 0.0,
free_list_efficiency: 0.0,
cache_warming_effectiveness: 0.0,
cache_pollution_level: 0.0,
}
}
}
impl Default for ContentionMetrics {
fn default() -> Self {
Self {
lock_contention_time: Duration::from_secs(0),
avg_contention_per_alloc: Duration::from_secs(0),
peak_concurrent_allocations: 0,
contention_hotspots: Vec::new(),
}
}
}
impl Default for AllocatorPerformanceProfile {
fn default() -> Self {
Self {
performance_tier: PerformanceTier::Medium,
optimization_opportunities: Vec::new(),
recommended_config: Vec::new(),
performance_score: 0.5,
}
}
}
impl PerformanceSnapshot {
pub fn new() -> Self {
Self {
timestamp: Instant::now(),
allocation_latency: Duration::from_secs(0),
bandwidth_utilization: 0.0,
cache_hit_rate: 0.0,
cpu_utilization: 0.0,
}
}
pub fn update(&mut self, latency: Duration, bandwidth: f64, cache_rate: f64, cpu: f64) {
self.timestamp = Instant::now();
self.allocation_latency = latency;
self.bandwidth_utilization = bandwidth;
self.cache_hit_rate = cache_rate;
self.cpu_utilization = cpu;
}
}
impl MemoryStateSnapshot {
pub fn new() -> Self {
Self {
total_allocated: 0,
available_memory: 0,
fragmentation_level: 0.0,
active_allocations: 0,
}
}
pub fn update(
&mut self,
allocated: usize,
available: usize,
fragmentation: f64,
active: usize,
) {
self.total_allocated = allocated;
self.available_memory = available;
self.fragmentation_level = fragmentation;
self.active_allocations = active;
}
pub fn memory_pressure(&self) -> f64 {
if self.total_allocated + self.available_memory == 0 {
0.0
} else {
self.total_allocated as f64 / (self.total_allocated + self.available_memory) as f64
}
}
}
pub struct AllocatorStatsAggregator {
stats: HashMap<String, ScirS2AllocatorStats>,
}
impl AllocatorStatsAggregator {
pub fn new() -> Self {
Self {
stats: HashMap::new(),
}
}
pub fn update_stats(&mut self, stats: ScirS2AllocatorStats) {
self.stats.insert(stats.name.clone(), stats);
}
pub fn get_stats(&self, name: &str) -> Option<&ScirS2AllocatorStats> {
self.stats.get(name)
}
pub fn get_all_stats(&self) -> &HashMap<String, ScirS2AllocatorStats> {
&self.stats
}
pub fn calculate_aggregate_metrics(&self) -> AggregateMetrics {
let mut total_allocations = 0;
let mut total_deallocations = 0;
let mut total_allocated = 0;
let mut total_failures = 0;
let mut efficiency_sum = 0.0;
for stats in self.stats.values() {
total_allocations += stats.total_allocations;
total_deallocations += stats.total_deallocations;
total_allocated += stats.current_allocated;
total_failures += stats.allocation_failures;
efficiency_sum += stats.memory_efficiency;
}
let allocator_count = self.stats.len();
let avg_efficiency = if allocator_count > 0 {
efficiency_sum / allocator_count as f64
} else {
0.0
};
AggregateMetrics {
total_allocations,
total_deallocations,
total_allocated,
total_failures,
average_efficiency: avg_efficiency,
allocator_count,
}
}
}
#[derive(Debug, Clone)]
pub struct AggregateMetrics {
pub total_allocations: u64,
pub total_deallocations: u64,
pub total_allocated: usize,
pub total_failures: u64,
pub average_efficiency: f64,
pub allocator_count: usize,
}