正如在回答这个问题的答案中指出的那样
What device number should I use (0 or 1), to copy P2P (GPU0->GPU1)?
源或目标GPU上的cuda流都可用于对等拷贝。然而,这是我从分析中得到的,它有点令人困惑。
#include <cuda.h>
#include <cuda_runtime.h>
int main() {
cudaDeviceEnablePeerAccess(0, 1);
cudaDeviceEnablePeerAccess(1, 0);
// on device 0
cudaSetDevice(0);
float* data0;
cudaMalloc(&data0, 1024000);
// on device 1
cudaSetDevice(1);
cudaStream_t stream1;
cudaStreamCreate(&stream1);
float* data1;
cudaMalloc(&data1, 1024000);
cudaMemcpyAsync(data0, data1, 1024000, cudaMemcpyDefault, stream1);
cudaDeviceSynchronize();
cudaMemcpyAsync(data1, data0, 1024000, cudaMemcpyDefault, stream1);
cudaDeviceSynchronize();
}
问题是,
为什么在我明确地将其分配给设备1时,在设备0上执行了复制作业?
答案 0 :(得分:3)
分析器中的索引方案与cudaSetDevice函数使用的索引不同。如果查看代码,则创建的流在设备1上生成,但它与分析器上的设备索引[0]相关联。您应该使用NVTX's Resource Naming API来命名设备。它将使您更好地了解资源在资源管理器上的映射方式。
答案 1 :(得分:0)
这段代码真的很粗心!
cudaDeviceEnablePeerAccess
不接受两个设备ID,第二个参数应始终为0。
在正确调用cudaDeviceEnablePeerAccess
之后,分析结果显示无论设置哪个流,cudaMemcpyAsync
始终在源设备中发生。似乎如果使用目标GPU中的流,它将被重新分配给源设备中的流,该流是自动创建的。
但是,尽管副本始终在源设备中执行,但如果该功能发布到目标流,它将阻止目标流,直到副本完成,我想这是通过cudaEvent
。我猜这就是为什么
“当流属于源GPU时,性能最大化。”如本文所述 What device number should I use (0 or 1), to copy P2P (GPU0->GPU1)?
例如:
cudaMemcpyPeerAsync(data0, 0, data1, 1, 1024000, stream0);
cudaMemcpyPeerAsync(data1, 1, data0, 0, 1024000, stream0);
虽然第一个副本将分配给设备0,第二个副本将分配给设备1,但这两个操作不会重叠,因为它们位于同一个流中。
如果第一个副本设置为设备1,则它们可以重叠。
cudaMemcpyPeerAsync(data0, 0, data1, 1, 1024000, stream1);
cudaMemcpyPeerAsync(data1, 1, data0, 0, 1024000, stream0);