CUDA 编程指南 13.4.2 · 非官方中文译本
连续阅读
原著发布于 2026 年 9 月 10 日对照 NVIDIA 英文原文对应英文网页

3.5. CUDA 功能概览

本编程指南的第 1 至第 3 节介绍了 CUDA 和 GPU 编程,通过概念说明和简单的代码示例涵盖了基础主题。本指南第 4 部分中介绍特定 CUDA 功能的各节,假定读者已了解本指南第 1 至第 3 节所涵盖的概念。

CUDA 有许多适用于不同问题的功能。并非所有功能都适用于每一种用例。本章旨在介绍其中的每项功能,并说明其预期用途以及可能有助于解决的问题。各项功能根据其旨在解决的问题类型进行了粗略分类。某些功能(例如 CUDA 图)可能归入多个类别。

第 4 节更为完整、详细地介绍了这些 CUDA 功能。

3.5.1. 提高核函数性能

本节概述的所有功能都旨在帮助核函数开发者最大限度地提高其核函数的性能。

3.5.1.1. 异步屏障

异步屏障已在第 3.2.4.2 节中介绍,它允许对线程间同步进行更精细的控制。异步屏障将屏障的到达与等待分离。这使应用程序能够在等待其他线程到达时,执行不依赖于该屏障的工作。可以为不同的线程作用域指定异步屏障。有关异步屏障的完整详细信息,请参见第 4.10 节。

3.5.1.2. 异步数据复制与张量内存加速器(TMA)

在 CUDA 核函数代码中,异步数据复制是指在共享内存与 GPU DRAM 之间移动数据的同时仍能进行计算的能力。不应将其与 CPU 和 GPU 之间的异步内存复制混淆。此功能使用异步屏障。第 4.12 节详细介绍了异步复制的使用。

3.5.1.3. 流水线

流水线是一种用于将工作分阶段并协调多缓冲区生产者-消费者模式的机制,通常用于使计算与异步数据复制重叠执行。第 4.11 节提供了在 CUDA 中使用流水线的详细信息和示例。

3.5.1.4. 通过簇启动控制进行工作窃取

工作窃取是一种在不均衡工作负载中维持利用率的技术,已完成工作的工作者可以从其他工作者那里“窃取”任务。簇启动控制是计算能力 10.0(Blackwell)中引入的一项功能,它使核函数能够直接控制在途线程块调度,从而实时适应不均衡的工作负载。一个线程块可以取消另一个尚未开始的线程块或簇的启动,认领其索引,并立即开始执行窃取的工作。这种工作窃取流程可在数据不规则或运行时存在变化的情况下使 SM 保持忙碌并缩短空闲时间,实现更细粒度的负载均衡,而不必仅依赖硬件调度器。

第 4.13 节提供了如何使用此功能的详细信息。

3.5.2. 改善延迟

本节概述的功能有一个共同主题,即旨在降低某种类型的延迟,尽管各项功能所针对的延迟类型不同。总体而言,它们侧重于核函数启动层级或更高层级的延迟。核函数内部的 GPU 内存访问延迟不在此处考虑的延迟之列。

3.5.2.1. 绿色上下文

绿色上下文也称为执行上下文,是一项 CUDA 功能的名称,该功能使程序能够创建仅在 GPU 的一部分 SM 上执行工作的CUDA 上下文。默认情况下,一次核函数启动的线程块会被分派到 GPU 内任何能够满足该核函数资源要求的 SM 上。许多因素会影响哪些 SM 可以执行某个线程块,包括但不一定限于:共享内存使用量、寄存器使用量、簇的使用以及线程块中的线程总数。

执行上下文允许将核函数启动到专门创建的上下文中,该上下文会进一步限制可用于执行核函数的 SM 数量。重要的是,当程序创建使用某一组 SM 的绿色上下文时,GPU 上的其他上下文不会将线程块调度到分配给该绿色上下文的 SM 上。这也包括主上下文,即 CUDA 运行时使用的默认上下文。这使得这些 SM 可以为高优先级或延迟敏感的工作负载预留。

