Files
wehub-resource-sync 94057c3d3e
PR Test (NPU) / check-changes (push) Has been cancelled
PR Test (NPU) / pr-gate (push) Has been cancelled
PR Test (NPU) / set-image-config (push) Has been cancelled
PR Test (NPU) / stage-b-test-1-npu-a2 (0) (push) Has been cancelled
PR Test (NPU) / stage-b-test-1-npu-a2 (1) (push) Has been cancelled
PR Test (NPU) / stage-b-test-2-npu-a2 (0) (push) Has been cancelled
PR Test (NPU) / stage-b-test-2-npu-a2 (1) (push) Has been cancelled
PR Test (NPU) / stage-b-test-4-npu-a3 (push) Has been cancelled
PR Test (NPU) / stage-b-test-16-npu-a3 (push) Has been cancelled
PR Test (NPU) / multimodal-gen-test-1-npu-a3 (push) Has been cancelled
PR Test (NPU) / multimodal-gen-test-2-npu-a3 (push) Has been cancelled
PR Test (Arm64) / pr-gate (push) Has been cancelled
PR Test (Arm64) / check-changes (push) Has been cancelled
PR Test (Arm64) / build-test (push) Has been cancelled
PR Test (sgl-router) / gate (push) Has been cancelled
PR Test (sgl-router) / tier-1 — lint (push) Has been cancelled
PR Test (sgl-router) / tier-2 — build + test (push) Has been cancelled
PR Test (sgl-router) / tier-3 — docker (placeholder) (push) Has been cancelled
PR Test (sgl-router) / tier-3 — k8s integration (push) Has been cancelled
PR Test (sgl-router) / tier-3 — e2e (push) Has been cancelled
PR Test (sgl-router) / finish (push) Has been cancelled
PR Test (NPU) / single-node-poc (map[name:qwen3_6_27b_w8a8_1p_in64k_out1k_50ms runner:linux-aarch64-a3-2 test_case:test/registered/ascend/performance/qwen3_6_27b/test_npu_qwen3_6_27b_w8a8_1p_in64k_out1k_50ms.py test_type:perf]) (push) Has been cancelled
PR Test (NPU) / pr-test-npu-finish (push) Has been cancelled
PR Test (Xeon) / pr-gate (push) Has been cancelled
PR Test (Xeon) / check-changes (push) Has been cancelled
PR Test (Xeon) / build-test (, xeon-gnr, base-b-test-cpu) (push) Has been cancelled
PR Test (XPU) / check-changes (push) Has been cancelled
PR Test (XPU) / pr-gate (push) Has been cancelled
PR Test (XPU) / stage-a-test-1-gpu-xpu (push) Has been cancelled
PR Test (XPU) / wait-for-stage-a (push) Has been cancelled
PR Test (XPU) / stage-b-test-1-gpu-xpu (push) Has been cancelled
PR Test (XPU) / finish (push) Has been cancelled
CI Model Inventory / build-inventory (push) Has been cancelled
Lint / lint (push) Has been cancelled
PR Benchmark (SMG Components) / Benchmark Compilation Check (push) Has been cancelled
PR Benchmark (SMG Components) / Benchmark - Manual Policy (push) Has been cancelled
PR Benchmark (SMG Components) / Benchmark - Request Processing (push) Has been cancelled
PR Benchmark (SMG Components) / Benchmark Summary (push) Has been cancelled
PR Test (SMG) / build-wheel (push) Has been cancelled
Release SGLang Model Gateway to PyPI / build on windows (x86_64 - auto) (push) Has been cancelled
Release SGLang Model Gateway to PyPI / build on macos (x86_64 - auto) (push) Has been cancelled
PR Test (SMG) / python-unit-tests (push) Has been cancelled
PR Test (SMG) / unit-tests (push) Has been cancelled
PR Test (SMG) / benchmarks (push) Has been cancelled
PR Test (SMG) / chat-completions (push) Has been cancelled
PR Test (SMG) / chat-completions-4gpu (push) Has been cancelled
PR Test (SMG) / e2e (push) Has been cancelled
PR Test (SMG) / docker-build-test (push) Has been cancelled
PR Test (SMG) / k8s-integration (push) Has been cancelled
PR Test (SMG) / finish (push) Has been cancelled
PR Test (SMG) / summarize-benchmarks (push) Has been cancelled
Release SGLang Model Gateway Docker Image / publish (push) Has been cancelled
Release SGLang Model Gateway to PyPI / build on macos (aarch64 - auto) (push) Has been cancelled
Release SGLang Model Gateway to PyPI / build on linux (aarch64 - auto) (push) Has been cancelled
Release SGLang Model Gateway to PyPI / build on linux (x86_64 - auto) (push) Has been cancelled
Release SGLang Model Gateway to PyPI / build on linux (aarch64 - musllinux_1_1) (push) Has been cancelled
Release SGLang Model Gateway to PyPI / build on linux (x86_64 - musllinux_1_1) (push) Has been cancelled
Release SGLang Model Gateway to PyPI / Build SDist (push) Has been cancelled
Release SGLang Model Gateway to PyPI / Upload to PyPI (push) Has been cancelled
Release SGLang Kernels / build-cu129-matrix (aarch64, 12.9, 3.10, arm-kernel-build-node) (push) Has been cancelled
Release SGLang Kernels / build-cu129-matrix (x86_64, 12.9, 3.10, x64-kernel-build-node) (push) Has been cancelled
Release SGLang Kernels / release-cu129 (push) Has been cancelled
Release SGLang Kernels / build-cu130-matrix (aarch64, 13.0, 3.10, arm-kernel-build-node) (push) Has been cancelled
Release SGLang Kernels / build-cu130-matrix (x86_64, 13.0, 3.10, x64-kernel-build-node) (push) Has been cancelled
Release SGLang Kernels / release-cu130 (push) Has been cancelled
Release SGLang Kernels / build-rocm-matrix (3.10, 700) (push) Has been cancelled
Release SGLang Kernels / build-rocm-matrix (3.10, 720) (push) Has been cancelled
Release SGLang Kernels / release-rocm700 (push) Has been cancelled
Release SGLang Kernels / release-rocm720 (push) Has been cancelled
Release SGLang Kernels / build-musa43 (43, 3.10) (push) Has been cancelled
Release SGLang Kernels / release-musa43 (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 12:38:16 +08:00

655 lines
24 KiB
Python

import logging
import os
import struct
import time
from typing import Any, List, Optional
import torch
import torch.distributed as dist
from torch.distributed import ProcessGroup
from sglang.srt.utils import log_info_on_rank0
logger = logging.getLogger(__name__)
_drv = None
_FD_HEADER_BYTES = 24
_FD_SEND_TIMEOUT_S = 120.0
def _get_cuda_driver():
"""Lazily import cuda.bindings.driver (cached after first call)."""
global _drv
if _drv is None:
from cuda.bindings import driver
_drv = driver
return _drv
def check_drv(result_tuple, label):
"""Check a cuda.bindings driver call result and return the value."""
if not isinstance(result_tuple, tuple):
result_tuple = (result_tuple,)
err = result_tuple[0]
drv = _get_cuda_driver()
if err != drv.CUresult.CUDA_SUCCESS:
raise RuntimeError(f"{label}: {err}")
return result_tuple[1] if len(result_tuple) > 1 else None
def is_vmm_pointer(ptr: int) -> bool:
"""Check if a device pointer is VMM-backed (cuMemCreate/cuMemMap).
cuMemRetainAllocationHandle succeeds only on pointers from cuMemCreate;
it fails on cudaMalloc pointers.
"""
drv = _get_cuda_driver()
err, handle = drv.cuMemRetainAllocationHandle(ptr)
if err == drv.CUresult.CUDA_SUCCESS:
drv.cuMemRelease(handle)
return True
return False
def make_rw_access_desc(device_id: int):
"""A read-write, device-local ``CUmemAccessDesc`` for ``device_id``."""
drv = _get_cuda_driver()
desc = drv.CUmemAccessDesc()
desc.location.type = drv.CUmemLocationType.CU_MEM_LOCATION_TYPE_DEVICE
desc.location.id = device_id
desc.flags = drv.CUmemAccess_flags.CU_MEM_ACCESS_FLAGS_PROT_READWRITE
return desc
def all_ranks_ok(group: ProcessGroup, ok: bool) -> bool:
"""True iff ``ok`` holds on every rank in ``group`` (BAND all-reduce)."""
flag = torch.tensor([1 if ok else 0], dtype=torch.int32)
dist.all_reduce(flag, op=dist.ReduceOp.BAND, group=group)
return flag.item() == 1
def release_mappings(mappings) -> None:
"""Unmap + address-free each ``(va, span_size, [(rel, size), ...])`` mapping.
Pops from ``mappings`` so a partially-released list is safe to retry.
"""
drv = _get_cuda_driver()
while mappings:
va, span_size, mapped_chunks = mappings.pop()
for rel, size in mapped_chunks:
check_drv(drv.cuMemUnmap(int(va) + int(rel), int(size)), "cuMemUnmap")
check_drv(drv.cuMemAddressFree(int(va), int(span_size)), "cuMemAddressFree")
def _send_fd(sock, fd: int, src_rank: int, base_idx: int) -> None:
import array
import socket
fds = array.array("i", [int(fd)])
header = struct.pack("<QQQ", int(src_rank), int(base_idx), 1)
sent = sock.sendmsg(
[header],
[(socket.SOL_SOCKET, socket.SCM_RIGHTS, fds.tobytes())],
)
if sent != len(header):
raise RuntimeError(f"sendmsg sent {sent} bytes, expected {len(header)}")
def _recv_fd(sock):
import array
import socket
fd_item_size = array.array("i").itemsize
data, ancdata, _, _ = sock.recvmsg(
_FD_HEADER_BYTES, socket.CMSG_SPACE(fd_item_size)
)
if not data:
return None
if len(data) != _FD_HEADER_BYTES:
raise RuntimeError(
f"received truncated fd header: {len(data)} < {_FD_HEADER_BYTES}"
)
src_rank, base_idx, fd_count = struct.unpack("<QQQ", data)
fds = array.array("i")
for level, cmsg_type, cmsg_data in ancdata:
if level == socket.SOL_SOCKET and cmsg_type == socket.SCM_RIGHTS:
fds.frombytes(cmsg_data[: len(cmsg_data) - (len(cmsg_data) % fd_item_size)])
if fd_count != 1 or len(fds) != 1:
for fd in fds:
os.close(fd)
raise RuntimeError(
f"expected one fd, got header={fd_count}, ancillary={len(fds)}"
)
return int(src_rank), int(base_idx), int(fds[0])
def export_shareable_handles(retained_handles, group: ProcessGroup, rank: int):
"""Export retained VMM handles, preferring FABRIC and falling back to POSIX fds.
FABRIC is used only if every rank can export it; otherwise all ranks use POSIX
fds. Returns ``(fabric_handles, posix_fds, use_fabric)`` (one list populated);
raises if both fail on any rank. Caller owns the returned ``posix_fds``.
"""
drv = _get_cuda_driver()
FABRIC = drv.CUmemAllocationHandleType.CU_MEM_HANDLE_TYPE_FABRIC
POSIX_FD = drv.CUmemAllocationHandleType.CU_MEM_HANDLE_TYPE_POSIX_FILE_DESCRIPTOR
fabric_handles: List[bytes] = []
fabric_error: Optional[Exception] = None
try:
for alloc_h in retained_handles:
fabric_h = check_drv(
drv.cuMemExportToShareableHandle(alloc_h, FABRIC, 0),
"cuMemExportToShareableHandle(FABRIC)",
)
fabric_handles.append(bytes(fabric_h.data))
fabric_ok = True
except Exception as e:
fabric_error = e
fabric_ok = False
fabric_handles = []
logger.info(
"FABRIC handle export failed on rank %s; falling back to "
"POSIX fd transport: %s",
rank,
e,
)
if all_ranks_ok(group, fabric_ok):
return fabric_handles, [], True
posix_fds: List[int] = []
posix_error: Optional[Exception] = None
try:
for alloc_h in retained_handles:
fd = check_drv(
drv.cuMemExportToShareableHandle(alloc_h, POSIX_FD, 0),
"cuMemExportToShareableHandle(POSIX_FD)",
)
posix_fds.append(int(fd))
posix_ok = True
except Exception as e:
posix_error = e
posix_ok = False
for fd in posix_fds:
try:
os.close(fd)
except OSError:
pass
posix_fds = []
if not all_ranks_ok(group, posix_ok):
cause = posix_error or fabric_error
message = (
"VMM handle export failed: FABRIC export failed on at least one "
"rank and POSIX fd export failed on at least one rank"
)
if cause is not None:
message += f"; local rank {rank} error: {cause}"
raise RuntimeError(message) from posix_error
return [], posix_fds, False
def exchange_posix_fds(
group: ProcessGroup,
rank: int,
world_size: int,
local_fds: List[int],
peer_base_counts: List[int],
):
"""Exchange POSIX file descriptors across ranks via SCM_RIGHTS over a UNIX
socket. Returns ``{(src_rank, base_idx): fd}`` for every peer. The caller
owns the received fds and must close them.
"""
import socket
import tempfile
import threading
sock_kind = getattr(socket, "SOCK_SEQPACKET", socket.SOCK_STREAM)
sock_dir = tempfile.mkdtemp(prefix="sgl_ar_fd_")
sock_path = os.path.join(sock_dir, f"rank_{rank}.sock")
server = socket.socket(socket.AF_UNIX, sock_kind)
server.settimeout(_FD_SEND_TIMEOUT_S)
received_fds = {}
errors = []
def recv_loop():
try:
for _ in range(world_size - 1):
conn, _ = server.accept()
with conn:
conn.settimeout(_FD_SEND_TIMEOUT_S)
while True:
packet = _recv_fd(conn)
if packet is None:
break
src_rank, base_idx, fd = packet
key = (src_rank, base_idx)
if key in received_fds:
os.close(fd)
raise RuntimeError(f"duplicate fd for {key}")
received_fds[key] = fd
except BaseException as e:
errors.append(e)
try:
server.bind(sock_path)
server.listen(world_size)
paths = [None] * world_size
dist.all_gather_object(paths, sock_path, group=group)
thread = threading.Thread(target=recv_loop, daemon=True)
thread.start()
try:
for peer_rank, peer_path in enumerate(paths):
if peer_rank == rank:
continue
with socket.socket(socket.AF_UNIX, sock_kind) as sock:
sock.settimeout(_FD_SEND_TIMEOUT_S)
sock.connect(peer_path)
for base_idx, fd in enumerate(local_fds):
_send_fd(sock, fd, rank, base_idx)
finally:
thread.join(_FD_SEND_TIMEOUT_S)
if thread.is_alive():
raise RuntimeError("timed out waiting for POSIX fd exchange")
if errors:
raise RuntimeError("POSIX fd exchange receive failed") from errors[0]
expected = {
(src_rank, base_idx)
for src_rank, count in enumerate(peer_base_counts)
if src_rank != rank
for base_idx in range(count)
}
missing = expected.difference(received_fds)
extra = set(received_fds).difference(expected)
if missing or extra:
for fd in received_fds.values():
os.close(fd)
raise RuntimeError(
"POSIX fd exchange mismatch: "
f"missing={sorted(missing)[:8]}, extra={sorted(extra)[:8]}"
)
return received_fds
finally:
server.close()
try:
os.unlink(sock_path)
except FileNotFoundError:
pass
try:
os.rmdir(sock_dir)
except OSError:
pass
def import_peer_handle(fabric_handle, fd, *, use_fabric: bool, peer_rank: int):
"""Import a peer allocation handle (FABRIC or POSIX fd). Returns the handle.
For POSIX the fd is duped before import so the caller keeps ownership of the
original.
"""
drv = _get_cuda_driver()
if use_fabric:
FABRIC = drv.CUmemAllocationHandleType.CU_MEM_HANDLE_TYPE_FABRIC
return check_drv(
drv.cuMemImportFromShareableHandle(fabric_handle, FABRIC),
f"cuMemImportFromShareableHandle(rank={peer_rank})",
)
POSIX_FD = drv.CUmemAllocationHandleType.CU_MEM_HANDLE_TYPE_POSIX_FILE_DESCRIPTOR
dup_fd = os.dup(fd)
try:
return check_drv(
drv.cuMemImportFromShareableHandle(dup_fd, POSIX_FD),
f"cuMemImportFromShareableHandle(rank={peer_rank}, POSIX_FD)",
)
finally:
try:
os.close(dup_fd)
except OSError:
pass
def import_and_map_alloc(
fabric_handle,
fd,
alloc_size: int,
device_id: int,
*,
use_fabric: bool,
peer_rank: int,
) -> int:
"""Import a peer allocation, map it at a freshly reserved VA, return the VA."""
drv = _get_cuda_driver()
imp_h = import_peer_handle(
fabric_handle, fd, use_fabric=use_fabric, peer_rank=peer_rank
)
prop = check_drv(
drv.cuMemGetAllocationPropertiesFromHandle(imp_h),
"cuMemGetAllocationPropertiesFromHandle",
)
gran = check_drv(
drv.cuMemGetAllocationGranularity(
prop,
drv.CUmemAllocationGranularity_flags.CU_MEM_ALLOC_GRANULARITY_RECOMMENDED,
),
"cuMemGetAllocationGranularity",
)
va = check_drv(
drv.cuMemAddressReserve(alloc_size, int(gran), 0, 0), "cuMemAddressReserve"
)
check_drv(drv.cuMemMap(int(va), alloc_size, 0, imp_h, 0), "cuMemMap")
access = make_rw_access_desc(device_id)
check_drv(drv.cuMemSetAccess(int(va), alloc_size, [access], 1), "cuMemSetAccess")
check_drv(drv.cuMemRelease(imp_h), "cuMemRelease(peer)")
return int(va)
def map_chunk_into_span(
fabric_handle,
fd,
span_va: int,
rel: int,
alloc_size: int,
device_id: int,
*,
use_fabric: bool,
peer_rank: int,
) -> None:
"""Import + map a peer chunk into a caller-reserved span at ``span_va + rel``."""
drv = _get_cuda_driver()
imp_h = import_peer_handle(
fabric_handle, fd, use_fabric=use_fabric, peer_rank=peer_rank
)
check_drv(
drv.cuMemMap(int(span_va) + rel, int(alloc_size), 0, imp_h, 0),
"cuMemMap(span)",
)
access = make_rw_access_desc(device_id)
check_drv(
drv.cuMemSetAccess(int(span_va) + rel, int(alloc_size), [access], 1),
"cuMemSetAccess(span)",
)
check_drv(drv.cuMemRelease(imp_h), "cuMemRelease(span)")
class VmmGraphInputManager:
def __init__(
self,
obj: Any,
group: ProcessGroup,
rank: int,
world_size: int,
) -> None:
self.obj = obj
self.group = group
self.rank = rank
self.world_size = world_size
self._peer_mappings = []
def register_graph_inputs(self):
"""Register graph capture inputs via VMM handle exchange.
VMM-compatible path for expandable_segments. The C++ side deduplicates
graph capture pointers into unique base allocations via cuMemGetAddressRange.
Python exports handles for each unique base, imports + cuMemMaps peer
allocations, then registers the peer VAs. FABRIC handles are preferred;
POSIX file descriptors are used when FABRIC is unavailable.
"""
FABRIC_HANDLE_BYTES = 64
MAX_VMM_BASES = 4096
MAX_CHUNKS_PER_INPUT = 16
t0 = time.perf_counter()
bases_info, input_chunk_indices, input_offsets = (
self.obj.get_graph_capture_bases()
)
if not bases_info:
return
new_count = len(input_chunk_indices)
num_bases = len(bases_info)
device_id = torch.cuda.current_device()
if num_bases > MAX_VMM_BASES:
raise RuntimeError(
f"Too many VMM bases to share: {num_bases} > {MAX_VMM_BASES}"
)
drv = _get_cuda_driver()
local_posix_fds: List[int] = []
retained_handles = []
try:
for base_ptr, _ in bases_info:
alloc_h = check_drv(
drv.cuMemRetainAllocationHandle(base_ptr),
"cuMemRetainAllocationHandle",
)
retained_handles.append(alloc_h)
local_fabric_handles, local_posix_fds, use_fabric = (
export_shareable_handles(retained_handles, self.group, self.rank)
)
local_input_chunks = [
[int(idx) for idx in indices] for indices in input_chunk_indices
]
for chunks in local_input_chunks:
if len(chunks) > MAX_CHUNKS_PER_INPUT:
raise RuntimeError(
"Too many VMM chunks for graph input: "
f"{len(chunks)} > {MAX_CHUNKS_PER_INPUT}"
)
# All-gather base metadata and per-input VMM spans. A captured tensor
# can cross expandable-segment allocation boundaries, so peer mappings
# must preserve each input's contiguous virtual-address span. FABRIC
# handles are inline metadata; POSIX fds are exchanged separately via
# SCM_RIGHTS because fd integers are process-local.
header_struct = struct.Struct("<QQ")
base_struct = struct.Struct(
f"<QQ{FABRIC_HANDLE_BYTES}s" if use_fabric else "<QQ"
)
input_struct = struct.Struct(f"<QQ{MAX_CHUNKS_PER_INPUT}Q")
base_offset = header_struct.size
input_offset = base_offset + MAX_VMM_BASES * base_struct.size
payload_size = input_offset + new_count * input_struct.size
local_payload = bytearray(payload_size)
header_struct.pack_into(local_payload, 0, num_bases, new_count)
for i, (base_ptr, alloc_size) in enumerate(bases_info):
if use_fabric:
base_struct.pack_into(
local_payload,
base_offset + i * base_struct.size,
int(base_ptr),
int(alloc_size),
local_fabric_handles[i],
)
else:
base_struct.pack_into(
local_payload,
base_offset + i * base_struct.size,
int(base_ptr),
int(alloc_size),
)
for i, (chunks, offset) in enumerate(
zip(local_input_chunks, input_offsets)
):
padded_chunks = chunks + [0] * (MAX_CHUNKS_PER_INPUT - len(chunks))
input_struct.pack_into(
local_payload,
input_offset + i * input_struct.size,
int(offset),
len(chunks),
*padded_chunks,
)
in_buf = torch.frombuffer(local_payload, dtype=torch.uint8).clone()
gather_list = [torch.empty_like(in_buf) for _ in range(self.world_size)]
dist.all_gather(gather_list, in_buf, group=self.group)
all_base_payload = []
all_input_chunks = []
all_input_offsets = []
for rank, gathered in enumerate(gather_list):
payload = gathered.numpy().tobytes()
peer_num_bases, peer_new_count = header_struct.unpack_from(payload, 0)
if peer_new_count != new_count:
raise RuntimeError(
"Mismatched graph input count across ranks: "
f"rank {rank} has {peer_new_count}, expected {new_count}"
)
peer_bases = []
for i in range(peer_num_bases):
if use_fabric:
base_ptr, alloc_size, fabric_handle = base_struct.unpack_from(
payload, base_offset + i * base_struct.size
)
else:
base_ptr, alloc_size = base_struct.unpack_from(
payload, base_offset + i * base_struct.size
)
fabric_handle = None
peer_bases.append((base_ptr, fabric_handle, alloc_size))
peer_chunks = []
peer_offsets = []
for i in range(new_count):
unpacked = input_struct.unpack_from(
payload, input_offset + i * input_struct.size
)
offset, chunk_count, *chunks = unpacked
peer_offsets.append(offset)
peer_chunks.append(list(chunks[:chunk_count]))
all_base_payload.append(peer_bases)
all_input_chunks.append(peer_chunks)
all_input_offsets.append(peer_offsets)
posix_peer_fds = {}
if not use_fabric:
posix_peer_fds = exchange_posix_fds(
self.group,
self.rank,
self.world_size,
local_posix_fds,
[len(peer_bases) for peer_bases in all_base_payload],
)
# Import + map peer allocations. Individual base mappings are kept for
# single-chunk inputs; span mappings reserve a contiguous VA range and
# map each chunk at its original relative offset.
peer_base_va = {} # (rank, base_idx) -> local VA
peer_span_va = {} # (rank, chunk_indices...) -> (local VA, peer base)
new_mappings = []
try:
for peer_rank in range(self.world_size):
if peer_rank == self.rank:
for idx, (bp, _) in enumerate(bases_info):
peer_base_va[(peer_rank, idx)] = int(bp)
continue
peer_bases = all_base_payload[peer_rank]
for idx, (_, fb, alloc_size) in enumerate(peer_bases):
fd = None if use_fabric else posix_peer_fds[(peer_rank, idx)]
va = import_and_map_alloc(
fb,
fd,
alloc_size,
device_id,
use_fabric=use_fabric,
peer_rank=peer_rank,
)
peer_base_va[(peer_rank, idx)] = va
new_mappings.append((va, alloc_size, [(0, alloc_size)]))
# Build per-input peer VA lists and register.
peer_ptrs = []
for j in range(new_count):
ptrs_j = []
for rank in range(self.world_size):
chunks = all_input_chunks[rank][j]
off = all_input_offsets[rank][j]
if len(chunks) == 1:
ptrs_j.append(peer_base_va[(rank, chunks[0])] + off)
continue
span_key = (rank, *chunks)
if span_key not in peer_span_va:
peer_bases = all_base_payload[rank]
first_base = peer_bases[chunks[0]][0]
last_base, _, last_size = peer_bases[chunks[-1]]
span_size = (
int(last_base) + int(last_size) - int(first_base)
)
if rank == self.rank:
span_va = int(first_base)
else:
span_va = check_drv(
drv.cuMemAddressReserve(span_size, 0, 0, 0),
"cuMemAddressReserve(span)",
)
mapped_chunks = []
for chunk_idx in chunks:
base_ptr, fb, alloc_size = peer_bases[chunk_idx]
rel = int(base_ptr) - int(first_base)
fd = (
None
if use_fabric
else posix_peer_fds[(rank, chunk_idx)]
)
map_chunk_into_span(
fb,
fd,
span_va,
rel,
int(alloc_size),
device_id,
use_fabric=use_fabric,
peer_rank=rank,
)
mapped_chunks.append((rel, int(alloc_size)))
new_mappings.append(
(int(span_va), span_size, mapped_chunks)
)
peer_span_va[span_key] = (int(span_va), int(first_base))
span_va, _ = peer_span_va[span_key]
ptrs_j.append(span_va + off)
peer_ptrs.append(ptrs_j)
self.obj.register_peer_mapped_inputs(peer_ptrs)
self._peer_mappings.extend(new_mappings)
except Exception:
release_mappings(new_mappings)
raise
finally:
for fd in posix_peer_fds.values():
os.close(fd)
elapsed_ms = (time.perf_counter() - t0) * 1000
transport = "FABRIC" if use_fabric else "POSIX fd"
log_info_on_rank0(
logger,
f"Registered {new_count} cuda graph addresses via "
f"{transport} handles ({num_bases} unique allocations) "
f"in {elapsed_ms:.1f} ms",
)
finally:
for fd in local_posix_fds:
os.close(fd)
for h in retained_handles:
check_drv(drv.cuMemRelease(h), "cuMemRelease(retained)")
def close(self):
if not self._peer_mappings:
return
release_mappings(self._peer_mappings)