9.2_点对点机制

9.2 点对点机制

当CUDA程序使用多个GPU时,它们被称为“同事节点”(peer)。因为应用程序通常对它们一视同仁,仿佛它们是在一个项目上通力协作的同事。CUDA支持两种风格的点对点模式:显式的点对点内存复制和点对点寻址 [1]。

9.2.1 点对点内存复制

内存复制操作可以在任何两个不同设备的内存之间进行。当统一虚拟寻址(Unified Virtual Addressing,UVA)起作用时,鉴于CUDA可以推断出每个设备的节点内存,使用普通的内存复制函数族即可实现点对点内存复制。而如果UVA没有启用,点对点内存复制则必须显式调用CUDAMemcpyPeer()、CUDAMemcpyPeerAsync()、CUDAMemcpy3DPeer()或CUDAMemcpy3DPeerAsync()。

注意 CUDA不仅仅能够在两个可以直接互相寻址的设备内存间进行复制操作,而且可以在任何两个设备之间进行内存复制。如有必要,CUDA内存复制操作将使用主机内存作为中转缓冲区,从而系统中的任何设备都可以访问它。

点对点内存复制操作无法与其他操作并发执行。点对点内存复制操作要想开始,必须保证GPU上之前的等待操作全部完成;同时只有点对点内存复制操作完成之后,才能执行后续的操作。一旦有可能,CUDA将在两个指针之间进行直接点对点映射。使用直接映射,所产生的复制操作不必通过主机内存中转,速度更快。

9.2.2 点对点寻址

设备内存的点对点映射,如图2-20所示,使得一个GPU上的内核可以读写驻留在另一个GPU上的内存。由于GPU只能使用点对点的方式以PCIe速率读写数据,开发人员必须按照下述步骤划分工作量:

1)每个GPU拥有大约等量的工作要做。
2)GPU只需交换适量的数据。

基于流水线方式的计算机视觉系统即是这类系统的典型例子。在GPU构成的流水线结构中,每个步骤计算一个中间数据结构(例如,所预测对象的位置),这一数据结构需要送入流水线中下一个GPU进一步分析。这一流水线计算方式也称为模板计算(stencil computation),其中多数计算任务是由这些独立的GPU来单独执行的,但在计算步骤之间必须交换边缘数据。

欲让点对点寻址起作用,有赖于下列条件:

·启用了统一虚拟寻址。

  • 双端的GPU的计算能力必须是SM2.x或更高,并且必须基于在同等芯片。

·GPU必须位于相同的I/O集线器。

可以调用cu(da)DeviceCanAccessPeer()来查询当前设备是否可以对另一个设备的内存进行映射。

cudaError_t CUDADeviceCanAccessPeer(int *canAccessPeer, int device, int peerDevice);  
CResult cuDeviceCanAccessPeer(int *canAccessPeer, CUdevice device, CUdevice peerDevice);

点对点的映射并不是默认启用的,必须明确调用CUDADeviceEnablePeerAccess()或cuCtxEnablePeerAccess()来启用。

cudaError_t CUDADeviceEnablePeerAccess(int peerDevice, unsigned int flags);  
CResult cuCtxEnablePeerAccess(CUcontext peerContext, unsigned int Flags);

一旦点对点访问被启用,所有其他节点设备上的内存(包括新的内存分配),都是当前设备可以访问的。如要终止这种访问,可以调用CUDADeviceDisablePeerAccess()或cuCtxDisablePeerAccess()达到目的。

点对点访问需要占用少量额外的内存来保存更多的页表。这同样会导致更昂贵的内存分配,因为内存必须被映射到所有参与的设备。

点对点功能使上下文可以通过两种方式读写属于其他上下文的内存:或者通过用内存复制函数(可能会需要通过系统内存进行中转),或者直接通过内核对全局内存指针进行读写。

CUDADeviceEnablePeerAccess()函数对属于另一台设备的内存进行映射。点对点的内存寻址是不对称的。GPU A可能对GPU B分配的内存进行映射,但GPU A分配的内存对GPU B则不可用。为了让两个GPU互相使用对方的内存,每个GPU必须显式地对对方的内存进行映射。

// tell device 1 to map device 0 memory  
cudaSetDevice(1);  
cudaDeviceEnablePeerAccess(0,udaPeerAccessDefault);  
// tell device 0 to map device 1 memory  
cudaSetDevice(0);  
cudaDeviceEnablePeerAccess(1,udaPeerAccessDefault);

注意 对基于PCIe 3.0桥接芯片的GPU主板(如特斯拉

K10), 即使插到了 PCIe 2.0 的插槽上, 两个处于同一显卡的GPU也能以 PCIe 3.0 的速率进行通信。

[1] 对于点对点的寻址方案(peer-to-peer addressing),术语peer也表明所用GPU应该是完全相同的。

9.2_点对点机制 - The CUDA Handbook | OpenTech