第 4.6 节提供了绿色上下文使用的完整详细信息。

3.5.2.2. 局部性域

局部性域是 GPU 内存和 SM 的一个子集。在具有多个局部性域的 GPU 上,在特定局部性域内分配内存,然后在仅包含同一局部性域中 SM 的绿色上下文中执行使用该内存的核函数,可能会带来好处。

局部性域是一项性能功能:未对内存或计算进行局部化的 CUDA 代码仍会正确执行。

第 1.2.3.2 节介绍了局部性域背后的概念,第 4.7 节则提供了更多信息,说明如何确定 GPU 具有多少个局部性域、如何将内存分配到特定局部性域,以及如何创建仅包含同一局部性域中 SM 的绿色上下文。

3.5.2.3. 流有序内存分配

流有序内存分配器允许程序将 GPU 内存的分配和释放按顺序排入CUDA 流。与立即执行的cudaMalloc和cudaFree不同,cudaMallocAsync和cudaFreeAsync会将内存分配或释放操作插入 CUDA 流中。第 4.3 节介绍了这些 API 的全部详细信息。

3.5.2.4. CUDA 图

CUDA 图使应用程序能够指定一系列 CUDA 操作(例如核函数启动或内存复制)及这些操作之间的依赖关系,以便在 GPU 上高效执行这些操作。使用CUDA 流可以实现类似的行为,实际上,创建图的机制之一称为流捕获,它可以将流上的操作记录到 CUDA 图中。也可以使用CUDA 图 API来创建图。

图创建后,即可将其实例化并多次执行。这有助于指定将重复执行的工作负载。图在性能方面具有一些优势,既能降低与调用 CUDA 操作相关的 CPU 启动开销,又能实现只有在预先指定整个工作负载时才可用的优化。

第 4.2 节说明并演示了如何使用 CUDA 图。

3.5.2.5. 程序化依赖启动

程序化依赖启动是一项 CUDA 功能,它允许依赖核函数(即依赖先前核函数输出的核函数)在其所依赖的主核函数完成之前开始执行。依赖核函数可以执行准备代码和无关工作,直到需要主核函数的数据时才在该处阻塞。主核函数可以在依赖核函数所需的数据就绪时发出信号,从而解除依赖核函数的阻塞,使其继续执行。这使核函数之间能够部分重叠执行,有助于保持较高的 GPU 利用率,同时最大限度地降低关键数据路径的延迟。第 4.5 节介绍了程序化依赖启动。

3.5.2.6. 延迟加载

延迟加载是一项允许控制 JIT 编译器在应用程序启动时如何工作的特性。如果在应用程序启动过程中对所有核函数进行 JIT 编译,那么对于包含许多需要从 PTX JIT 编译为 cubin 的核函数的应用程序,启动时间可能会很长。默认行为是在需要模块时才对其进行编译。可以使用环境变量更改这一行为,具体说明见第 4.8 节。

3.5.3. 功能性特性

此处描述的特性具有一个共同点,即它们旨在提供额外的能力或功能。

3.5.3.1. 扩展 GPU 内存

扩展 GPU 内存是通过 NVLink-C2C 连接的系统所具备的一项特性,它能够让 GPU 高效地访问系统内的所有内存。第 4.19 节详细介绍了 EGM。

3.5.3.2. 动态并行

CUDA 应用程序最常见的做法是从 CPU 上运行的代码中启动核函数。也可以从 GPU 上运行的核函数中创建新的核函数调用。这项特性称为CUDA 动态并行。第 4.20 节详细介绍了如何从 GPU 上运行的代码中创建新的 GPU 核函数启动。

3.5.4. CUDA 互操作性

3.5.4.1. CUDA 与其他 API 的互操作性

