P2P复制的cudaMemcpy()和cudaMemcpyPeer()有什么区别?

时间:2014-03-27 17:08:46

标签: cuda gpgpu nvidia

我想直接将数据从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 )
  1. 如果我使用 cudaMemcpy() ,那么我必须首先设置标记cudaSetDeviceFlags( cudaDeviceMapHost )吗?
  2. 我是否必须使用cudaMemcpy()指针作为cudaHostGetDevicePointer(& uva_ptr, ptr, 0)函数的结果?
  3. 功能 cudaMemcpyPeer() 有什么优势,如果没有任何优势,为什么还需要呢?

1 个答案:

答案 0 :(得分:4)

统一虚拟寻址(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的点对点memcpy

当无法使用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);

用于启用主机映射到设备内存,这是一个不同的东西,并考虑主机&lt; - &gt;设备内存移动而不是点对点内存移动,这是您帖子的主题。

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

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