Support multi node nvlink fabric - #23
Conversation
| acc_tid = tidx - 32 | ||
| H_PER = cutlass.const_expr(TILE_ELEMS // ACC_THREADS) | ||
| acc_reg = cute.make_fragment((H_PER,), Float32) | ||
| acc_reg = cute.make_rmem_tensor((H_PER,), Float32) |
There was a problem hiding this comment.
This is only needed by the 4.6.0 upgrade (make_fragment was removed there). If you’d like to move to 4.6.0, please open a separate PR for the upgrade
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. |
| // Export an allocation (or multicast object) as the shareable form matching | ||
| // `use_fabric`: a Python int holding a POSIX fd, or a 64-byte bytes object | ||
| // holding a CUmemFabricHandle. | ||
| static inline pybind11::object nvl_export_shareable( |
There was a problem hiding this comment.
Maybe we can return this as at::Tensor instead of pybind11::object, which can be directly used by all_gather instead of all_gather_object to avoid pickle overhead if there're too many devices.
| return pybind11::bytes( | ||
| reinterpret_cast<const char *>(fabric.data), sizeof(fabric.data)); |
There was a problem hiding this comment.
| return pybind11::bytes( | |
| reinterpret_cast<const char *>(fabric.data), sizeof(fabric.data)); | |
| auto handle_tensor = at::empty({(int64_t)sizeof(CUmemFabricHandle)}, | |
| at::TensorOptions().dtype(at::kByte).device(at::kCPU)); | |
| std::memcpy(handle_tensor.data_ptr(), &fabric, sizeof(CUmemFabricHandle)); | |
| return std::move(handle_tensor) |
| CUCHECK(cuMemExportToShareableHandle( | ||
| &fd, handle, CU_MEM_HANDLE_TYPE_POSIX_FILE_DESCRIPTOR, 0)); | ||
| TORCH_CHECK(fd >= 0, "cuMemExportToShareableHandle returned invalid fd"); | ||
| return pybind11::int_(fd); |
|
|
||
| // Import a peer's shareable handle produced by nvl_export_shareable. | ||
| static inline CUmemGenericAllocationHandle nvl_import_shareable( | ||
| const pybind11::object &shareable, bool use_fabric |
There was a problem hiding this comment.
pybind11::object -> at::Tensor
| // non-root: import the multicast object from the handle sent by root. If it is | ||
| // an fd, the caller may close it once imported. | ||
| inline int64_t nvl_multicast_import( | ||
| const pybind11::object &shareable, bool use_fabric |
| int64_t size_bytes, int64_t num_devices | ||
| // passes it back unchanged to bind_map. The caller passes the shareable handle | ||
| // to the other ranks (closing the fd, if it is one, after all have imported). | ||
| inline std::tuple<int64_t, pybind11::object> nvl_multicast_create( |
| multi_node = False | ||
| unsupported = [] if nvl_fabric_supported() else [socket.gethostname()] | ||
| else: | ||
| probe = (socket.gethostname(), bool(nvl_fabric_supported())) |
There was a problem hiding this comment.
Using rank instead of hostname in logging, so that converting bool(nvl_fabric_supported() to torch tensor and collecting it by all_gather_into_tensor instead of all_gather_object to avoid pickle dump/load.
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.