我想直接将数据从GPU0-DDR复制到GPU1-DDR,而无需CPU-RAM。

如第15页的此处所述:http://people.maths.ox.ac.uk/gilesm/cuda/MultiGPU_Programming.pdf

Peer-to-Peer Memcpy
 Direct copy from pointer on GPU A to pointer on GPU B

 With UVA, just use cudaMemcpy(…, cudaMemcpyDefault)
     Or cudaMemcpyAsync(…, cudaMemcpyDefault)

 Also non-UVA explicit P2P copies:
     cudaError_t cudaMemcpyPeer( void * dst, int dstDevice, const void* src,
        int srcDevice, size_t count )
     cudaError_t cudaMemcpyPeerAsync( void * dst, int dstDevice,
        const void* src, int srcDevice, size_t count, cuda_stream_t stream = 0 )



如果使用cudaMemcpy(),那么我是否必须首先设置标志cudaSetDeviceFlags( cudaDeviceMapHost )
我是否必须使用从功能cudaMemcpy()获得的cudaHostGetDevicePointer(& uva_ptr, ptr, 0)指针?
函数cudaMemcpyPeer()有什么优势,如果没有优势,为什么需要它?

最佳答案

统一虚拟寻址(UVA)可以为所有CPU和GPU内存提供一个地址空间,因为它允许根据指针值确定物理内存位置。

具有UVA *的对等Memcpy

如果可以使用UVA,则cudaMemcpy可以用于对等memcpy,因为CUDA可以推断出哪个设备“拥有”了哪个内存。以下是使用UVA执行对等memcpy所需的说明:

//Check for peer access between participating GPUs:
cudaDeviceCanAccessPeer(&can_access_peer_0_1, gpuid_0, gpuid_1);
cudaDeviceCanAccessPeer(&can_access_peer_1_0, gpuid_1, gpuid_0);

//Enable peer access between participating GPUs:
cudaSetDevice(gpuid_0);
cudaDeviceEnablePeerAccess(gpuid_1, 0);
cudaSetDevice(gpuid_1);
cudaDeviceEnablePeerAccess(gpuid_0, 0);

//UVA memory copy:
cudaMemcpy(gpu0_buf, gpu1_buf, buf_size, cudaMemcpyDefault);


不使用UVA的对等内存

如果无法进行UVA,则通过cudaMemcpyPeer完成对等memcpy。这是一个例子

// Set device 0 as current
cudaSetDevice(0);
float* p0;
size_t size = 1024 * sizeof(float);
// Allocate memory on device 0
cudaMalloc(&p0, size);
// Set device 1 as current
cudaSetDevice(1);
float* p1;
// Allocate memory on device 1
cudaMalloc(&p1, size);
// Set device 0 as current
cudaSetDevice(0);
// Launch kernel on device 0
MyKernel<<<1000, 128>>>(p0);
// Set device 1 as current
cudaSetDevice(1);
// Copy p0 to p1
cudaMemcpyPeer(p1, 1, p0, 0, size);
// Launch kernel on device 1
MyKernel<<<1000, 128>>>(p1);


如您所见,在前一种情况下(可能使用UVA),您无需指定不同的指针所指的设备;在后一种情况下(不需要UVA),您必须明确提及指针所指的设备。

指令

cudaSetDeviceFlags(cudaDeviceMapHost);


用于启用主机到设备内存的映射,这是另一回事,它考虑的是主机设备内存移动,而不是对等内存移动,这是您的帖子主题。

总之,您的问题的答案是:


没有;
没有;
如果可能,请启用UVA并使用cudaMemcpy(无需指定设备);否则,请使用cudaMemcpyPeer(并且您需要指定设备)。

09-05 15:26