CUDA Graph 是 NVIDIA CUDA 平台中用于优化 GPU 工作流执行效率的机制。它通过将一系列 GPU 操作(如内核启动、内存拷贝等)预定义为有向图结构,减少 CPU 与 GPU 之间的交互开销,从而提高性能。以下是对 CUDA Graph 的详细解释:
1. CUDA Graph 的核心概念
- 图的组成:
- 节点(Nodes):表示单个 GPU 操作(如内核启动、内存拷贝、事件记录等)。
- 边(Edges):定义节点间的依赖关系,确保操作按正确顺序执行。
- 执行模式:
- 传统模式:CPU 逐个提交操作到 GPU 流(Stream),每次提交需 CPU 参与。
- Graph 模式:将操作及其依赖关系预先编码成图,一次性提交整个图,减少 CPU 开销。
2. CUDA Graph 的优势
- 降低 CPU 开销:避免频繁的 CPU-GPU 同步和指令提交。
- 提升 GPU 利用率:预定义的依赖关系允许 GPU 提前优化资源调度。
- 适用于短小、重复的任务:对大量小内核或固定流程的任务(如推理)效果显著。
- 可复用性:实例化后的图可多次执行,无需重新构建。
3. 构建 CUDA Graph 的两种方式
方式 1:显式创建(Explicit API)
- 步骤:
- 创建空图:
cudaGraphCreate()
- 手动添加节点并指定依赖(如
cudaGraphAddKernelNode
、cudaGraphAddMemcpyNode
)。 - 实例化图:将图转换为可执行的“实例”(
cudaGraphInstantiate
)。 - 执行图:
cudaGraphLaunch(instance)
。
- 创建空图:
- 适用场景:对图的精细控制需求较高时。
方式 2:流捕获(Stream Capture)
- 步骤:
- 开始捕获流:
cudaStreamBeginCapture(stream)
。 - 在流中执行常规 CUDA 操作(如内核、内存拷贝)。
- 结束捕获并生成图:
cudaStreamEndCapture(stream, &graph)
。 - 实例化并执行图。
- 开始捕获流:
- 优点:简化现有代码迁移,自动捕获依赖关系。
- 注意事项:捕获期间需避免非捕获操作(如使用默认流)。
4. 典型应用场景
- 深度学习推理:固定计算图多次执行。
- 物理模拟/游戏引擎:重复的 GPU 计算步骤。
- 流水线并行:将多个阶段的操作预定义为图,减少同步开销。
5. 关键 API 函数
- 图管理:
cudaGraphCreate(), cudaGraphDestroy() cudaGraphInstantiate(), cudaGraphLaunch()
- 流捕获:
cudaStreamBeginCapture(), cudaStreamEndCapture()
- 节点类型:
- 内核节点、内存拷贝节点、事件节点、子图节点(CUDA 11+)等。
6. 优化与注意事项
- 参数固化:图的节点参数(如内核参数指针)在实例化后不可更改。若需变更,需重新构建或使用 CUDA 11+ 的节点更新功能。
- 图的更新(CUDA 11+):
- 允许更新部分节点参数(如内核参数、内存地址)而无需重建整个图。
- 性能权衡:
- 图的构建和实例化有一定开销,适合长期复用场景。
- 动态变化的工作流可能不适合用图。
7. 示例代码(流捕获)
cudaStream_t stream;
cudaGraph_t graph;
cudaGraphExec_t instance;cudaStreamCreate(&stream);// 开始捕获流
cudaStreamBeginCapture(stream, cudaStreamCaptureModeGlobal);// 在流中执行操作(示例:内存拷贝 + 内核启动)
kernel1<<<..., stream>>>(...);
cudaMemcpyAsync(..., stream);
kernel2<<<..., stream>>>(...);// 结束捕获并实例化图
cudaStreamEndCapture(stream, &graph);
cudaGraphInstantiate(&instance, graph, NULL, NULL, 0);// 执行图
cudaGraphLaunch(instance, stream);
cudaDeviceSynchronize();// 清理
cudaGraphExecDestroy(instance);
cudaGraphDestroy(graph);
cudaStreamDestroy(stream);
8. 性能对比
- 测试场景:多个短内核连续执行。
- 传统流:每次内核启动需 CPU 提交,延迟累积。
- CUDA Graph:一次提交,延迟显著降低。
- 结果:吞吐量提升可达数倍(视具体任务而定)。
9. 兼容性与限制
- CUDA 版本:需 CUDA 10.0 或更高版本,部分高级功能需 CUDA 11+。
- GPU 架构:支持 Pascal 及更新架构(如 Volta、Ampere)。
总结
CUDA Graph 通过预定义和复用 GPU 操作图,优化了固定工作流的执行效率,尤其适合高重复性任务。开发者可通过显式创建或流捕获灵活构建图,结合 CUDA 11+ 的节点更新功能,进一步平衡性能与灵活性。正确使用时,它能显著减少 CPU 开销,提升 GPU 利用率。