本编程指南旨在针对基于 NVIDIA Maxwell 架构的 GPU 调优 CUDA 应用程序。
1. Maxwell 调优指南
1.1. NVIDIA Maxwell 计算架构
Maxwell 是 NVIDIA 面向 CUDA 计算应用程序的下一代架构。Maxwell 保留并扩展了与之前的 NVIDIA 架构(如 Fermi 和 Kepler)相同的 CUDA 编程模型,遵循这些架构最佳实践的应用程序通常无需任何代码更改即可在 Maxwell 架构上看到加速。本指南总结了可以通过利用 Maxwell 架构特性来微调应用程序以获得额外加速的方法。1
Maxwell 为流式多处理器 (SM) 引入了全新的设计,从而显著提高了能效。虽然 Kepler SMX 设计在其所属世代中已非常高效,但在其开发过程中,NVIDIA 的 GPU 架构师看到了架构效率实现又一次巨大飞跃的机会;Maxwell SM 正是这种愿景的实现。控制逻辑分区、工作负载平衡、时钟门控粒度、基于编译器的调度、每个时钟周期发出的指令数量以及许多其他增强功能的改进,使得 Maxwell SM(也称为 SMM)的效率远远超过 Kepler SMX。
首款基于 Maxwell 的 GPU 代号为 GM107,专为笔记本电脑和小型 (SFF) PC 等功耗受限环境而设计。GM107 在一篇题为 NVIDIA GeForce GTX 750 Ti:采用第一代 Maxwell GPU 技术,专为每瓦特极致性能而设计 的白皮书中进行了描述。2
首款使用第二代 Maxwell 架构的 GPU 代号为 GM204。第二代 Maxwell GPU 在保持上一代能效的同时,性能显著提高。GM204 在一篇题为 NVIDIA GeForce GTX 980:采用 Maxwell,有史以来最先进的 GPU 的白皮书中进行了描述。
GM204 的计算编程特性与 GM107 的计算编程特性相似,除非本指南中明确指出。有关本指南中讨论的编程特性的详细信息,请参阅 CUDA C++ 编程指南。
1.2. CUDA 最佳实践
CUDA C++ 编程指南 和 CUDA C++ 最佳实践指南 中描述的性能指南和最佳实践适用于所有支持 CUDA 的 GPU 架构。程序员必须主要关注遵循这些建议,以实现最佳性能。
这些指南中的高优先级建议如下:
找到并行化顺序代码的方法,
最大限度地减少主机和设备之间的数据传输,
调整内核启动配置以最大限度地提高设备利用率,
确保全局内存访问合并,
尽可能最大限度地减少对全局内存的冗余访问,
避免同一 Warp 内的线程出现长时间的发散执行序列。
1.3. 应用程序兼容性
在解决本指南中涵盖的特定性能调优问题之前,请参阅 Maxwell CUDA 应用程序兼容性指南,以确保您的应用程序以与 Maxwell 兼容的方式编译。
1.4. Maxwell 调优
1.4.1. SMM
Maxwell 流式多处理器 SMM 在许多方面与 Kepler 架构的 SMX 相似。SMM 相对于 SMX 的主要增强功能旨在提高效率,而无需显著增加应用程序每个 SM 的可用并行性。
1.4.1.1. 占用率
每个 SMM 的最大并发 Warp 数量与 SMX 相同(即 64),并且 影响 Warp 占用率的因素 与 SMX 相似或有所改进
寄存器文件大小(64k 32 位寄存器)与 SMX 相同。
每个线程的最大寄存器数 255 与 Kepler GK110 相同。与 Kepler 一样,应通过实验来确定寄存器溢出与占用率之间的最佳平衡。
每个 SM 的最大线程块数已从 16 增加到 32。对于线程块较小(64 个或更少线程)的内核(在共享内存和寄存器文件资源允许的情况下),这应带来自动占用率的提高。此类内核过去往往会低估 SMX 的利用率,但 SMM 的情况有所改善。
共享内存容量已增加(请参阅 共享内存容量)。
因此,开发人员可以期望 SMM 上的占用率与之前相似或有所提高,而无需更改其应用程序。与此同时,最大设备利用率的 Warp 占用率要求(即,可用并行性)与 SMX 相似或更低(请参阅 指令延迟)。
1.4.1.2. 指令调度
每个 SM 的 CUDA 核心数已减少为 2 的幂,但是凭借 Maxwell 改进的执行效率,每个 SM 的性能通常在 Kepler 性能的 10% 以内,并且 SMM 改进的面积效率意味着每个 GPU 的 CUDA 核心数将大大高于可比的 Fermi 或 Kepler 芯片。与 Kepler 设计相比,SMM 保留了相同的每个时钟周期的指令发出槽数,并减少了算术延迟。
与 SMX 一样,每个 SMM 都有四个 Warp 调度器。但是,与 SMX 不同,所有 SMM 核心功能单元都分配给特定的调度器,没有共享单元。除了选择 2 的幂的 CUDA 核心数(简化了调度并减少了停顿周期)之外,SMM 中 SM 计算资源的这种分区也是 SMM 精简效率的主要组成部分。
2 的幂的每个分区 CUDA 核心数简化了调度,因为每个 SMM 的 Warp 调度器都向专用的 CUDA 核心集发出指令,CUDA 核心集的大小等于 Warp 宽度。每个 Warp 调度器仍然可以灵活地双重发出指令(例如,在同一周期中向 CUDA 核心发出数学运算指令,同时向加载/存储单元发出内存运算指令),但现在单次发出指令就足以充分利用所有 CUDA 核心。
1.4.1.3. 指令延迟
SMM 的另一个主要改进是相关数学运算延迟已显著减少;这带来的结果是停顿周期进一步减少,因为 SMM 上的可用 Warp 级并行性(即,占用率)应等于或大于 SMX(请参阅 占用率),同时每个数学运算完成所需的时间更少,从而提高了利用率和吞吐量。
1.4.1.4. 指令吞吐量
SMM 中峰值指令吞吐量的最显著变化如下:
每个 SM 的 CUDA 核心数 的变化带来了每个 SM 每个时钟周期的峰值单精度浮点运算次数的相应变化。但是,由于 SM 的数量通常会增加,因此结果是聚合峰值吞吐量的增加;此外,上面讨论的调度和延迟改进也使这个峰值更容易接近。
许多整数运算(包括乘法、逻辑运算和移位)的吞吐量都得到了提高。此外,现在还有专门的整数指令可以加速指针运算。当数据结构的大小为 2 的幂时,这些指令效率最高。
注意
与之前的推荐最佳实践一样,在 SMM 上获得最佳吞吐量时,应尽可能优先使用有符号算术而不是无符号算术。C 语言标准对无符号数学运算的溢出行为施加了更多限制,从而限制了编译器优化机会。
1.4.2. 内存吞吐量
1.4.2.1. 统一 L1/纹理缓存
Maxwell 将 L1 和纹理缓存的功能组合到一个单元中。
与 Kepler 一样,Maxwell 中的全局加载仅缓存在 L2 中,除非使用 Kepler 中引入的 LDG 只读数据缓存机制。
与 Kepler GK110B 类似,GM204 默认保留此行为,但也允许应用程序选择在其统一 L1/纹理缓存中缓存全局加载。选择机制与 GK110B 相同:在编译时将 -Xptxas -dlcm=ca
标志传递给 nvcc
。
本地加载也仅缓存在 L2 中,如果使用 Kepler 时 L1 本地加载命中率很高,则可能会增加寄存器溢出的成本。因此,应重新评估占用率与溢出之间的平衡,以确保最佳性能。特别是考虑到算术延迟的改进,为 Maxwell 构建的代码可能会受益于略低的占用率(由于每个线程的寄存器增加),以换取更低的溢出。
统一 L1/纹理缓存充当内存访问的合并缓冲区,在将数据传递到 Warp 之前,收集 Warp 的线程请求的数据。此功能以前由 Fermi 和 Kepler 中的独立 L1 缓存提供。
CUDA Toolkit 6.0 中添加了两个新的设备属性:globalL1CacheSupported
和 localL1CacheSupported
。希望为各种架构世代提供单独调优路径的开发人员可以使用这些字段来简化路径选择过程。
注意
在 GM204 中启用全局缓存可能会影响占用率。如果启用缓存后,每个线程块的 SM 资源使用率将导致零占用率,则 CUDA 驱动程序将覆盖缓存选择以允许内核启动成功。分析器会报告这种情况。
1.4.4. 动态并行
GK110 引入了一种名为动态并行的新架构特性,该特性允许 GPU 为自身创建额外的工作。CUDA 5.0 中引入了利用此特性的编程模型增强功能,以使在 GK110 上运行的内核能够在同一 GPU 上启动其他内核。
SMM 通过在整个产品线(甚至在 GM107 等低功耗芯片中)支持动态并行,使其成为主流。这将使开发人员受益,因为这意味着应用程序将不再需要针对高端 GPU 的特殊算法实现,这些实现与功耗受限环境中可用的算法实现不同。
2. 修订历史
版本 1.0
首次公开发布
版本 1.1
针对第二代 Maxwell(计算能力 5.2)进行了更新。
版本 1.2
更新了对 CUDA C++ 编程指南和 CUDA C++ 最佳实践指南的引用。
3. 声明
3.1. 声明
本文档仅供参考,不应视为对产品的特定功能、条件或质量的保证。NVIDIA Corporation(“NVIDIA”)对本文档中包含信息的准确性或完整性不作任何明示或暗示的陈述或保证,并且对本文档中包含的任何错误不承担任何责任。NVIDIA 对因使用此类信息或因使用此类信息而可能导致的侵犯第三方专利或其他权利的行为的后果或使用不承担任何责任。本文档不构成对开发、发布或交付任何材料(如下所定义)、代码或功能的承诺。
NVIDIA 保留随时对本文档进行更正、修改、增强、改进和任何其他更改的权利,恕不另行通知。
客户在下订单前应获取最新的相关信息,并应验证此类信息是否为最新且完整。
NVIDIA 产品根据订单确认时提供的 NVIDIA 标准销售条款和条件进行销售,除非 NVIDIA 和客户的授权代表签署的个别销售协议(“销售条款”)另有约定。NVIDIA 特此明确反对将任何客户通用条款和条件应用于购买本文档中引用的 NVIDIA 产品。本文档未直接或间接形成任何合同义务。
NVIDIA 产品并非设计、授权或保证适用于医疗、军事、航空、航天或生命维持设备,也不适用于 NVIDIA 产品的故障或失灵可能合理预期会导致人身伤害、死亡或财产或环境损害的应用。NVIDIA 对在上述设备或应用中包含和/或使用 NVIDIA 产品不承担任何责任,因此,此类包含和/或使用由客户自行承担风险。
NVIDIA 不对基于本文档的产品适用于任何特定用途做出任何陈述或保证。NVIDIA 不一定会对每个产品的所有参数进行测试。客户全权负责评估和确定本文档中包含的任何信息的适用性,确保产品适合客户计划的应用和用途,并为该应用执行必要的测试,以避免应用或产品的默认设置。客户产品设计中的缺陷可能会影响 NVIDIA 产品的质量和可靠性,并可能导致超出本文档中包含的附加或不同的条件和/或要求。对于可能基于或归因于以下原因的任何默认设置、损坏、成本或问题,NVIDIA 不承担任何责任:(i) 以任何违反本文档的方式使用 NVIDIA 产品,或 (ii) 客户产品设计。
本文档未授予任何 NVIDIA 专利权、版权或其他 NVIDIA 知识产权下的任何明示或暗示的许可。NVIDIA 发布的有关第三方产品或服务的信息不构成 NVIDIA 授予使用此类产品或服务的许可,也不构成 NVIDIA 对其的保证或认可。使用此类信息可能需要获得第三方的专利或其他知识产权下的许可,或获得 NVIDIA 的专利或其他知识产权下的 NVIDIA 许可。
只有在事先获得 NVIDIA 书面批准的情况下,才允许复制本文档中的信息,且复制时不得进行更改,并应完全遵守所有适用的出口法律和法规,并附带所有相关的条件、限制和声明。
本文档和所有 NVIDIA 设计规范、参考板、文件、图纸、诊断程序、列表和其他文档(统称为“材料”)均按“原样”提供。NVIDIA 不对材料做出任何明示、暗示、法定或其他形式的保证,并且明确否认所有关于不侵权、适销性和特定用途适用性的暗示保证。在法律未禁止的范围内,在任何情况下,NVIDIA 均不对因使用本文档而引起的任何损害(包括但不限于任何直接、间接、特殊、偶然、惩罚性或后果性损害,无论何种原因造成,也无论何种责任理论)承担责任,即使 NVIDIA 已被告知可能发生此类损害。尽管客户可能因任何原因而遭受任何损害,但 NVIDIA 对本文所述产品的客户承担的累计总责任应根据产品的销售条款进行限制。
3.2. OpenCL
OpenCL 是 Apple Inc. 的商标,已获得 Khronos Group Inc. 的许可使用。
3.3. 商标
NVIDIA 和 NVIDIA 徽标是 NVIDIA Corporation 在美国和其他国家/地区的商标或注册商标。其他公司和产品名称可能是与其相关的各自公司的商标。