Support multi node nvlink fabric - #23
Conversation
asp0ex
left a comment
There was a problem hiding this comment.
Two things before merge:
- Split the cutlass 4.4.2 → 4.6.0 bump (and the
make_fragment→
make_rmem_tensorrename) into a separate PR — we need to stay on 4.4.2
for compatibility with other kernels (inline onsetup.py/
grad_reduce.py). benchmarks/bench_vs_deepep.pyneeds to follow thefds→shareables
rename; it callsnvl_dist_mapdirectly and now raisesTypeError
(inline onbindings.cu).
Rest of the fabric change LGTM.
|
Thanks @asp0ex. nvidia-cutlass-dsl version change is removed. I upgraded it as my environment and sglang use 4.6.0. bench_vs_deepep.py is also updated. |
| const at::Tensor &handles, int64_t index, bool use_fabric | ||
| ) { | ||
| CUmemGenericAllocationHandle handle; | ||
| if (use_fabric) { |
There was a problem hiding this comment.
Maybe we can add more sanity check for handles like
# global_check
TORCH_CHECK(handles.device().is_cpu(), "handles must be a CPU tensor");
TORCH_CHECK(handles.is_contiguous(), "handles must be contiguous");
# if use_fabric
TORCH_CHECK(handles.dim() == 2, "handles must be 2D [-1, 64] when using fabric");
TORCH_CHECK(handles.dtype() == at::kByte, "handles must be uint8 in fabric");
TORCH_CHECK(handles.size(1) == (int64_t)sizeof(CUmemFabricHandle),
"handles.size(1) in fabric must be ", sizeof(CUmemFabricHandle));
# else
TORCH_CHECK(handles.dim() == 1, "handles must be 1D when not using fabric");
TORCH_CHECK(handles.dtype() == at::kLong, "handles must be long in local fd");| int64_t world_size, | ||
| bool use_fabric | ||
| ) { | ||
| TORCH_CHECK((int64_t)shareables.size() == world_size, |
There was a problem hiding this comment.
This can keep as
TORCH_CHECK((int64_t)shareables.size(0) == world_size,
"shareables.size()=", shareables.size(0), " != world_size=", world_size);| at::ScalarType dtype, | ||
| const std::vector<int64_t> &fds, | ||
| const at::Tensor &shareables, | ||
| int64_t local_rank, |
There was a problem hiding this comment.
It seems this local_rank is not used.
Also, other local_rank maybe change to rank since this is a global rank in both fabric and fd
|
|
||
|
|
||
| def _use_fabric_for_group( | ||
| world_size: int, |
There was a problem hiding this comment.
Is world_size necessary here? Maybe we can just use dist.get_world_size(group=group) for getting world_size.
|
|
||
| def _all_gather_shareables( | ||
| local_handle: torch.Tensor, | ||
| world_size: int, |
| _HANDLE_TYPE_ENV = "MOONEP_MEM_HANDLE_TYPE" | ||
|
|
||
|
|
||
| def _use_fabric_for_group( |
There was a problem hiding this comment.
Maybe this can be cached by @lru_cache(maxsize=1) since create_nvl_single_owner_tensor, create_nvl_dist_multicast_tensor and create_nvl_dist_tensor will use it redundantly
Current MoonEP supports each rank of an EP group lives on the same node. This PR adds support for multi node with nvlink via CUDA fabric handles, valid for every GPU in the same NVLink/IMEX domain, e.g., GB200.
Tests
Run the benchmark on single node and two nodes.