cuda编程笔记(28)-- cudaMemcpyPeer 与 P2P 访问机制

cudaMemcpyPeer 是什么?

cudaMemcpyPeer() 是 CUDA 提供的一个 跨 GPU 内存拷贝函数,可以直接在两个不同 GPU 设备之间传输数据,而不需要中转到主机内存。

cpp 复制代码
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,
    cudaStream_t stream = 0);
  • 当两个 GPU 支持 P2P(Peer-to-Peer)访问 并且已开启时,

    它们之间的拷贝 不经过主机内存,由 GPU 内部的 DMA 直接完成;

  • 否则,会退化为"Host 中转":数据会被先拷到主机内存,再传到目标 GPU。

P2P(Peer-to-Peer)访问机制

P2P 是指不同 GPU 能够直接访问彼此的显存(Device Memory),无需经过 CPU 或主机内存。

这在多 GPU 的 NVLink 或 PCIe 同域拓扑下尤其有用。

有了 P2P:

  • 一张 GPU 可以直接读取另一张 GPU 的 global memory;

  • cudaMemcpyPeer() 可以用 GPU-GPU 通道直接传数据;

  • 两个 GPU kernel 之间可以共享数据缓冲区(只要启用了 peer access)。

cpp 复制代码
//判断device设备是否能p2p访问peerDevice设备,结果通过canAccessPeer返回
//若canAccessPeer为0则表示不支持P2P
cudaError_t cudaDeviceCanAccessPeer(int *canAccessPeer, int device, int peerDevice);

//设置当前设备可以p2p访问peerDevice设备,flags只能设置为0
cudaError_t cudaDeviceEnablePeerAccess(int peerDevice, unsigned int flags);

//设置当前设备禁用通过p2p访问peerDevice设备
cudaError_t cudaDeviceDisablePeerAccess(int peerDevice);

开启 P2P 的步骤

假设我们有两个设备 0 和 1:

cpp 复制代码
int canAccess01, canAccess10;
cudaDeviceCanAccessPeer(&canAccess01, 0, 1);
cudaDeviceCanAccessPeer(&canAccess10, 1, 0);

if (canAccess01 && canAccess10) {
    cudaSetDevice(0);
    cudaDeviceEnablePeerAccess(1, 0);
    cudaSetDevice(1);
    cudaDeviceEnablePeerAccess(0, 0);
}

注意事项

  • 必须在 支持统一虚拟寻址(UVA) 的系统上;

  • 如果两个 GPU 不在同一个 PCIe 根复合体(root complex),P2P 可能不可用;

  • 启用后,对方显存指针可以直接被访问(比如 kernel 从另一 GPU 的缓冲区读数据);

  • NVLink 拓扑下,P2P 带宽比 PCIe 高数倍。

示例代码

cpp 复制代码
#include <cuda_runtime.h>
#include <cstdio>

int main() {
    int canAccessPeer = 0;
    cudaDeviceCanAccessPeer(&canAccessPeer, 0, 1);
    if (!canAccessPeer) {
        printf("GPU0 与 GPU1 之间不支持 P2P\n");
        return 0;
    }

    cudaSetDevice(0);
    cudaDeviceEnablePeerAccess(1, 0);
    cudaSetDevice(1);
    cudaDeviceEnablePeerAccess(0, 0);

    int N = 1024;
    float *d0, *d1;
    cudaSetDevice(0);
    cudaMalloc(&d0, N * sizeof(float));
    cudaSetDevice(1);
    cudaMalloc(&d1, N * sizeof(float));

    // GPU1 <- GPU0
    cudaMemcpyPeer(d1, 1, d0, 0, N * sizeof(float));
    cudaDeviceSynchronize();

    printf("GPU0 -> GPU1 拷贝完成\n");
    cudaSetDevice(0);
    cudaFree(d0);
    cudaDeviceDisablePeerAccess(1);  // 可选:禁用 P2P
    cudaSetDevice(1);
    cudaFree(d1);
    cudaDeviceDisablePeerAccess(0);  // 可选:禁用 P2P
}

但是很可惜,我的机器上不可以使用p2p

bash 复制代码
GPU0 与 GPU1 之间不支持 P2P

可以用如下命令查看GPU的情况

bash 复制代码
$ nvidia-smi topo -m
        GPU0    GPU1    CPU Affinity    NUMA Affinity   GPU NUMA ID
GPU0     X      SYS     0-39    0               N/A
GPU1    SYS      X      0-39    0               N/A

Legend:

  X    = Self
  SYS  = Connection traversing PCIe as well as the SMP interconnect between NUMA nodes (e.g., QPI/UPI)
  NODE = Connection traversing PCIe as well as the interconnect between PCIe Host Bridges within a NUMA node
  PHB  = Connection traversing PCIe as well as a PCIe Host Bridge (typically the CPU)
  PXB  = Connection traversing multiple PCIe bridges (without traversing the PCIe Host Bridge)
  PIX  = Connection traversing at most a single PCIe bridge
  NV#  = Connection traversing a bonded set of # NVLinks
GPU间连接 显示 含义
GPU0 ↔ GPU1 SYS 通过系统互联(SMP Interconnect)通信,需要跨 CPU NUMA 节点主板总线桥

GPU0 与 GPU1 不在同一个 PCIe Root Complex 下 ,通信必须经过 CPU/QPI/UPI 链路,因此 无法建立 GPU→GPU 的直接 P2P 通信

相关推荐
quanjui3 小时前
【医学尝试】基于Segment Anything Model的医学图像分割研究:眼底OCT与X线胸片微调实战
人工智能·笔记·学习
小黄蚁3 小时前
FreeRTOS学习笔记(十二)
笔记·学习
茯苓gao3 小时前
嵌入式开发笔记:电机参数辨识与自学习完全指南——从电气参数到机械特性的深度解析
笔记·嵌入式硬件·学习
优化Henry4 小时前
学习笔记之VoNR语音业务注册流程
网络·笔记·学习·5g·信息与通信
摇滚侠4 小时前
《RocketMQ 官网》阅读笔记 RocketMQ 订阅 (Subscription)
笔记·rocketmq
风曦Kisaki5 小时前
Kubernetes(K8s)笔记Day03: Pod命名空间,标签,Pod 的调度,污点与容忍度,Pod 常见状态和重启策略,Pod 生命周期
linux·运维·笔记·docker·云原生·容器·kubernetes
六bring个六5 小时前
git使用笔记
笔记·git
砚凝霜6 小时前
软考网络工程师|第 3 章 以太网帧、物理层标准、VLAN 完整备考笔记
网络·笔记
hanlin036 小时前
刷题笔记:力扣第704、977、209题(数组相关)
笔记·算法·leetcode
晓梦林6 小时前
[WUSTCTF2020]Cr0ssfun-学习笔记
笔记·学习