为什么在指定的流中没有发生 cudaMemcpyAsync P2P 复制
Why cudaMemcpyAsync P2P copy is not happening in the specified stream
正如这个问题的答案中所指出的那样
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 上执行?
探查器中的索引方案与 cudaSetDevice 函数使用的索引不同。如果您查看您的代码,您创建的流是在设备 1 上创建的,但它与分析器上索引为 [0] 的设备相关联。您应该使用 NVTX's Resource Naming API 来命名设备。它会让您更好地了解资源是如何映射到探查器上的。
这段代码真是粗心!
cudaDeviceEnablePeerAccess
不接受两个设备 ID,第二个参数应始终为 0。
正确调用cudaDeviceEnablePeerAccess
后,profiling结果显示无论设置哪个stream,源设备总是会出现cudaMemcpyAsync
。似乎如果使用目标 GPU 中的流,它将被重新分配到源设备中的流,这是自动创建的。
不过,虽然复制总是在源设备中执行,但如果将函数下发到目标流,它会阻塞目标流,直到复制完成,我猜是通过cudaEvent
。我想这就是为什么
"performance is maximized when stream belongs to the source GPU." as stated in this post
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);
正如这个问题的答案中所指出的那样
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 上执行?
探查器中的索引方案与 cudaSetDevice 函数使用的索引不同。如果您查看您的代码,您创建的流是在设备 1 上创建的,但它与分析器上索引为 [0] 的设备相关联。您应该使用 NVTX's Resource Naming API 来命名设备。它会让您更好地了解资源是如何映射到探查器上的。
这段代码真是粗心!
cudaDeviceEnablePeerAccess
不接受两个设备 ID,第二个参数应始终为 0。
正确调用cudaDeviceEnablePeerAccess
后,profiling结果显示无论设置哪个stream,源设备总是会出现cudaMemcpyAsync
。似乎如果使用目标 GPU 中的流,它将被重新分配到源设备中的流,这是自动创建的。
不过,虽然复制总是在源设备中执行,但如果将函数下发到目标流,它会阻塞目标流,直到复制完成,我猜是通过cudaEvent
。我想这就是为什么
"performance is maximized when stream belongs to the source GPU." as stated in this post 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);