C++ 从多个MPI进程调用cudaMemcpy最可靠的方法是什么?

C++ 从多个MPI进程调用cudaMemcpy最可靠的方法是什么?,c++,pointers,cuda,mpi,C++,Pointers,Cuda,Mpi,我正在开发一个库,该库使用CUDA和MPI动态分配微分方程的解。我有许多节点,每个节点都有一个NVIDIA GPU。当然,每个节点也有多个进程。该方程接受一定数量的输入(本例中为6),并构建一个解决方案,该解决方案在GPU的全局内存中表示为一个数组 我当前的策略是在每个节点的根进程上分配输入数据缓冲区: if (node_info.is_node_root_process) { cudaMalloc(&gpu_input_buffer.u_buffer, totalsize);

我正在开发一个库,该库使用CUDA和MPI动态分配微分方程的解。我有许多节点,每个节点都有一个NVIDIA GPU。当然,每个节点也有多个进程。该方程接受一定数量的输入(本例中为6),并构建一个解决方案,该解决方案在GPU的全局内存中表示为一个数组

我当前的策略是在每个节点的根进程上分配输入数据缓冲区:

if (node_info.is_node_root_process)
{
    cudaMalloc(&gpu_input_buffer.u_buffer, totalsize);
    cudaMalloc(&gpu_input_buffer.v_buffer, totalsize);
}
然后,我希望每个进程分别调用
cudaMemcpy
,将输入数据复制到GPU全局内存中,每个进程都复制到该输入缓冲区中的不同位置。这样,输入缓冲区在内存中是连续的,可以实现内存合并

我知道从多个进程(或线程)调用
cudaMemcpy
,调用将在设备上串行执行。这很好

我想做的是共享地址,例如,
gpu\u input\u buffer.u\u buffer
指向每个进程。这样,每个进程都有一个偏移量
process\gpu\u io\u offset
,这样与该进程相关的数据就是
gpu\u input\u buffer.u\u buffer+process\u gpu\u io\u offset
gpu input\u buffer.u\u buffer+process\u gpu\u io\u offset+点数-1

我已经读到,由于使用了虚拟寻址,所以禁止通过MPI共享指针值,但由于所有GPU数据都驻留在单个内存空间中,而且GPU\u input\u buffer.u\u buffer是一个设备指针,我认为这应该可以

这是实现我想要的东西的可靠方法吗

编辑:基于CUDA文档:

主机线程创建的任何设备内存指针或事件句柄都可以 被同一进程中的任何其他线程直接引用。信息技术 但是,在此过程之外无效,因此不能 由属于不同进程的线程直接引用

这意味着我原来的方法是无效的。正如已经指出的那样,CUDAAPI为此目的提供了IPC内存句柄,但是我找不到任何关于如何使用MPI共享的信息。的文档只是:

CUDA IPC内存句柄


这并没有提供任何信息来支持我需要做的事情。可以创建MPI派生类型并进行通信,但这需要我知道cudaIpcMemHandle_t的成员,我不知道。CUDA运行时API特别支持在同一台机器上的进程之间共享内存区域(和事件)。就用那个

以下是示例片段(使用my)

主要流程:

auto buffer = cuda::memory::device::make_unique<unsigned char[]>(totalsize);
gpu_input_buffer.u_buffer = buffer.get(); // because it's a smart pointer
auto handle_to_share = cuda::memory::ipc::export_(gpu_input_buffer.u_buffer);
do_some_MPI_magic_here_to_share_the_handle(handle_to_share);

CUDA运行时API特别支持在同一台计算机上的进程之间共享内存区域(和事件)。就用那个

以下是示例片段(使用my)

主要流程:

auto buffer = cuda::memory::device::make_unique<unsigned char[]>(totalsize);
gpu_input_buffer.u_buffer = buffer.get(); // because it's a smart pointer
auto handle_to_share = cuda::memory::ipc::export_(gpu_input_buffer.u_buffer);
do_some_MPI_magic_here_to_share_the_handle(handle_to_share);

谢谢你的回复。我需要仔细查看您的包装,但我希望将代码的依赖项数量保持在最低限度。此外,关于在
这里做些什么\u MPI\u魔术\u共享\u句柄
中实际应该做什么,仍然是模棱两可的。。。据我所知,MPI传输仅限于
MPI_Datatype
枚举中指定的类型,因此我不太确定如何共享句柄。使用本机CUDA运行时API是否有一种干净的方法可以做到这一点?@wvn:下面的API调用是:
cudaIpcOpenMemHandle()
cudaIpcGetMemHandle()
。请参阅关于它们的说明。我还应该提到,协作者仅限于使用标准库的非常旧的版本,因此我不能保证此解决方案可以移植到他的环境中。@wvn:这只是一堆八位组。而且,即使不是-只是对MPI撒谎。没关系,这是同一台机器上的进程。相同的填充,相同的字节顺序,相同的一切。即使这真的很重要-库达人照顾你;请参阅编辑。CUDA示例代码包括如何在使用CUDA IPC且不需要MPI的进程之间共享CUDA设备内存分配的示例。感谢您的响应。我需要仔细查看您的包装,但我希望将代码的依赖项数量保持在最低限度。此外,关于在
这里做些什么\u MPI\u魔术\u共享\u句柄
中实际应该做什么,仍然是模棱两可的。。。据我所知,MPI传输仅限于
MPI_Datatype
枚举中指定的类型,因此我不太确定如何共享句柄。使用本机CUDA运行时API是否有一种干净的方法可以做到这一点?@wvn:下面的API调用是:
cudaIpcOpenMemHandle()
cudaIpcGetMemHandle()
。请参阅关于它们的说明。我还应该提到,协作者仅限于使用标准库的非常旧的版本,因此我不能保证此解决方案可以移植到他的环境中。@wvn:这只是一堆八位组。而且,即使不是-只是对MPI撒谎。没关系,这是同一台机器上的进程。相同的填充,相同的字节顺序,相同的一切。即使这真的很重要-库达人照顾你;请参阅编辑。CUDA示例代码包括如何在使用CUDA IPC且不需要MPI的进程之间共享CUDA设备内存分配的示例。
typedef __device_builtin__ struct __device_builtin__ cudaIpcMemHandle_st 
{
    char reserved[CUDA_IPC_HANDLE_SIZE];
} cudaIpcMemHandle_t;