除了 CUDA 之外,还有其他在 GPU 上运行代码的机制。GPU 最初为之提供加速的应用领域,即计算机图形学,使用自己的一套 API,例如 Direct3D 和 Vulkan。应用程序可能希望在使用 CUDA 进行计算的同时,使用某个图形 API 进行 3D 渲染。CUDA 提供了在 CUDA 上下文与 3D API 所用的 GPU 上下文之间交换 GPU 上存储的数据的机制。例如,应用程序可以使用 CUDA 进行仿真,然后使用 3D API 对结果进行可视化。这是通过使某些缓冲区能够同时由 CUDA 和图形 API 读取和/或写入来实现的。

允许与图形 API 共享缓冲区的相同机制,也用于与通信机制共享缓冲区,这些通信机制可以在多节点环境中实现快速、直接的 GPU 到 GPU 通信。

第 4.21 节介绍了 CUDA 如何与其他 GPU API 互操作,以及如何在 CUDA 与其他 API 之间共享数据,并针对多种不同的 API 提供了具体示例。

3.5.4.2. 进程间通信

对于规模非常大的计算,通常会联合使用多个 GPU,以利用更多内存和更多计算资源来共同处理一个问题。在单个系统内,即集群计算术语中的单个节点内,可以在一个主机进程中使用多个 GPU。第 3.4 节对此进行了介绍。

另一种常见做法是使用分布在单台或多台计算机上的独立主机进程。当多个进程协同工作时,它们之间的通信称为进程间通信。CUDA 进程间通信(CUDA IPC)提供了在不同进程之间共享 GPU 缓冲区的机制。第 4.16 节解释并演示了如何使用 CUDA IPC 在不同主机进程之间进行协调和通信。

3.5.5. 细粒度控制

3.5.5.1. 虚拟内存管理

如第 2.6.1 节所述,系统中的所有 GPU 与 CPU 内存共享同一个统一虚拟地址空间。大多数应用程序可以使用 CUDA 提供的默认内存管理,而无需更改其行为。不过,CUDA 驱动 API为有需要的应用程序提供了对这一虚拟内存空间布局的高级、精细控制。这主要适用于控制在单个系统内以及跨多个系统的 GPU 之间共享缓冲区时的行为。

第 4.17 节介绍了 CUDA 驱动 API 提供的控制功能、这些功能的工作原理,以及开发者在何种情况下可能会发现它们有用。

3.5.5.2. 计算互连传输

第 4.18 节介绍了一种以资源为中心的模型,用于通过 NVLink 互连网络(fabric)进行由 GPU 发起的数据移动。在该模型中,对等方由逻辑端点 ID 和偏移量来标识,而不是由映射的虚拟地址来标识。该特性面向编写通信原语的开发者;当NCCL Device API或NVSHMEM中的任意一种符合应用程序的通信模式时,应用程序应优先使用它。

3.5.5.3. 驱动入口点访问

驱动入口点访问是指从 CUDA 11.3 开始提供的获取 CUDA 驱动 API 和 CUDA 运行时 API 函数指针的能力。它还允许开发者获取驱动函数特定变体的函数指针,以及访问比 CUDA 工具包中可用的驱动更新的驱动所提供的驱动函数。第 4.22 节介绍了驱动入口点访问。

3.5.5.4. 错误日志管理

错误日志管理提供了用于处理和记录 CUDA API 错误的实用工具。只需设置一个环境变量CUDA_LOG_FILE,即可将 CUDA 错误直接捕获到 stderr、stdout 或文件中。错误日志管理还允许应用程序注册一个回调,在 CUDA 遇到错误时触发该回调。第 4.9 节提供了有关错误日志管理的更多详细信息。

原著 © 2007 至 2026 NVIDIA Corporation 及其关联公司。保留所有权利。
中文译本仅作学习参考,非 NVIDIA 官方出版物。技术含义有疑问时请核对NVIDIA 英文原文。
关于本译本

输入关键词搜索全书。