Spaces:
Runtime error
Runtime error
| """ | |
| Virtual RAM Module - 128GB System Memory Abstraction | |
| This module implements a symbolic representation of 128GB system RAM using | |
| efficient data structures and lazy allocation strategies. It avoids allocating | |
| real memory and uses dictionaries or sparse mappings to simulate blocks. | |
| """ | |
| import time | |
| from typing import Dict, Any, Optional, Union | |
| from dataclasses import dataclass | |
| import numpy as np | |
| class RAMBlock: | |
| """Represents a block of memory in the symbolic RAM.""" | |
| name: str | |
| size_bytes: int | |
| allocated_time: float | |
| last_accessed: float | |
| access_count: int = 0 | |
| # We use a symbolic representation instead of actual data | |
| # The data field will be None for large blocks to avoid memory allocation | |
| data: Optional[Union[np.ndarray, bytes]] = None | |
| is_symbolic: bool = True # True if this is a symbolic block (no real data) | |
| class VirtualRAM: | |
| """ | |
| Virtual RAM class that simulates 128GB of system memory symbolically. | |
| This class provides block allocation, tracking, and transfer capabilities | |
| without actually allocating large amounts of physical memory. | |
| """ | |
| def __init__(self, capacity_gb: int = 128): | |
| self.capacity_bytes = capacity_gb * 1024 * 1024 * 1024 # Convert GB to bytes | |
| self.capacity_gb = capacity_gb | |
| # Block registry - stores metadata about allocated blocks | |
| self.blocks: Dict[str, RAMBlock] = {} | |
| # Memory usage tracking | |
| self.allocated_bytes = 0 | |
| self.allocation_counter = 0 | |
| # Access simulation parameters | |
| self.access_delay_ms = 0.1 # Simulated RAM access delay | |
| self.transfer_bandwidth_gbps = 51.2 # DDR5-6400 bandwidth | |
| # Statistics | |
| self.total_allocations = 0 | |
| self.total_deallocations = 0 | |
| self.total_accesses = 0 | |
| self.total_transfers = 0 | |
| print(f"VirtualRAM initialized with {capacity_gb}GB capacity") | |
| def allocate_block(self, name: str, size_bytes: int, | |
| store_data: bool = False) -> bool: | |
| """ | |
| Allocate a block of memory symbolically. | |
| Args: | |
| name: Unique name for the block | |
| size_bytes: Size of the block in bytes | |
| store_data: If True, actually allocate small amounts of real data for testing | |
| If False (default), only store metadata symbolically | |
| Returns: | |
| True if allocation successful, False if not enough space or name exists | |
| """ | |
| # Check if name already exists | |
| if name in self.blocks: | |
| print(f"Block '{name}' already exists") | |
| return False | |
| # Check if we have enough capacity | |
| if self.allocated_bytes + size_bytes > self.capacity_bytes: | |
| print(f"Not enough capacity: requested {size_bytes:,} bytes, " | |
| f"available {self.capacity_bytes - self.allocated_bytes:,} bytes") | |
| return False | |
| # Create the block | |
| current_time = time.time() | |
| # For all blocks, we store only metadata to avoid memory issues | |
| actual_data = None | |
| is_symbolic = True | |
| # If store_data is explicitly requested and size is very small, we can store actual data | |
| if store_data and size_bytes <= 1024 * 1024 * 10: # Up to 10MB for actual data | |
| actual_data = np.zeros(size_bytes, dtype=np.uint8) | |
| is_symbolic = False | |
| print(f"Allocated real data for block \'{name}\' ({size_bytes:,} bytes)") | |
| else: | |
| print(f"Created symbolic block \'{name}\' of {size_bytes:,} bytes") | |
| block = RAMBlock( | |
| name=name, | |
| size_bytes=size_bytes, | |
| allocated_time=current_time, | |
| last_accessed=current_time, | |
| data=actual_data, | |
| is_symbolic=is_symbolic | |
| ) | |
| self.blocks[name] = block | |
| self.allocated_bytes += size_bytes | |
| self.total_allocations += 1 | |
| self.allocation_counter += 1 | |
| print(f"Allocated block '{name}': {size_bytes:,} bytes " | |
| f"({'symbolic' if is_symbolic else 'real data'})") | |
| return True | |
| def get_block(self, name: str) -> Optional[RAMBlock]: | |
| """ | |
| Retrieve a block by name and simulate access delay. | |
| Args: | |
| name: Name of the block to retrieve | |
| Returns: | |
| RAMBlock if found, None otherwise | |
| """ | |
| if name not in self.blocks: | |
| return None | |
| # Simulate access delay | |
| time.sleep(self.access_delay_ms / 1000.0) | |
| # Update access statistics | |
| block = self.blocks[name] | |
| block.last_accessed = time.time() | |
| block.access_count += 1 | |
| self.total_accesses += 1 | |
| return block | |
| def release_block(self, name: str) -> bool: | |
| """ | |
| Deallocate a block of memory. | |
| Args: | |
| name: Name of the block to deallocate | |
| Returns: | |
| True if deallocation successful, False if block not found | |
| """ | |
| if name not in self.blocks: | |
| print(f"Block '{name}' not found") | |
| return False | |
| block = self.blocks[name] | |
| self.allocated_bytes -= block.size_bytes | |
| self.total_deallocations += 1 | |
| del self.blocks[name] | |
| print(f"Released block '{name}': {block.size_bytes:,} bytes") | |
| return True | |
| def transfer_to_vram(self, block_name: str, vram_instance, | |
| vram_name: Optional[str] = None) -> Optional[str]: | |
| """ | |
| Transfer a RAM block to VRAM with delay simulation. | |
| Args: | |
| block_name: Name of the RAM block to transfer | |
| vram_instance: Instance of VRAM to transfer to | |
| vram_name: Optional name for the block in VRAM | |
| Returns: | |
| VRAM block ID if successful, None otherwise | |
| """ | |
| # Get the block from RAM | |
| block = self.get_block(block_name) | |
| if block is None: | |
| print(f"Block '{block_name}' not found in RAM") | |
| return None | |
| # Calculate transfer time based on bandwidth | |
| transfer_time_ms = (block.size_bytes / (self.transfer_bandwidth_gbps * 1e9)) * 1000 | |
| print(f"Transferring '{block_name}' ({block.size_bytes:,} bytes) " | |
| f"from RAM to VRAM (estimated {transfer_time_ms:.2f}ms)") | |
| # Prepare data for transfer | |
| if block.is_symbolic: | |
| # For symbolic blocks, create a small representative data sample | |
| sample_size = min(1024, block.size_bytes) # 1KB sample | |
| transfer_data = np.random.randint(0, 256, sample_size, dtype=np.uint8) | |
| print(f"Using {sample_size} byte sample for symbolic block transfer") | |
| else: | |
| # Use actual data | |
| transfer_data = block.data | |
| # Perform the transfer to VRAM | |
| if vram_name is None: | |
| vram_name = f"ram_transfer_{block_name}" | |
| vram_id = vram_instance.transfer_from_ram(vram_name, transfer_data, | |
| delay_ms=transfer_time_ms) | |
| if vram_id: | |
| self.total_transfers += 1 | |
| print(f"Successfully transferred '{block_name}' to VRAM as '{vram_id}'") | |
| else: | |
| print(f"Failed to transfer '{block_name}' to VRAM") | |
| return vram_id | |
| def create_tensor_block(self, name: str, shape: tuple, dtype=np.float32) -> bool: | |
| """ | |
| Create a tensor block with specified shape and data type. | |
| Args: | |
| name: Name for the tensor block | |
| shape: Shape of the tensor (e.g., (1024, 1024, 3)) | |
| dtype: Data type of the tensor | |
| Returns: | |
| True if creation successful, False otherwise | |
| """ | |
| # Calculate size in bytes | |
| element_size = np.dtype(dtype).itemsize | |
| total_elements = np.prod(shape) | |
| size_bytes = total_elements * element_size | |
| # Allocate the block symbolically | |
| success = self.allocate_block(name, size_bytes, store_data=False) | |
| if success: | |
| # Store tensor metadata | |
| block = self.blocks[name] | |
| block.tensor_shape = shape | |
| block.tensor_dtype = dtype | |
| print(f"Created tensor block '{name}' with shape {shape} and dtype {dtype}") | |
| return success | |
| def info(self) -> Dict[str, Any]: | |
| """ | |
| Get comprehensive information about the Virtual RAM state. | |
| Returns: | |
| Dictionary containing RAM usage statistics and metadata | |
| """ | |
| used_bytes = self.allocated_bytes | |
| free_bytes = self.capacity_bytes - used_bytes | |
| utilization_percent = (used_bytes / self.capacity_bytes) * 100 | |
| # Calculate average block size | |
| avg_block_size = used_bytes / len(self.blocks) if self.blocks else 0 | |
| # Find largest and smallest blocks | |
| largest_block = max(self.blocks.values(), key=lambda b: b.size_bytes) if self.blocks else None | |
| smallest_block = min(self.blocks.values(), key=lambda b: b.size_bytes) if self.blocks else None | |
| # Count symbolic vs real blocks | |
| symbolic_blocks = sum(1 for b in self.blocks.values() if b.is_symbolic) | |
| real_blocks = len(self.blocks) - symbolic_blocks | |
| info_dict = { | |
| "capacity_gb": self.capacity_gb, | |
| "capacity_bytes": self.capacity_bytes, | |
| "used_bytes": used_bytes, | |
| "free_bytes": free_bytes, | |
| "utilization_percent": utilization_percent, | |
| "total_blocks": len(self.blocks), | |
| "symbolic_blocks": symbolic_blocks, | |
| "real_data_blocks": real_blocks, | |
| "avg_block_size_bytes": avg_block_size, | |
| "largest_block_name": largest_block.name if largest_block else None, | |
| "largest_block_size": largest_block.size_bytes if largest_block else 0, | |
| "smallest_block_name": smallest_block.name if smallest_block else None, | |
| "smallest_block_size": smallest_block.size_bytes if smallest_block else 0, | |
| "total_allocations": self.total_allocations, | |
| "total_deallocations": self.total_deallocations, | |
| "total_accesses": self.total_accesses, | |
| "total_transfers": self.total_transfers, | |
| "block_names": list(self.blocks.keys()) | |
| } | |
| return info_dict | |
| def print_info(self) -> None: | |
| """Print a formatted summary of Virtual RAM information.""" | |
| info = self.info() | |
| print("\n" + "="*50) | |
| print("VIRTUAL RAM INFORMATION") | |
| print("="*50) | |
| print(f"Capacity: {info['capacity_gb']} GB ({info['capacity_bytes']:,} bytes)") | |
| print(f"Used: {info['used_bytes']:,} bytes ({info['utilization_percent']:.2f}%)") | |
| print(f"Free: {info['free_bytes']:,} bytes") | |
| print(f"Total Blocks: {info['total_blocks']}") | |
| print(f" - Symbolic blocks: {info['symbolic_blocks']}") | |
| print(f" - Real data blocks: {info['real_data_blocks']}") | |
| if info['total_blocks'] > 0: | |
| print(f"Average block size: {info['avg_block_size_bytes']:,.0f} bytes") | |
| print(f"Largest block: '{info['largest_block_name']}' ({info['largest_block_size']:,} bytes)") | |
| print(f"Smallest block: '{info['smallest_block_name']}' ({info['smallest_block_size']:,} bytes)") | |
| print(f"\nStatistics:") | |
| print(f" - Total allocations: {info['total_allocations']}") | |
| print(f" - Total deallocations: {info['total_deallocations']}") | |
| print(f" - Total accesses: {info['total_accesses']}") | |
| print(f" - Total transfers: {info['total_transfers']}") | |
| if info['block_names']: | |
| print(f"\nBlock names: {', '.join(info['block_names'])}") | |
| print("="*50) | |
| def simulate_workload(self, num_operations: int = 100) -> None: | |
| """ | |
| Simulate a typical workload with allocations, accesses, and deallocations. | |
| Args: | |
| num_operations: Number of operations to simulate | |
| """ | |
| print(f"\nSimulating workload with {num_operations} operations...") | |
| import random | |
| for i in range(num_operations): | |
| operation = random.choice(['allocate', 'access', 'deallocate']) | |
| if operation == 'allocate' and len(self.blocks) < 50: # Limit to 50 blocks | |
| size = random.randint(1024, 100 * 1024 * 1024) # 1KB to 100MB | |
| name = f"workload_block_{i}" | |
| self.allocate_block(name, size) | |
| elif operation == 'access' and self.blocks: | |
| block_name = random.choice(list(self.blocks.keys())) | |
| self.get_block(block_name) | |
| elif operation == 'deallocate' and self.blocks: | |
| block_name = random.choice(list(self.blocks.keys())) | |
| self.release_block(block_name) | |
| print(f"Workload simulation completed.") | |
| if __name__ == "__main__": | |
| # Test the VirtualRAM module | |
| print("Testing VirtualRAM module...") | |
| # Create a VirtualRAM instance with 128GB capacity | |
| vram = VirtualRAM(capacity_gb=128) | |
| # Test basic allocation | |
| print("\n1. Testing basic allocation...") | |
| vram.allocate_block("small_buffer", 1024 * 1024, store_data=True) # 1MB with real data | |
| vram.allocate_block("medium_buffer", 50 * 1024 * 1024) # 50MB symbolic | |
| vram.allocate_block("large_tensor", 16 * 1024 * 1024 * 1024) # 16GB symbolic | |
| # Test tensor creation | |
| print("\n2. Testing tensor creation...") | |
| vram.create_tensor_block("ai_weights", (1000, 1000, 512), np.float32) | |
| vram.create_tensor_block("image_batch", (32, 224, 224, 3), np.uint8) | |
| # Test block access | |
| print("\n3. Testing block access...") | |
| block = vram.get_block("small_buffer") | |
| if block: | |
| print(f"Accessed block: {block.name}, size: {block.size_bytes:,} bytes") | |
| # Test info display | |
| print("\n4. Testing info display...") | |
| vram.print_info() | |
| # Test workload simulation | |
| print("\n5. Testing workload simulation...") | |
| vram.simulate_workload(20) | |
| # Final info | |
| print("\n6. Final state...") | |
| vram.print_info() | |
| print("\nVirtualRAM test completed!") | |