I want to subclass ProcessGroupNCCL to enable communication using a user-specified CUDA stream.
class CustomProcessGroupNCCL: public ProcessGroupNCCL {
public:
using ProcessGroupNCCL::ProcessGroupNCCL;
// Set NCCL stream by device index
void setNcclStreamByDevice(int device_index, const c10::cuda::CUDAStream& stream) {
std::string key = std::to_string(device_index);
std::lock_guard<std::mutex> guard(mutex_);
if (ncclStreams_.find(key) != ncclStreams_.end()) {
ncclStreams_.at(key) = stream;
} else {
TORCH_CHECK(false, "Key not found in ncclStreams_: ", key);
}
}
// Get NCCL stream by device index
c10::cuda::CUDAStream getNcclStreamByDevice(int device_index) {
std::string key = std::to_string(device_index);
std::lock_guard<std::mutex> guard(mutex_);
auto it = ncclStreams_.find(key);
TORCH_CHECK(it != ncclStreams_.end(), "Key not found in ncclStreams_: ", key);
return it->second;
}
// List all available NCCL stream keys
std::vector<std::string> getAvailableStreamKeys() {
std::lock_guard<std::mutex> guard(mutex_);
std::vector<std::string> keys;
for (const auto& pair : ncclStreams_) {
keys.push_back(pair.first);
}
return keys;
}
// List all available NCCL streams
std::unordered_map<std::string, c10::cuda::CUDAStream> getAvailableStreams(){
return ncclStreams_;
}
protected:
std::mutex mutex_;
};
PYBIND11_MODULE(TORCH_EXTENSION_NAME, m) {
m.doc() = "Custom ProcessGroupNCCL with stream management capabilities";
// Expose the factory function
m.def("create_custom_nccl_backend", &c10d::createCustomNCCLBackend,
"Create a custom NCCL backend with stream management",
py::arg("store"), py::arg("rank"), py::arg("size"), py::arg("options"));
// Expose the CustomProcessGroupNCCL class
py::class_<c10d::CustomProcessGroupNCCL, c10d::ProcessGroupNCCL, c10::intrusive_ptr<c10d::CustomProcessGroupNCCL>>(m, "CustomProcessGroupNCCL")
.def("set_nccl_stream_by_device", &c10d::CustomProcessGroupNCCL::setNcclStreamByDevice,
"Set NCCL stream by device index",
py::arg("device_index"), py::arg("stream"))
.def("get_nccl_stream_by_device", &c10d::CustomProcessGroupNCCL::getNcclStreamByDevice,
"Get NCCL stream by device index",
py::arg("device_index"))
.def("get_available_stream_keys", &c10d::CustomProcessGroupNCCL::getAvailableStreamKeys,
"List all available NCCL stream keys")
.def("get_available_streams", &c10d::CustomProcessGroupNCCL::getAvailableStreams);
}
I write a simple python test
import custom_nccl_backend
def setup_custom_nccl_backend():
"""
Register the custom NCCL backend with PyTorch distributed.
"""
def custom_nccl_backend_creator(store, rank, size, *args):
# Create default options for ProcessGroupNCCL
options = torch.distributed.ProcessGroupNCCL.Options()
# You can customize options here if needed
# options.timeout = timedelta(seconds=300)
# options.is_high_priority_stream = False
# Use our custom factory function
print("register args:", store, rank, size, *args)
return custom_nccl_backend.create_custom_nccl_backend(
store, rank, size, options
)
# Register the custom backend
dist.Backend.register_backend("CUSTOM_NCCL", custom_nccl_backend_creator
# main
dist.init_process_group(
backend="cuda:custom_nccl",
rank=rank,
world_size=world_size
)
# Get the process group
pg = dist.group.WORLD
backend = pg._get_backend(torch.device(f"cuda:{rank}"))
# Create a custom CUDA stream
device = torch.device(f"cuda:{rank}")
torch.cuda.set_device(device)
custom_stream = torch.cuda.Stream(device=device)
print(f"[Rank {rank}] Created custom stream: {custom_stream}")
# Set the custom stream for this device
backend.set_nccl_stream_by_device(rank, custom_stream)
It seems that c10::cuda::CUDAStream cannot be converted to and from Python’s torch.cuda.Stream . How should I handle this?
-- Process 0 terminated with the following error:
Traceback (most recent call last):
File "/usr/local/lib/python3.12/dist-packages/torch/multiprocessing/spawn.py", line 90, in _wrap
fn(i, *args)
File "/mnt/code/wangtianxing.wtx/code/streamer-ttv-7b/csrc/ProcessGroupNCCLCustom/example_usage.py", line 84, in example_with_custom_streams
backend.set_nccl_stream_by_device(rank, custom_stream)
TypeError: set_nccl_stream_by_device(): incompatible function arguments. The following argument types are supported:
1. (self: custom_nccl_backend.CustomProcessGroupNCCL, device_index: int, stream: c10::cuda::CUDAStream) -> None
Invoked with: <custom_nccl_backend.CustomProcessGroupNCCL object at 0x7f1f528a39b0>, 0, <torch.cuda.Stream device=cuda:0 cuda_stream=0xa43a250>