from __future__ import annotations import logging from collections import defaultdict import torch from sglang.srt.mem_cache.mmap_allocator import alloc_mmap logger = logging.getLogger(__name__) class HostTensorAllocator: def __init__(self): """Initialize the HostTensorAllocator.""" self.dtype = None self.dims = None def allocate(self, dims: tuple, dtype: torch.dtype, device: str) -> torch.Tensor: assert ( device == "cpu" ), f"HostTensorAllocator only supports CPU allocations; got device={device!r}" self.dtype = dtype self.dims = dims return alloc_mmap(dims, dtype) def get_allocator_from_storage(allocator_type): if allocator_type == "mooncake": try: from sglang.srt.mem_cache.storage.mooncake_store.mooncake_store import ( MooncakeHostTensorAllocator, ) return MooncakeHostTensorAllocator() except ImportError: logger.warning( "Mooncake's tensor allocator requires mooncake >= 0.3.8.post1. " "Please upgrade Mooncake by 'pip install mooncake-transfer-engine --upgrade'. " "Fallback to use default allocator." ) return HostTensorAllocator() elif allocator_type == "mori": try: from sglang.srt.mem_cache.storage.umbp.umbp_host_allocator import ( UMBPHostTensorAllocator, ) return UMBPHostTensorAllocator() except (ImportError, RuntimeError) as exc: logger.warning( "UMBPHostTensorAllocator unavailable (%s). " "Falling back to torch.empty-based allocator.", exc, ) return HostTensorAllocator() else: return HostTensorAllocator() def _cuda_host_register(buffer: torch.Tensor) -> None: cudart = torch.cuda.cudart() n_bytes = buffer.numel() * buffer.element_size() rc = cudart.cudaHostRegister(buffer.data_ptr(), n_bytes, 0) if int(rc) != 0: raise RuntimeError( f"cudaHostRegister failed (rc={int(rc)}, " f"{cudart.cudaGetErrorString(rc)}) for ptr={buffer.data_ptr():#x} " f"size={n_bytes}; host buffer is not pinned and device transfers " f"may silently return stale data." ) def _cuda_host_unregister(buffer: torch.Tensor) -> None: cudart = torch.cuda.cudart() rc = cudart.cudaHostUnregister(buffer.data_ptr()) if int(rc) != 0: # Best-effort on shutdown: warn, don't raise -- a leak is reclaimed at exit. logger.warning( "cudaHostUnregister failed (rc=%d, %s) for ptr=%#x", int(rc), cudart.cudaGetErrorString(rc), buffer.data_ptr(), ) def alloc_with_host_register( dims: tuple, dtype: torch.dtype, device: str, pin_memory: bool, allocator: HostTensorAllocator, ) -> torch.Tensor: """ Allocate tensor and register host memory with cudaHostRegister. CudaHostRegister only applies when pin_memory=True. """ buffer = allocator.allocate(dims, dtype=dtype, device=device) if pin_memory: _cuda_host_register(buffer) return buffer def alloc_with_pin_memory( dims: tuple, dtype: torch.dtype, device: str, pin_memory: bool, allocator: None, ) -> torch.Tensor: """ Allocate tensor using PyTorch's built-in pin_memory flag. """ buffer = torch.empty(dims, dtype=dtype, device=device, pin_memory=pin_memory) return buffer ALLOC_MEMORY_FUNCS = defaultdict( lambda: alloc_with_host_register, { "npu": alloc_with_pin_memory, "musa": alloc_with_pin_memory, }, )