对于P2P复制,cudaMemcpy()和CUDAMEMCPyper()之间有什么区别?

对于P2P复制,cudaMemcpy()和CUDAMEMCPyper()之间有什么区别?,cuda,gpgpu,nvidia,Cuda,Gpgpu,Nvidia,我想不使用CPU-RAM直接将数据从GPU0-DDR复制到GPU1-DDR 如第15页所述: 如果我使用,那么我必须首先设置一个标志cudaSetDeviceFlags(cudadevicemapost) 我是否必须使用从函数cudaHostGetDevicePointer(&uva_ptr,ptr,0)中得到的cudaMemcpy()指针 功能是否有任何优势?如果没有优势,为什么需要它 统一虚拟寻址(UVA)为所有CPU和GPU内存启用一个地址空间,因为它允许根据指针值确定物理内存位置 带UV

我想不使用CPU-RAM直接将数据从GPU0-DDR复制到GPU1-DDR

如第15页所述:

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

  • 统一虚拟寻址(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,则通过
    cudamemcypeer
    完成点对点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并使用
    cudaMemcpy
    (您不需要指定设备);否则,请使用
    cudaMemcpyPeer
    (您需要指定设备)

  • 谢谢但是在启动
    cudamemcypeer(p1,1,p0,0,size)之前,我必须在哪个上下文中(
    setCudaDevice(0或1);
    ,在0或1中?@Alex我认为这与此无关,因为您在调用
    cudamemcypeer
    时指定了源设备和目标设备。谢谢。但是如果我使用
    cudaMemcpyPeerAsync(,,,,stream)
    那么我必须使用
    setCudaDevice()设置上下文吗
    此流是在哪个位置创建的?@Alex我认为在这种情况下您不需要指定设备。从对的回答中,明确指出,
    cudaMemcpyPeerAsync
    调用将显示在分配给它的流(和设备)中,尤其是源设备。另请参见第20张幻灯片上的示例。您必须从另一个角度看待问题。您必须确保在对等异步内存传输的源设备上创建了用作
    cudamemcypeerasync
    参数的
    流。
    
    // 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);
    
    cudaSetDeviceFlags(cudaDeviceMapHost);