我想使用不支持点对点(不在同一PCI根集线器上)的GPU的旧API在不同进程中的两个GPU之间复制数据。但是,我在同步方面遇到了麻烦。我理解的基本步骤是:
(过程0,设备0):
void * d_X;
cudaMalloc(&d_X, size);
// Put something into d_X;
cudaIpcMemHandle_t data;
cudaIpcGetMemHandle(&data, (void *)d_X);
- >通过MPI_Send / MPI_Recv发送地址和大小到进程1
(过程1,设备1):
cudaSetDevice(1);
void * d_Y;
cudaMalloc(&d_Y, size);
cudaSetDevice(0); // Need to be on device 0 to copy from device 0
void * d_X;
cudaIpcOpenMemHandle(&d_X, data, cudaIpcMemLazyEnablePeerAccess);
cudaMemcpyPeer(d_Y, 1, d_X, 0, size);
cudaIpcCloseMemHandle(d_X);
这基本上是正确的吗?一旦我确定这是正确的方法,我需要弄清楚如何正确同步,因为它很清楚我有同步问题(过时的内存被复制)。
我的GPU确实支持UVA但cudaDeviceCanAccessPeer
返回0.我实际上试图编写一些既适用于P2P也适用于此的代码,但这是我遇到的麻烦。
答案 0 :(得分:2)
我不认为你所要求的是可能的。
如果你读cudaIPCOpenMemHandle
cudaIpcMemLazyEnablePeerAccess
(在任何情况下都需要将内存句柄从另一个进程转换为本地进程中可用的设备指针),唯一可能的标志是cudaMemcpyPeer
。如果你在不具备对等功能的设备上使用此标志运行此调用,它将返回错误(根据我的测试,无论如何它应该非常明显)。
因此,在进程A中,除非设备具有对等能力(或者除非它与进程A使用的设 - 在documentation)中证明了这一点。
"后退"选项是在进程B中将数据从设备复制到主机,并使用普通的Linux IPC机制(例如映射的内存,如the cuda simpleIPC sample code中所示),以便在进程A中使主机数据可用。从那里你可以复制如果你愿意,它可以进入过程中的设备。
虽然这看起来很乏味,但对于同一进程中的两个设备,当这两个设备之间无法实现P2P时,它或多或少与template <typename BidirIt, typename OutputIt, typename T,
typename BinaryDoOp, typename BinaryUndoOp>
void sliding_window(BidirIt first, BidirIt last, OutputIt d_first,
typename std::iterator_traits<BidirIt>::difference_type length,
T init = typename std::iterator_traits<BidirIt>::value_type(),
BinaryDoOp op = std::plus<>{},
BinaryUndoOp undo = std::minus<>{})
完全相同。 simpleIPC sample code模式是通过主机临时缓冲区复制数据。