十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

CUDA simpleIPC 示例深度解析:基于 CUDA Runtime API 的多进程跨 GPU 互操作

CUDA simpleIPC 示例深度解析:基于 CUDA Runtime API 的多进程跨 GPU 互操作 CUDA simpleIPC 示例深度解析基于 CUDA Runtime API 的多进程跨 GPU 互操作【免费下载链接】cuda-samplesSamples for CUDA Developers which demonstrates features in CUDA Toolkit项目地址: https://gitcode.com/GitHub_Trending/cu/cuda-samples导读simpleIPC是 NVIDIA CUDA Samples 仓库cpp/0_Introduction/simpleIPC中一个最基础的进程间通信Inter Process Communication, IPC示例它演示了如何让多个操作系统进程各自绑定一块 GPU并借助 CUDA IPC 机制在进程间共享设备内存指针与 CUDA 事件。通过阅读本文你将掌握cudaIpcGetMemHandle/cudaIpcOpenMemHandle这一对导出-导入设备指针的核心用法、IPC 事件在跨进程流同步中的作用以及一个可复用的主进程分发 子进程计算 共享内存协调多进程协作架构。示例概览一进程一 GPU 的分布式计算雏形本示例使用 CUDA Runtime API 实现核心思想是一个进程对应一块 GPUone process per GPU来完成计算任务本质上是一个简化版的多进程多 GPU 计算框架主进程parent枚举系统中所有支持 IPC 的设备为每块设备分配一段设备内存并创建跨进程事件每个子进程child绑定一个 GPU打开其他进程内存的 IPC 句柄在各自设备上启动同一个simpleKernel内核交叉写入其他设备的内存最后每个子进程把属于自己的缓冲区拷回主机内存进行校验确认跨进程读写的数据内容正确。整个流程贯穿了 CUDA Systems Integration、Peer to PeerP2P与 InterProcess Communication 三个关键概念见 README 的 Key Concepts 一节是理解生产级多进程 CUDA 应用如多 GPU 推理服务、多进程管线的入门范本。支持环境与前置条件根据 simpleIPC/README.md本示例的软硬件要求如下维度要求GPU 计算能力Compute Capability 3.0 及以上操作系统Linux 或 WindowsCPU 架构x86_64、ppc64le注意源码中明确对 ARM 返回EXIT_WAIVED见下文构建依赖CUDA Toolkit、IPC 相关支持见仓库根 README.md 中对 CUDA IPC 的说明从 simpleIPC.cu 的main函数可以看到平台限制的落地实现__arm__/__aarch64__下直接打印 Not supported on ARM 并返回EXIT_WAIVED与 CMakeLists.txt 中 Will not build sample simpleIPC - not supported on aarch64 的构建期判断相互印证。此外CMakeLists.txt 还展示了本示例对编译工具链的要求CMake 最低版本 3.20启用cxx_std_17与cuda_std_17并开启CUDA_SEPARABLE_COMPILATION可分离编译便于cudaOccupancyMaxActiveBlocksPerMultiprocessor等运行时 API 查询内核属性。核心架构共享内存驱动的多进程协作整个程序只有一个二进制文件simpleIPC通过命令行参数个数区分角色simpleIPC.cu无参数运行进入parentProcess扮演主进程带一个整数参数运行进入childProcess(id)扮演编号为id的子进程。关键数据结构 shmStruct主进程与子进程之间传递设备选择、IPC 句柄等信息依赖一块由主进程创建、所有子进程映射的系统共享内存其结构定义在 simpleIPC.cutypedef struct shmStruct_st { size_t nprocesses; // 参与计算的进程/设备数量 int barrier; // 软件屏障计数器 int sense; // 屏障翻转位 int devices[MAX_DEVICES]; // 每个进程绑定的设备号 cudaIpcMemHandle_t memHandle[MAX_DEVICES]; // 每块设备内存的 IPC 句柄 cudaIpcEventHandle_t eventHandle[MAX_DEVICES]; // 每个跨进程事件的 IPC 句柄 } shmStruct;其中MAX_DEVICES为 32simpleIPC.cuDATA_SIZE为 64MBsimpleIPC.cu。注释特别说明对直接 NVLINK 或 PCI-E 直连的 GPU同一时刻最多允许 8 个对等端peers而 NVSWITCH 连接如 DGX-2 类平台不受此限制。共享内存与进程管理工具共享内存的创建/打开/关闭、进程的派生/等待由仓库通用工具 helper_multiprocess.h 与 helper_multiprocess.cpp 提供Linux 下sharedMemoryCreate/sharedMemoryOpen基于 POSIXshm_openmmapMAP_SHAREDWindows 下基于CreateFileMappingMapViewOfFilehelper_multiprocess.cppspawnProcess在 Linux 使用forkexecvpWindows 使用CreateProcesshelper_multiprocess.cpp为避免共享内存名冲突主进程用自身 PID 拼接出唯一的命名如simpleIPCshm12345子进程通过getppid()拿到父进程 PID 后打开同一块共享内存simpleIPC.cu。主进程流程设备筛选、句柄导出与子进程派发parentProcesssimpleIPC.cu按以下步骤工作1. 设备筛选。遍历所有设备cudaGetDeviceCount要求同时满足支持统一寻址prop.unifiedAddressing这是 CUDA IPC 的前提计算模式为cudaComputeModeDefault不能是独占/禁止模式因为本示例要求两个进程同时访问同一设备与已选设备两两满足cudaDeviceCanAccessPeer双向。满足全部条件才将该设备加入shm-devices数组否则打印提示并跳过simpleIPC.cu。2. 显式开启 P2P。对入选设备两两调用cudaSetDevicecudaDeviceEnablePeerAccess。源码注释指出这一步对 IPC 并非必需但会在设备上预先建立对等关系对于每 GPU 最多 8 个 peer的系统相当于提前占用并理顺对等关系simpleIPC.cu。3. 分配内存并导出句柄。在每个入选设备上cudaMalloc一块DATA_SIZE64MB内存然后cudaIpcGetMemHandle导出设备内存的 IPC 句柄存入共享内存cudaEventCreate创建事件标志位为cudaEventDisableTiming | cudaEventInterprocess跨进程事件必须禁用计时cudaIpcGetEventHandle导出事件句柄存入共享内存simpleIPC.cu。4. 派发并等待子进程。为每个入选设备spawnProcess一个子进程参数是设备索引i随后waitProcess阻塞等待全部子进程退出并检查退出码simpleIPC.cu。子进程流程句柄导入、跨设备写入与数据校验childProcess(id)simpleIPC.cu是计算与验证的核心1. 打开共享内存并绑定设备。打开父进程创建的共享内存读取进程总数procCount与自己的设备号然后cudaSetDevice(shm-devices[id])并创建非阻塞流cudaStreamNonBlockingsimpleIPC.cu。2. 导入所有设备的内存与事件句柄。对每个进程icudaIpcOpenMemHandle(ptr, shm-memHandle[i], cudaIpcMemLazyEnablePeerAccess); cudaIpcOpenEventHandle(event, shm-eventHandle[i]);这里使用了cudaIpcMemLazyEnablePeerAccess标志——注释明确说明不需要显式开启 peer access导入 IPC 句柄时即可惰性建立对等访问simpleIPC.cu。这与父进程中的显式cudaDeviceEnablePeerAccess形成对照。3. 循环跨设备写缓冲。在procCount轮循环中每个子进程按下标(i id) % procCount选择一块下一个要写入的缓冲区cudaStreamWaitEvent让本流等待该缓冲区当前持有者记录的事件确保缓冲区就绪启动simpleKernel把整块 64MB 缓冲区逐字节写入自身设备编号idcudaEventRecord记录事件通知后续消费者该缓冲区已写完barrierWait软屏障同步所有子进程防止某个进程冲得太快、覆盖掉他人还在等待的事件记录simpleIPC.cu。4. 拷回并校验。等待属于自己的缓冲区事件后cudaMemcpyAsync把 64MB 数据拷回主机端verification_buffer逐字节与期望值(id 1) % procCount比较——因为缓冲区最终写入者正是下一个编号的兄弟进程simpleIPC.cu。软件屏障的实现barrierWaitsimpleIPC.cu是一个两阶段的 CPU 原子屏障先做报到__sync_add_and_fetch/InterlockedAdd累加计数最后一人置sense1再做离场递减计数归零时复位sense0通过轮询sense实现所有进程的汇合。这是保证事件记录不被兄弟进程抢先覆盖的关键同步点。CUDA Runtime API 全景原 README 列出了本示例涉及的全部 CUDA Runtime API按功能分组整理如下全部可在 simpleIPC.cu 中找到实际调用功能域API设备管理cudaSetDevice、cudaGetDeviceCount、cudaGetDeviceProperties、cudaDeviceCanAccessPeer、cudaDeviceEnablePeerAccess、cudaOccupancyMaxActiveBlocksPerMultiprocessor内存管理cudaMalloc、cudaFree、cudaMemcpyAsyncIPC 内存cudaIpcGetMemHandle、cudaIpcOpenMemHandle、cudaIpcCloseMemHandleIPC 事件cudaIpcGetEventHandle、cudaIpcOpenEventHandle事件/流cudaEventCreate、cudaEventRecord、cudaEventSynchronize、cudaEventDestroy、cudaStreamCreateWithFlags、cudaStreamWaitEvent、cudaStreamSynchronize、cudaStreamDestroy错误处理cudaGetLastError其中IPC 内存三件套是贯穿全示例的主线主进程cudaIpcGetMemHandle导出、子进程cudaIpcOpenMemHandle导入、结束时cudaIpcCloseMemHandle关闭simpleIPC.cu。IPC 事件则保证跨进程的异步执行序事件本身只做同步信号、不记录时间戳因此创建时必须带cudaEventDisableTiming。构建与运行本示例的构建配置见 cpp/0_Introduction/simpleIPC/CMakeLists.txt关键点包括find_package(CUDAToolkit REQUIRED)、默认 CUDA 架构列表75 80 86 87 89 90 100 110 120、默认开启-lineinfo调试工具可用的行号信息ENABLE_CUDA_DEBUG时替换为-G以及CUDA_SEPARABLE_COMPILATION ON。可参照仓库根 README.md 的通用流程构建Linuxmkdir build cd build cmake .. make -j$(nproc)构建产物simpleIPC位于 build 目录对应位置直接无参运行即可主进程会自动挑选互相可访问的设备、派生子进程并在所有子进程完成后打印各阶段的 Step %lld done 与各进程的 verifying... / Process %d complete! 输出。若系统没有任何支持 IPC 的设备程序会输出 No CUDA devices support IPC 并以EXIT_WAIVED退出simpleIPC.cu。运行前提与注意事项统一寻址是硬前提不支持unifiedAddressing的设备会被直接跳过计算模式需为默认模式独占或禁止模式会使两进程共享设备失效Peer 数量上限直连拓扑下每 GPU 同时最多 8 个 peerNVSWITCH 拓扑不设此限ARM 平台不支持aarch64 下构建期跳过、运行期EXIT_WAIVED共享内存命名唯一性以主进程 PID 为后缀避免并发运行多个实例时互相干扰。小结simpleIPC用不到四百行代码完整演示了一条进程间共享设备内存的可行路径以操作系统共享内存传递cudaIpcMemHandle_t与cudaIpcEventHandle_t以 IPC 事件 软件屏障维持多进程间的数据依赖与执行序最终通过逐字节校验验证跨进程读写正确性。它同时触及了 CUDA 系统集成设备枚举、计算模式、P2Ppeer 能力检测与使能与 IPC 三大主题是从单进程多流走向多进程多 GPU 编程的关键桥梁。仓库中同类的进阶参考还包括 simpleP2PP2P 直连与 simpleMultiGPU多 GPU 协作而 helper_multiprocess.cpp 中的共享内存与进程派生封装则可直接复用到你自己的多进程 CUDA 项目中。【免费下载链接】cuda-samplesSamples for CUDA Developers which demonstrates features in CUDA Toolkit项目地址: https://gitcode.com/GitHub_Trending/cu/cuda-samples创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表