use std::env;
use std::time::Instant;
use realizar::apr::{AprV2Model, HEADER_SIZE, MAGIC};
use realizar::error::Result;
fn main() -> Result<()> {
println!("=== Memory-Mapped APR Loading Demo ===\n");
let args: Vec<String> = env::args().collect();
if args.len() > 1 {
let model_path = &args[1];
demo_real_model(model_path)?;
} else {
demo_synthetic_model()?;
}
println!("\n=== Demo Complete ===");
Ok(())
}
fn demo_real_model(path: &str) -> Result<()> {
println!("Loading model: {}\n", path);
let start = Instant::now();
let model = AprV2Model::load(path)?;
let load_time = start.elapsed();
println!("Model Info:");
println!(" Tensors: {}", model.tensor_count());
println!(" Parameters: ~{}", model.estimated_parameters());
println!(" Load time: {:?}", load_time);
println!(" Using mmap: {}", model.is_mmap());
println!();
let names = model.tensor_names();
println!("Tensors (first 10 of {}):", names.len());
for name in names.iter().take(10) {
println!(" - {}", name);
}
if names.len() > 10 {
println!(" ... and {} more", names.len() - 10);
}
println!();
println!("Simulating GPU transfer...");
let transfer_start = Instant::now();
for name in model.tensor_names() {
let _bytes = model.get_tensor_bytes(name)?;
}
let transfer_time = transfer_start.elapsed();
println!(" Transfer time: {:?}", transfer_time);
println!();
#[cfg(unix)]
{
println!("Releasing CPU pages (madvise MADV_DONTNEED)...");
let release_start = Instant::now();
model.release_cpu_pages()?;
let release_time = release_start.elapsed();
println!(" Release time: {:?}", release_time);
println!();
println!(" Pages are now backed by file, not zram.");
println!(" Re-access will fault from disk (cheap for SSDs).");
}
Ok(())
}
fn demo_synthetic_model() -> Result<()> {
println!("No model path provided. Creating synthetic demo.\n");
let mut data = vec![0u8; 256];
data[0..4].copy_from_slice(&MAGIC);
data[4] = 2; data[5] = 0; data[6..8].copy_from_slice(&0u16.to_le_bytes()); data[8..12].copy_from_slice(&0u32.to_le_bytes()); data[12..20].copy_from_slice(&(HEADER_SIZE as u64).to_le_bytes()); data[20..24].copy_from_slice(&0u32.to_le_bytes()); data[24..32].copy_from_slice(&(HEADER_SIZE as u64).to_le_bytes()); data[32..40].copy_from_slice(&(HEADER_SIZE as u64).to_le_bytes());
let model = AprV2Model::from_bytes(data)?;
println!("Synthetic Model Info:");
println!(" Tensors: {}", model.tensor_count());
println!(
" Using mmap: {} (from_bytes always uses heap)",
model.is_mmap()
);
println!();
println!("Loading Strategy:");
println!(" - AprV2Model::load(path) → mmap for uncompressed files");
println!(" - AprV2Model::from_bytes(v) → heap (for network/compressed)");
println!();
println!("Key APIs for Memory Management:");
println!();
println!(" // Load with mmap (zero-copy)");
println!(" let model = AprV2Model::load(\"model.apr\")?;");
println!();
println!(" // Check if using mmap");
println!(" if model.is_mmap() {{");
println!(" println!(\"Using memory-mapped I/O\");");
println!(" }}");
println!();
println!(" // Transfer tensors to GPU");
println!(" for name in model.tensor_names() {{");
println!(" let bytes = model.get_tensor_bytes(&name)?;");
println!(" cuda::memcpy_htod(gpu_ptr, bytes);");
println!(" }}");
println!();
println!(" // Release CPU pages (Unix only)");
println!(" #[cfg(unix)]");
println!(" model.release_cpu_pages()?;");
println!();
println!(" // Pages now backed by file, not zram!");
println!();
println!("Monitor zram usage:");
println!(" cat /sys/block/zram0/mm_stat # Raw stats");
println!(" zramctl # Human-readable");
Ok(())
}