[diffusion] optimization: pin layerwise host stores in place at their exact size (#39021)

Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Mick
2026-09-11 22:04:40 +08:00
committed by GitHub
co-authored by Claude Opus 5
parent e8a36d339c
commit ab9750fb35
2 changed files with 146 additions and 10 deletions
@@ -1,6 +1,7 @@
import bisect import bisect
import ctypes import ctypes
import ctypes.util import ctypes.util
import math
import mmap import mmap
import os import os
import queue import queue
@@ -8,6 +9,7 @@ import re
import sys import sys
import threading import threading
import time import time
import weakref
from collections.abc import Iterator, Mapping, Sequence from collections.abc import Iterator, Mapping, Sequence
from contextlib import nullcontext from contextlib import nullcontext
from time import perf_counter from time import perf_counter
@@ -395,6 +397,92 @@ _DIRECT_CHUNK = 64 << 20
MAPPED_DIRECT_READ_MIN_BYTES = 8 * 1024**3 MAPPED_DIRECT_READ_MIN_BYTES = 8 * 1024**3
def _pin_in_place(tensor: torch.Tensor) -> bool:
"""Page-lock an allocated CPU tensor in place, at exactly its size.
torch's pinned pool rounds each block up to a power of two (a 1.20 GiB
layer store costs 2 GiB), which the pin budget never charged for.
"""
if not torch.cuda.is_available():
return False
storage = tensor.untyped_storage()
nbytes = storage.nbytes()
if nbytes == 0:
return False
try:
cudart = torch.cuda.cudart()
if int(cudart.cudaHostRegister(storage.data_ptr(), nbytes, 0)) != 0:
return False
except Exception:
return False
weakref.finalize(storage, _unpin_in_place, storage.data_ptr())
return True
def _unpin_in_place(data_ptr: int) -> None:
try:
torch.cuda.cudart().cudaHostUnregister(data_ptr)
except Exception:
pass
def _shared_storage(nbytes: int) -> Optional[torch.UntypedStorage]:
"""Anonymous shared memory (memfd) of exactly `nbytes`, or None off Linux.
Shared rather than private anonymous memory so the locked pages stay on
the shmem side of the process's accounting, where cudaHostAlloc kept
them: the host-anon figures (and the forced-host-view budget that
subtracts them) keep meaning "pageable copies".
"""
if not hasattr(os, "memfd_create"):
return None
try:
fd = os.memfd_create("sglang-pinned-store", 0)
except OSError:
return None
try:
os.ftruncate(fd, nbytes)
return torch.UntypedStorage.from_file(
f"/proc/self/fd/{fd}", shared=True, nbytes=nbytes
)
except Exception:
return None
finally:
os.close(fd)
# Below this, torch's own pinned pool: its power-of-two rounding costs little on
# small blocks, and two small blocks can share a page, which cudaHostRegister
# refuses to lock twice.
_REGISTER_MIN_BYTES = 64 << 20
def _pinned_empty(*size: int, dtype: torch.dtype, stride=None) -> torch.Tensor:
"""A pinned CPU tensor of exactly this size; torch's pinned pool as fallback."""
shape = size[0] if stride is not None else size
if stride is None:
storage_numel = math.prod(shape)
else:
storage_numel = 1 + sum((d - 1) * st for d, st in zip(shape, stride) if d > 0)
storage_numel = storage_numel if math.prod(shape) else 0
nbytes = storage_numel * dtype.itemsize
if nbytes >= _REGISTER_MIN_BYTES:
storage = _shared_storage(nbytes)
tensor = torch.empty(0, dtype=dtype)
if storage is not None:
tensor.set_(storage, 0, shape, stride or tensor.stride())
elif stride is None:
tensor = torch.empty(*size, dtype=dtype)
else:
tensor = torch.empty_strided(size=shape, stride=stride, dtype=dtype)
if _pin_in_place(tensor):
return tensor
del tensor, storage
if stride is None:
return torch.empty(*size, dtype=dtype, pin_memory=True)
return torch.empty_strided(size=shape, stride=stride, dtype=dtype, pin_memory=True)
class _DirectReader: class _DirectReader:
"""Read a mapped tensor's bytes from its checkpoint file with O_DIRECT. """Read a mapped tensor's bytes from its checkpoint file with O_DIRECT.
@@ -646,7 +734,11 @@ class MappedLayerCourier:
[] []
if direct_copy if direct_copy
else [ else [
torch.empty(slot_bytes, dtype=torch.uint8, pin_memory=pin_slots) (
_pinned_empty(slot_bytes, dtype=torch.uint8)
if pin_slots
else torch.empty(slot_bytes, dtype=torch.uint8)
)
for _ in range(self._NUM_SLOTS) for _ in range(self._NUM_SLOTS)
] ]
) )
@@ -1304,12 +1396,18 @@ class LayerwiseOffloadManager:
# Preserve non-contiguous layouts such as the transposed FP8 # Preserve non-contiguous layouts such as the transposed FP8
# weight views expected by CUTLASS kernels. # weight views expected by CUTLASS kernels.
cpu_tensor = torch.empty_strided( if pin_this_layer:
size=local_weight.shape, cpu_tensor = _pinned_empty(
stride=local_weight.stride(), local_weight.shape,
dtype=dtype, dtype=dtype,
pin_memory=pin_this_layer, stride=local_weight.stride(),
) )
else:
cpu_tensor = torch.empty_strided(
size=local_weight.shape,
stride=local_weight.stride(),
dtype=dtype,
)
if pin_this_layer: if pin_this_layer:
yield cpu_tensor.untyped_storage() yield cpu_tensor.untyped_storage()
cpu_tensor.copy_(local_weight) cpu_tensor.copy_(local_weight)
@@ -1341,9 +1439,10 @@ class LayerwiseOffloadManager:
total_numel = current_offset total_numel = current_offset
# create concatenated CPU buffer (in pinned memory) # create concatenated CPU buffer (in pinned memory)
cpu_buffer = torch.empty( if pin_this_layer:
total_numel, dtype=dtype, pin_memory=pin_this_layer cpu_buffer = _pinned_empty(total_numel, dtype=dtype)
) else:
cpu_buffer = torch.empty(total_numel, dtype=dtype)
if pin_this_layer: if pin_this_layer:
yield cpu_buffer.untyped_storage() yield cpu_buffer.untyped_storage()
@@ -2266,3 +2266,40 @@ def test_mixed_scm_and_dbcache_step_schedule(monkeypatch, step_kinds):
on_gpu = idx in manager._gpu_layers on_gpu = idx in manager._gpu_layers
assert _layer_weight_ok(model.blocks[idx]) is on_gpu, (kind, idx) assert _layer_weight_ok(model.blocks[idx]) is on_gpu, (kind, idx)
manager.prepare_for_next_req(non_blocking=False) manager.prepare_for_next_req(non_blocking=False)
@pytest.mark.skipif(not torch.cuda.is_available(), reason="requires CUDA")
def test_large_pinned_stores_are_registered_in_place_at_exact_size(monkeypatch):
pooled = []
empty = torch.empty
def record_pool_use(*args, **kwargs):
if kwargs.get("pin_memory"):
pooled.append(kwargs)
return empty(*args, **kwargs)
monkeypatch.setattr(torch, "empty", record_pool_use)
nbytes = layerwise_offload_mod._REGISTER_MIN_BYTES + 4096
tensor = layerwise_offload_mod._pinned_empty(nbytes, dtype=torch.uint8)
# locked where it was allocated: pinned, no pool block, no rounding
assert tensor.is_pinned()
assert tensor.untyped_storage().nbytes() == nbytes
assert pooled == []
del tensor
gc.collect()
@pytest.mark.skipif(not torch.cuda.is_available(), reason="requires CUDA")
def test_small_pinned_stores_keep_using_the_pool(monkeypatch):
pooled = []
empty = torch.empty
def record_pool_use(*args, **kwargs):
if kwargs.get("pin_memory"):
pooled.append(kwargs)
return empty(*args, **kwargs)
monkeypatch.setattr(torch, "empty", record_pool_use)
tensor = layerwise_offload_mod._pinned_empty(1024, dtype=torch.float32)
assert tensor.is_pinned()
assert len(pooled) == 1