总结一下多GPU的相关要点。
1、使用多gpu的原因:
2、常见的gpu间通信模式
3、单一节点内遍历并选择设备的代码
cudaError_t cudaGetDeviceCount(int *count);
cudaError_t cudaGetDeviceProperties(struct cudaDeviceProp *prop, int device);
cudaError_t cudaSetDevice(int device);
4、应用程序为64位运行在计算能力4.0以上,连接在同一个PCIe根节点上的gpu,可以通过cuda p2p api直接进行通信,允许两种通信模式:
gpu连接在不同的PCIe根节点上,仍然可以使用cuda p2p api 进行点对点传输,驱动器将通过主机内存透明地传输数据。 32位应用程序不支持点对点访问
5、启用点对点访问的代码
//检查设备是否支持点对点访问
cudaError_t cudaDeviceCanAccessPeer(int* canAccessPeer, int device, int peerDevice);
//显式启用点对点访问
cudaError_t cudaDeviceEnablePeerAccess(int peerDevice, unsigned int flag);
//关闭点对点访问
cudaError_t cudaDeviceDisablePeerAccess(int peerDevice);
点对点访问的授权是单向的。
6、点对点内存复制
cudaError_t cudaMemcpyPeerAsync(void* dst, int dstDev, void* src, int srcDev, size_t nBytes, cudaStream_t stream);
7、多gpu间的同步 流和事件也适用于多gpu应用程序。典型的工作流程如下所示:
只有与流相关联的设备是当前设备时,在流中才能启动内核。只有与该流相关联的设备是当前设备时,才可以在流中记录事件。
这里要格外关注一个概念,即当前设备的概念。
任何时间都可以在任何流中进行内存拷贝,无论该流与什么设备相关联或当前设备是什么。即使流或事件与当前设备不相关,也可以查询或同步它们。
8、一旦选定当前设备,如下cuda运算将被应用到那个设备上:
9、跨设备的内存复制不需要显式地设置当前设备。如果在内存复制前指定了设备,也不会影响它的行为。
10、每个流和事件都与单一设备相联系,但同步流和事件时,并不需要该设备为当前设备。
Refs:
《cuda c编程 权威指南》