memscope-rs 0.2.3

A memory tracking library for Rust applications.
Documentation
# Snapshot Module

## Overview

The snapshot module provides memory snapshot construction and aggregation capabilities. It builds point-in-time views of memory usage from events stored in the EventStore, enabling analysis of current memory state and patterns.

## Components

### 1. SnapshotEngine

**File**: `src/snapshot/engine.rs`

**Purpose**: Builds memory snapshots from event data.

**Key Features**:
- Read-only: Does not consume events from EventStore
- Efficient: Optimized for fast snapshot construction
- Comprehensive: Captures all relevant memory state
- Thread-safe: Safe for concurrent access

**Core Implementation**:

```rust
pub struct SnapshotEngine {
    /// Reference to the event store
    event_store: SharedEventStore,
}

impl SnapshotEngine {
    /// Build a snapshot from the current event store state
    pub fn build_snapshot(&self) -> MemorySnapshot {
        let events = self.event_store.snapshot();
        self.build_snapshot_from_events(events)
    }

    /// Build a snapshot from a specific set of events
    pub fn build_snapshot_from_events(&self, events: Vec<MemoryEvent>) -> MemorySnapshot {
        let mut snapshot = MemorySnapshot::new();
        let mut ptr_to_allocation: HashMap<usize, ActiveAllocation> = HashMap::new();
        let mut thread_stats: HashMap<u64, ThreadMemoryStats> = HashMap::new();
        let mut peak_memory: usize = 0;
        let mut current_memory: usize = 0;

        for event in events {
            match event.event_type {
                MemoryEventType::Allocate | MemoryEventType::Reallocate => {
                    // Record allocation
                    let allocation = ActiveAllocation {
                        ptr: event.ptr,
                        size: event.size,
                        allocated_at: event.timestamp,
                        var_name: event.var_name,
                        type_name: event.type_name,
                        thread_id: event.thread_id,
                    };

                    ptr_to_allocation.insert(event.ptr, allocation);

                    // Update stats
                    snapshot.stats.total_allocations += 1;
                    snapshot.stats.total_allocated += event.size;
                    current_memory += event.size;

                    // Update thread stats
                    let thread_stat = thread_stats.entry(event.thread_id).or_insert_with(
                        || ThreadMemoryStats {
                            thread_id: event.thread_id,
                            allocation_count: 0,
                            total_allocated: 0,
                            current_memory: 0,
                            peak_memory: 0,
                        }
                    );
                    thread_stat.allocation_count += 1;
                    thread_stat.total_allocated += event.size;
                    thread_stat.current_memory += event.size;
                    if thread_stat.current_memory > thread_stat.peak_memory {
                        thread_stat.peak_memory = thread_stat.current_memory;
                    }
                }
                MemoryEventType::Deallocate => {
                    // Remove allocation
                    if let Some(allocation) = ptr_to_allocation.remove(&event.ptr) {
                        snapshot.stats.total_deallocations += 1;
                        snapshot.stats.total_deallocated += allocation.size;
                        current_memory -= allocation.size;

                        // Update thread stats
                        if let Some(thread_stat) = thread_stats.get_mut(&event.thread_id) {
                            thread_stat.current_memory -= allocation.size;
                        }
                    } else {
                        snapshot.stats.unmatched_deallocations += 1;
                    }
                }
                _ => {}
            }

            // Update peak memory
            if current_memory > peak_memory {
                peak_memory = current_memory;
            }
        }

        // Build final snapshot
        snapshot.active_allocations = ptr_to_allocation;
        snapshot.thread_stats = thread_stats;
        snapshot.stats.active_allocations = snapshot.active_allocations.len();
        snapshot.stats.current_memory = current_memory;
        snapshot.stats.peak_memory = peak_memory;

        snapshot
    }
}
```

### 2. MemorySnapshot

**File**: `src/snapshot/types.rs`

**Purpose**: Represents a point-in-time view of memory state.

**Snapshot Structure**:

```rust
pub struct MemorySnapshot {
    /// Active allocations
    pub active_allocations: HashMap<usize, ActiveAllocation>,
    /// Thread-specific memory statistics
    pub thread_stats: HashMap<u64, ThreadMemoryStats>,
    /// Overall statistics
    pub stats: SnapshotStats,
}

pub struct SnapshotStats {
    pub total_allocations: usize,
    pub total_deallocations: usize,
    pub active_allocations: usize,
    pub total_allocated: usize,
    pub total_deallocated: usize,
    pub current_memory: usize,
    pub peak_memory: usize,
    pub unmatched_deallocations: usize,
}
```

## Usage Examples

### Basic Usage

```rust
use memscope::snapshot::{SnapshotEngine, MemorySnapshot};
use memscope::event_store::EventStore;
use std::sync::Arc;

// Create snapshot engine
let event_store = Arc::new(EventStore::new());
let engine = SnapshotEngine::new(event_store);

// Build snapshot
let snapshot = engine.build_snapshot();

// Access snapshot data
println!("Active allocations: {}", snapshot.active_count());
println!("Current memory: {} bytes", snapshot.current_memory());
println!("Peak memory: {} bytes", snapshot.peak_memory());
```

### Snapshot with Events

```rust
// Add some events
event_store.record(MemoryEvent::allocate(0x1000, 1024, 1));
event_store.record(MemoryEvent::allocate(0x2000, 2048, 1));
event_store.record(MemoryEvent::deallocate(0x1000, 1024, 1));

// Build snapshot
let snapshot = engine.build_snapshot();

// Check results
assert_eq!(snapshot.active_count(), 1);
assert_eq!(snapshot.current_memory(), 2048);
```

## Design Principles

### 1. Read-only Operations
Snapshots do not modify event data:
- **Benefits**: Safe, reproducible analysis
- **Trade-off**: Must copy data for snapshot

### 2. Efficient Construction
Optimized for fast snapshot building:
- **Benefits**: Quick analysis
- **Trade-off**: May use more memory during construction

### 3. Thread Safety
Safe for concurrent access:
- **Benefits**: Multi-threaded analysis
- **Trade-off**: Synchronization overhead

## Best Practices

1. **Snapshot Frequency**: Balance between accuracy and performance
2. **Memory Management**: Clear old snapshots to free memory
3. **Thread Safety**: Use Arc<SnapshotEngine> for shared access
4. **Error Handling**: Always handle snapshot construction errors

## Limitations

1. **Point-in-time**: Only shows state at construction time
2. **Memory Usage**: Snapshots consume memory
3. **Construction Time**: Large datasets may take time to build
4. **Event Order**: Depends on correct event ordering

## Future Improvements

1. **Incremental Snapshots**: Update existing snapshots incrementally
2. **Differential Snapshots**: Compare snapshots to find changes
3. **Compression**: Compress snapshot data
4. **Persistence**: Save snapshots to disk
5. **Time Travel**: Reconstruct past states from events