| import numpy as np |
|
|
| class MemoryManager: |
| def __init__(self, hal): |
| self.hal = hal |
| self.allocated_blocks = {} |
| self.memory_pools = {} |
| self.stream_buffers = {} |
| self.virtual_to_physical_map = {} |
| self.next_virtual_address = 0 |
| self.tensor_cache = {} |
| |
| def create_memory_pool(self, pool_id, size_bytes): |
| """Create a new VGPU memory pool for tensor operations""" |
| if pool_id in self.memory_pools: |
| raise ValueError(f"Memory pool {pool_id} already exists") |
| self.memory_pools[pool_id] = { |
| 'size': size_bytes, |
| 'used': 0, |
| 'blocks': [] |
| } |
| |
| def _get_next_physical_address(self, size_bytes, pool_id=None): |
| """Allocate from specific memory pool if pool_id provided""" |
| if pool_id is not None: |
| pool = self.memory_pools.get(pool_id) |
| if pool and pool['used'] + size_bytes <= pool['size']: |
| addr = sum(b['size'] for b in pool['blocks']) |
| pool['used'] += size_bytes |
| pool['blocks'].append({'addr': addr, 'size': size_bytes}) |
| return addr |
| raise MemoryError(f"Not enough memory in pool {pool_id}") |
| |
| |
| addr = sum(block['size'] for block in self.allocated_blocks.values()) |
| return addr |
|
|
| def allocate(self, size_bytes, chip_id=0, pool_id=None, stream_id=None): |
| if not self.hal.initialized: |
| raise RuntimeError("HAL not initialized. Cannot allocate memory.") |
|
|
| physical_address = self._get_next_physical_address(size_bytes, pool_id) |
| |
| |
| if stream_id is not None: |
| if stream_id not in self.stream_buffers: |
| self.stream_buffers[stream_id] = [] |
| self.stream_buffers[stream_id].append(physical_address) |
| |
| def allocate_tensor(self, shape, dtype, pool_id=None, stream_id=None): |
| """Allocate memory for tensor operations""" |
| size_bytes = np.prod(shape) * np.dtype(dtype).itemsize |
| addr = self.allocate(size_bytes, pool_id=pool_id, stream_id=stream_id) |
| |
| tensor_info = { |
| 'shape': shape, |
| 'dtype': dtype, |
| 'address': addr, |
| 'pool_id': pool_id, |
| 'stream_id': stream_id |
| } |
| |
| self.tensor_cache[addr] = tensor_info |
| return addr |
| |
| def get_tensor_info(self, address): |
| """Get tensor metadata for VGPU operations""" |
| return self.tensor_cache.get(address) |
| virtual_address = self.next_virtual_address |
| self.next_virtual_address += size_bytes |
|
|
| self.allocated_blocks[virtual_address] = { |
| 'physical_address': physical_address, |
| 'size': size_bytes, |
| 'chip_id': chip_id, |
| 'data': [0] * size_bytes |
| } |
| self.virtual_to_physical_map[virtual_address] = physical_address |
|
|
| print(f"Allocated {size_bytes} bytes: Virtual Address {virtual_address} -> Physical Address {physical_address} on Chip {chip_id}.") |
| return virtual_address |
|
|
| def free(self, virtual_address): |
| if virtual_address in self.allocated_blocks: |
| block_info = self.allocated_blocks[virtual_address] |
| size = block_info['size'] |
| chip_id = block_info['chip_id'] |
| physical_address = block_info['physical_address'] |
|
|
| del self.allocated_blocks[virtual_address] |
| del self.virtual_to_physical_map[virtual_address] |
| |
| print(f"Freed {size} bytes: Virtual Address {virtual_address} (Physical {physical_address}) on Chip {chip_id}.") |
| else: |
| print(f"Warning: Attempted to free unallocated memory at virtual address {virtual_address}.") |
|
|
| def write_data(self, virtual_address, data, chip_id=0): |
| if virtual_address not in self.allocated_blocks or self.allocated_blocks[virtual_address]['chip_id'] != chip_id: |
| raise ValueError(f"Memory at virtual address {virtual_address} on Chip {chip_id} not allocated or invalid.") |
| block_info = self.allocated_blocks[virtual_address] |
| physical_address = block_info['physical_address'] |
| allocated_size = block_info['size'] |
| if len(data) > allocated_size: |
| raise ValueError(f"Data size ({len(data)}) exceeds allocated size ({allocated_size}) at virtual address {virtual_address}.") |
| |
| try: |
| v2_core = self.hal.get_v2_core(chip_id) |
| for i, byte_val in enumerate(data): |
| v2_core.mmu.write(physical_address + i, [byte_val], v2_core.clk) |
| print(f"[v2] Wrote {len(data)} bytes to v2 MMU at physical {physical_address} on Chip {chip_id}.") |
| except Exception: |
| |
| for i, byte_val in enumerate(data): |
| self.hal.write_global_memory(chip_id, physical_address + i, byte_val) |
| print(f"Wrote {len(data)} bytes to virtual address {virtual_address} (physical {physical_address}) on Chip {chip_id}.") |
| block_info['data'][:len(data)] = data |
|
|
| def read_data(self, virtual_address, size_bytes, chip_id=0): |
| if virtual_address not in self.allocated_blocks or self.allocated_blocks[virtual_address]['chip_id'] != chip_id: |
| raise ValueError(f"Memory at virtual address {virtual_address} on Chip {chip_id} not allocated or invalid.") |
| block_info = self.allocated_blocks[virtual_address] |
| physical_address = block_info['physical_address'] |
| allocated_size = block_info['size'] |
| if size_bytes > allocated_size: |
| raise ValueError(f"Read size ({size_bytes}) exceeds allocated size ({allocated_size}) at virtual address {virtual_address}.") |
| |
| read_data = [] |
| try: |
| v2_core = self.hal.get_v2_core(chip_id) |
| for i in range(size_bytes): |
| val = v2_core.mmu.read(physical_address + i) |
| read_data.append(val[0]) |
| print(f"[v2] Read {size_bytes} bytes from v2 MMU at physical {physical_address} on Chip {chip_id}.") |
| except Exception: |
| for i in range(size_bytes): |
| read_data.append(self.hal.read_global_memory(chip_id, physical_address + i)) |
| print(f"Read {size_bytes} bytes from virtual address {virtual_address} (physical {physical_address}) on Chip {chip_id}.") |
| block_info['data'][:size_bytes] = read_data |
| return read_data |
|
|
|
|
| def get_physical_address(self, virtual_address): |
| if virtual_address not in self.virtual_to_physical_map: |
| raise ValueError(f"Virtual address {virtual_address} not mapped.") |
| return self.virtual_to_physical_map[virtual_address] |
|
|
|
|
|
|