| # Adapted from https://github.com/vllm-project/vllm/blob/bf214ca22625e311a2c4c0dfbf7af19128f4919c/vllm/distributed/device_communicators/symm_mem.py | |
| import logging | |
| from typing import Optional, Union | |
| import torch | |
| import torch.distributed as dist | |
| from torch.distributed import ProcessGroup | |
| from sglang.srt.distributed.device_communicators.all_reduce_utils import ( | |
| SYMM_MEM_ALL_REDUCE_MAX_SIZES, | |
| ) | |
| from sglang.srt.utils import is_cuda, is_hip | |
| try: | |
| import torch.distributed._symmetric_memory as torch_symm_mem | |
| symm_mem_available = True | |
| except ImportError: | |
| symm_mem_available = False | |
| logger = logging.getLogger(__name__) | |
| _is_cuda = is_cuda() | |
| _is_hip = is_hip() | |
| symm_mem_is_available = False | |
| if _is_hip: | |
| symm_mem_is_available = False | |
| if _is_cuda: | |
| symm_mem_is_available = True | |
| class SymmMemCommunicator: | |
| """ | |
| Thin wrapper around symmetric-memory collectives. | |
| This communicator: | |
| - Validates device capability and world size. | |
| - Allocates a shared symmetric buffer. | |
| - Chooses between 'multimem' and 'two-shot' all-reduce kernels. | |
| - Exposes a fast-path all_reduce() compatible with bfloat16 inputs. | |
| If any prerequisite is not met, the instance remains disabled and will | |
| decline to perform symmetric-memory all-reduce. | |
| """ | |
| # Mapping: compute capability major -> supported world sizes for multimem | |
| # If the current (cc_major, world_size) is not listed, we fall back | |
| # to the two-shot path. | |
| _WORLD_SIZES_MULTIMEM = { | |
| 9: [4, 6, 8], | |
| 10: [6, 8], | |
| } | |
| def __init__(self, group: ProcessGroup, device: Union[int, str, torch.device]): | |
| """ | |
| Args: | |
| group: Torch process group used for rendezvous and naming. | |
| device: Target CUDA device (index, 'cuda:X', or torch.device). | |
| """ | |
| self.disabled = True | |
| if not symm_mem_available: | |
| return | |
| if isinstance(device, int): | |
| device = torch.device(f"cuda:{device}") | |
| elif isinstance(device, str): | |
| device = torch.device(device) | |
| torch.cuda.set_device(device) | |
| self.dtype = torch.bfloat16 | |
| self.device = device | |
| self.group = group | |
| self.world_size = dist.get_world_size(self.group) | |
| self.device_capability = torch.cuda.get_device_capability(device)[0] | |
| if self.device_capability < 9: | |
| logger.warning( | |
| "SymmMemCommunicator: Device capability %s not supported, " | |
| "communicator is not available.", | |
| self.device_capability, | |
| ) | |
| return | |
| if self.world_size not in SYMM_MEM_ALL_REDUCE_MAX_SIZES[self.device_capability]: | |
| logger.warning( | |
| "SymmMemCommunicator: World size %d not supported, " | |
| "communicator is not available.", | |
| self.world_size, | |
| ) | |
| return | |
| self.max_size = SYMM_MEM_ALL_REDUCE_MAX_SIZES[self.device_capability][ | |
| self.world_size | |
| ] | |
| self.buffer = torch_symm_mem.empty( | |
| self.max_size // self.dtype.itemsize, | |
| device=self.device, | |
| dtype=self.dtype, | |
| ) | |
| handle = torch_symm_mem.rendezvous(self.buffer, self.group.group_name) | |
| if handle.multicast_ptr == 0: | |
| logger.warning( | |
| "SymmMemCommunicator: symmetric memory " | |
| "multicast operations are not supported." | |
| ) | |
| self.buffer = None | |
| self.disabled = True | |
| return | |
| self.disabled = False | |
| def should_symm_mem_allreduce(self, inp: torch.Tensor): | |
| """ | |
| Fast-path eligibility check for a given tensor. | |
| Conditions: | |
| - Communicator must be enabled. | |
| - dtype must be bfloat16 (matches kernel + buffer dtype). | |
| - Total byte size must be 4-byte aligned (hardware requirement). | |
| - Payload must be smaller than the symmetric-memory max size. | |
| Returns: | |
| True if the symmetric-memory path can handle this tensor. | |
| """ | |
| if self.disabled: | |
| return False | |
| if inp.dtype != self.dtype: | |
| return False | |
| inp_size = inp.numel() * inp.element_size() | |
| # enforce 4-byte alignment | |
| if inp_size % 4 != 0: | |
| return False | |
| return inp_size < self.max_size | |
| def all_reduce( | |
| self, inp: torch.Tensor, *, out: Optional[torch.Tensor] = None | |
| ) -> Optional[torch.Tensor]: | |
| """ | |
| Perform an in-place sum all-reduce via symmetric memory. | |
| Args: | |
| inp: Input tensor on the target CUDA device (bfloat16). | |
| out: Optional output tensor; if omitted, a new tensor is allocated. | |
| Returns: | |
| The reduced tensor (same shape as inp), or None if disabled. | |
| Implementation details: | |
| - Stages 'inp' into the symmetric buffer. | |
| - Selects 'multimem' or 'two_shot' kernel based on topology. | |
| - Writes the result into 'out' and returns it. | |
| """ | |
| if out is None: | |
| out = torch.empty_like(inp) | |
| self.buffer[: inp.numel()].copy_(inp.view(-1)) | |
| if self.world_size in self._WORLD_SIZES_MULTIMEM[self.device_capability]: | |
| torch.ops.symm_mem.multimem_all_reduce_( | |
| self.buffer[: inp.numel()], "sum", self.group.group_name | |
| ) | |
| else: | |
| torch.ops.symm_mem.two_shot_all_reduce_( | |
| self.buffer[: inp.numel()], "sum", self.group.group_name | |
| ) | |
| out.copy_(self.buffer[: inp.numel()].view(out.shape)) | |
| return out | |
Xet Storage Details
- Size:
- 5.64 kB
- Xet hash:
- 08c80e98e6f6a2799ef839954667417861b21a9214e4a5fd74ba90827a15fe63
·
Xet efficiently stores files, intelligently splitting them into unique chunks and accelerating uploads and downloads. More info.