[TSM.ID].[11031972] PXE : Platform X Ecosystem I [118 Module -LIVE-]
This commit is contained in:
@@ -0,0 +1,9 @@
|
||||
[package]
|
||||
name = "xcu-garbage-collector"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
authors = ["TSM.ID <tsm@tsm.id>"]
|
||||
description = "[TSM.ID].[11031972] xcu-garbage-collector"
|
||||
|
||||
[dependencies]
|
||||
|
||||
@@ -0,0 +1,118 @@
|
||||
//! [TSM.ID].[11031972] — Platform X Ecosystem
|
||||
//! Mark-Sweep collector with tri-color marking
|
||||
|
||||
use crate::{GcColor, GcError, GcConfig, Result};
|
||||
|
||||
struct GcObject {
|
||||
data: Vec<u8>,
|
||||
color: GcColor,
|
||||
refs: Vec<usize>,
|
||||
generation: u8,
|
||||
ref_count: u32,
|
||||
}
|
||||
|
||||
pub struct MarkSweepCollector {
|
||||
objects: Vec<Option<GcObject>>,
|
||||
roots: Vec<usize>,
|
||||
free_slots: Vec<usize>,
|
||||
collections: u64,
|
||||
bytes_freed: u64,
|
||||
config: GcConfig,
|
||||
}
|
||||
|
||||
impl MarkSweepCollector {
|
||||
pub fn new(config: GcConfig) -> Self {
|
||||
Self {
|
||||
objects: Vec::with_capacity(config.heap_size / 64),
|
||||
roots: Vec::new(), free_slots: Vec::new(),
|
||||
collections: 0, bytes_freed: 0, config,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn allocate(&mut self, size: usize) -> Result<usize> {
|
||||
let total: usize = self.objects.iter().filter_map(|o| o.as_ref()).map(|o| o.data.len()).sum();
|
||||
if total + size > self.config.heap_size {
|
||||
self.collect()?;
|
||||
let after: usize = self.objects.iter().filter_map(|o| o.as_ref()).map(|o| o.data.len()).sum();
|
||||
if after + size > self.config.heap_size { return Err(GcError::AllocationFailed); }
|
||||
}
|
||||
let obj = GcObject { data: vec![0u8; size], color: GcColor::White, refs: Vec::new(), generation: 0, ref_count: 0 };
|
||||
if let Some(slot) = self.free_slots.pop() {
|
||||
self.objects[slot] = Some(obj);
|
||||
Ok(slot)
|
||||
} else {
|
||||
let idx = self.objects.len();
|
||||
self.objects.push(Some(obj));
|
||||
Ok(idx)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn add_root(&mut self, idx: usize) { self.roots.push(idx); }
|
||||
pub fn add_reference(&mut self, from: usize, to: usize) -> Result<()> {
|
||||
if from >= self.objects.len() || to >= self.objects.len() { return Err(GcError::InvalidReference); }
|
||||
if let Some(obj) = &mut self.objects[from] { obj.refs.push(to); }
|
||||
if let Some(obj) = &mut self.objects[to] { obj.ref_count += 1; }
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn collect(&mut self) -> Result<usize> {
|
||||
// Phase 1: Mark all white
|
||||
for obj in self.objects.iter_mut().flatten() { obj.color = GcColor::White; }
|
||||
// Phase 2: Mark roots gray
|
||||
let roots = self.roots.clone();
|
||||
for &r in &roots {
|
||||
if let Some(obj) = self.objects.get_mut(r).and_then(|o| o.as_mut()) { obj.color = GcColor::Gray; }
|
||||
}
|
||||
// Phase 3: Process gray objects
|
||||
let mut changed = true;
|
||||
while changed {
|
||||
changed = false;
|
||||
let len = self.objects.len();
|
||||
for i in 0..len {
|
||||
let refs = if let Some(Some(obj)) = self.objects.get(i) {
|
||||
if obj.color == GcColor::Gray { obj.refs.clone() } else { continue; }
|
||||
} else { continue; };
|
||||
if let Some(obj) = self.objects[i].as_mut() { obj.color = GcColor::Black; }
|
||||
for r in refs {
|
||||
if let Some(obj) = self.objects.get_mut(r).and_then(|o| o.as_mut()) {
|
||||
if obj.color == GcColor::White { obj.color = GcColor::Gray; changed = true; }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// Phase 4: Sweep white objects
|
||||
let mut freed = 0usize;
|
||||
for i in 0..self.objects.len() {
|
||||
let is_white = self.objects[i].as_ref().map(|o| o.color == GcColor::White).unwrap_or(false);
|
||||
if is_white {
|
||||
if let Some(obj) = self.objects[i].take() {
|
||||
freed += obj.data.len();
|
||||
self.free_slots.push(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
self.collections += 1;
|
||||
self.bytes_freed += freed as u64;
|
||||
Ok(freed)
|
||||
}
|
||||
|
||||
pub fn stats(&self) -> (u64, u64, usize) {
|
||||
let alive = self.objects.iter().filter(|o| o.is_some()).count();
|
||||
(self.collections, self.bytes_freed, alive)
|
||||
}
|
||||
|
||||
pub fn promote_survivors(&mut self) {
|
||||
for obj in self.objects.iter_mut().flatten() {
|
||||
if obj.color == GcColor::Black && obj.generation < 255 {
|
||||
obj.generation += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn object_generation(&self, idx: usize) -> Result<u8> {
|
||||
self.objects.get(idx)
|
||||
.and_then(|o| o.as_ref())
|
||||
.map(|o| o.generation)
|
||||
.ok_or(GcError::InvalidReference)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
//! [TSM.ID].[11031972] — Platform X Ecosystem
|
||||
//! xcu-garbage-collector — Deterministic Memory Cleaner
|
||||
#![deny(warnings)]
|
||||
|
||||
pub mod collector;
|
||||
pub mod tracker;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum GcError {
|
||||
AllocationFailed,
|
||||
InvalidReference,
|
||||
CollectionFailed(String),
|
||||
HeapCorrupted,
|
||||
}
|
||||
impl std::fmt::Display for GcError {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
Self::AllocationFailed => write!(f, "Allocation failed"),
|
||||
Self::InvalidReference => write!(f, "Invalid reference"),
|
||||
Self::CollectionFailed(e) => write!(f, "Collection failed: {e}"),
|
||||
Self::HeapCorrupted => write!(f, "Heap corrupted"),
|
||||
}
|
||||
}
|
||||
}
|
||||
impl std::error::Error for GcError {}
|
||||
pub type Result<T> = std::result::Result<T, GcError>;
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq)]
|
||||
pub enum GcColor { White, Gray, Black }
|
||||
|
||||
pub struct GcConfig {
|
||||
pub heap_size: usize,
|
||||
pub threshold: usize,
|
||||
pub generation_count: u8,
|
||||
}
|
||||
|
||||
impl Default for GcConfig {
|
||||
fn default() -> Self { Self { heap_size: 1_048_576, threshold: 768_000, generation_count: 3 } }
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
//! [TSM.ID].[11031972] — Platform X Ecosystem
|
||||
//! Allocation tracker with leak detection
|
||||
|
||||
use crate::Result;
|
||||
use std::collections::HashMap;
|
||||
|
||||
struct AllocationRecord {
|
||||
size: usize,
|
||||
timestamp: u64,
|
||||
freed: bool,
|
||||
}
|
||||
|
||||
pub struct AllocationTracker {
|
||||
records: HashMap<usize, AllocationRecord>,
|
||||
total_allocated: u64,
|
||||
total_freed: u64,
|
||||
peak_memory: u64,
|
||||
current_memory: u64,
|
||||
}
|
||||
|
||||
impl AllocationTracker {
|
||||
pub fn new() -> Self {
|
||||
Self { records: HashMap::new(), total_allocated: 0, total_freed: 0, peak_memory: 0, current_memory: 0 }
|
||||
}
|
||||
|
||||
pub fn track_alloc(&mut self, id: usize, size: usize) -> Result<()> {
|
||||
let now = std::time::SystemTime::now().duration_since(std::time::UNIX_EPOCH).expect("[TSM.ID]").as_millis() as u64;
|
||||
self.records.insert(id, AllocationRecord { size, timestamp: now, freed: false });
|
||||
self.total_allocated += size as u64;
|
||||
self.current_memory += size as u64;
|
||||
if self.current_memory > self.peak_memory { self.peak_memory = self.current_memory; }
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn track_free(&mut self, id: usize) -> Result<()> {
|
||||
if let Some(rec) = self.records.get_mut(&id) {
|
||||
rec.freed = true;
|
||||
self.total_freed += rec.size as u64;
|
||||
self.current_memory = self.current_memory.saturating_sub(rec.size as u64);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn detect_leaks(&self) -> Vec<(usize, usize, u64)> {
|
||||
self.records.iter()
|
||||
.filter(|(_, r)| !r.freed)
|
||||
.map(|(&id, r)| (id, r.size, r.timestamp))
|
||||
.collect()
|
||||
}
|
||||
|
||||
pub fn peak_memory(&self) -> u64 { self.peak_memory }
|
||||
pub fn current_memory(&self) -> u64 { self.current_memory }
|
||||
}
|
||||
|
||||
impl Default for AllocationTracker {
|
||||
fn default() -> Self { Self::new() }
|
||||
}
|
||||
Reference in New Issue
Block a user