为Maxwell架构优化CUDA应用程序

基于NVIDIA Maxwell架构的GPU调优CUDA应用程序编程指南。

1. Maxwell调优指南

1.1. NVIDIA Maxwell计算架构

Maxwell是NVIDIA为CUDA计算应用打造的下一代架构。Maxwell保留并扩展了与Fermi和Kepler等前代NVIDIA架构相同的CUDA编程模型,遵循这些架构最佳实践的应用程序通常无需修改代码即可在Maxwell架构上获得加速。本指南总结了如何通过利用Maxwell架构特性对应用程序进行微调以获得额外加速的方法。1

Maxwell引入了全新的流式多处理器(SM)设计,显著提升了能效。虽然Kepler SMX架构在其世代已具有极高能效,但通过研发过程,NVIDIA的GPU架构师发现了实现架构效率再次飞跃的机遇;Maxwell SM正是这一愿景的结晶。通过对控制逻辑分区、工作负载均衡、时钟门控粒度、基于编译器的调度、每时钟周期指令发射数量等多方面的改进,Maxwell SM(也称为SMM)的能效远超Kepler SMX。

首款基于Maxwell架构的GPU代号为GM107,专为笔记本和小型台式机(SFF)等功耗受限环境设计。关于GM107的详细技术说明可参阅白皮书NVIDIA GeForce GTX 750 Ti: Featuring First-Generation Maxwell GPU Technology, Designed for Extreme Performance per Watt2,该白皮书重点介绍了其每瓦特极致性能的第一代Maxwell GPU技术。

首款采用第二代Maxwell架构的GPU代号为GM204。第二代Maxwell GPU在保持前代能效优势的同时,性能实现显著提升。关于GM204的详细技术解析可参阅白皮书NVIDIA GeForce GTX 980: Featuring Maxwell, The Most Advanced GPU Ever Made

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架构的90%以上。同时SMM改进的面积效率意味着,与同级别的Fermi或Kepler芯片相比,每颗GPU将集成更多的CUDA核心。相较于Kepler设计,SMM架构在保持每时钟周期指令发射槽数量不变的同时,还降低了算术运算延迟。

与SMX类似,每个SMM配备四个warp调度器。然而不同于SMX的是,所有SMM核心功能单元都分配给特定调度器,不存在共享单元。这种对SM计算资源的分区设计——包括为每个SM选择2的幂次方数量的CUDA核心(这简化了调度并减少了停滞周期)——是SMM高效精简架构的重要组成部分。

每个分区中CUDA核心数量为2的幂次方简化了调度过程,因为每个SMM的线程束调度器会向一组专用的CUDA核心(数量等于线程束宽度)发出指令。每个线程束调度器仍具有双发射的灵活性(例如在同一周期内,可以向CUDA核心发出数学运算指令,同时向加载/存储单元发出内存操作指令),但现在单次发射已足以充分利用所有CUDA核心。

1.4.1.3. 指令延迟

SMM的另一项重大改进是显著降低了依赖数学运算的延迟;这带来的结果是进一步减少了停顿周期,因为SMM上可用的线程束级并行度(即占用率)应等于或大于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相同:在编译时向nvcc传递-Xptxas -dlcm=ca标志。

本地加载也仅缓存在L2中,如果Kepler架构下L1本地加载命中率较高,可能会增加寄存器溢出的成本。因此应重新评估占用率与溢出之间的平衡,以确保最佳性能。特别是考虑到算术延迟的改进,为Maxwell架构构建的代码可能会从稍低的占用率(由于每个线程寄存器数量增加)中受益,以换取更少的溢出。

统一的L1/纹理缓存作为内存访问的合并缓冲区,在将数据传递给线程束之前,会收集该线程束中线程所请求的数据。此功能先前由Fermi和Kepler架构中的独立L1缓存提供。

CUDA Toolkit 6.0中新增了两个设备属性:globalL1CacheSupportedlocalL1CacheSupported。希望为不同架构世代单独优化路径的开发者可以使用这些字段来简化路径选择过程。

注意

在GM204中启用全局变量缓存可能会影响占用率。如果每个线程块的SM资源使用情况在启用缓存时会导致零占用率,CUDA驱动程序将覆盖缓存选择以允许内核启动成功。分析器会报告这种情况。

1.4.3. 共享内存

1.4.3.1. 共享内存容量

在Fermi和Kepler架构中,共享内存与L1缓存共享相同的片上存储空间。相比之下,Maxwell架构为每个SMM的共享内存提供了专用空间,因为L1和纹理缓存的功能已在SMM中合并。与SMX相比,这增加了每个SMM可用的共享内存空间:GM107为每个SMM提供64 KB共享内存,而GM204进一步将这一数字提升至每个SMM 96 KB共享内存。

这为应用程序开发者带来了多项优势:

  • 对共享内存容量需求较高的算法(如基数排序)除了SM数量增加带来的整体提升外,每个SM的容量还能自动获得33%至100%的提升。

  • 应用程序不再需要为获得最佳性能而选择L1/共享内存的分割比例。为了保持与Fermi和Kepler架构的向后兼容性,应用程序可以选择继续指定这种偏好设置,但在Maxwell架构上该设置将被忽略,每个SMM将始终分配完整的64 KB作为共享内存。

注意

虽然在SMM中每个SM的共享内存容量有所增加,但每个线程块的限制仍为48 KB。为了在未来可能的GPU上获得最大灵活性,NVIDIA建议应用程序在任何单个线程块中最多使用32 KB的共享内存,这样例如至少可以容纳两个这样的线程块在每个SMM中。

1.4.3.2. 共享内存带宽

Kepler SMX引入了可选的8字节共享内存存储体模式,相比Fermi架构,该模式有望在每SM上提升8或16字节共享内存访问的带宽。然而,只有当应用程序在共享内存中存储这些较大元素时(即整数和fp32值无法受益),并且开发者通过API显式选择8字节存储体模式时,才能从中获益。

为了简化这一点,Maxwell回归到Fermi风格的共享内存存储体设计,其中存储体始终为四字节宽。考虑到SM数量的增加,整个芯片的共享内存总带宽与相应的Kepler芯片保持相当。通过这种方式,所有使用共享内存的应用程序现在都能受益于更高的带宽,即使仅将四字节项目存储到共享内存中,也无需通过API指定任何特殊偏好。

1.4.3.3. 快速共享内存原子操作

与Fermi架构相比,Kepler为全局内存的原子操作带来了显著更高的吞吐量。然而,共享内存的原子操作基本保持不变:两种架构都采用锁定/更新/解锁模式实现共享内存原子操作,在共享内存中特定位置更新存在高竞争的情况下,这种模式可能会带来较大开销。

Maxwell通过实现针对32位整数的原生共享内存原子操作,以及32位和64位的原生共享内存比较交换(CAS)功能,对此进行了改进。相比Fermi和Kepler架构的方法,这些特性可用于实现其他原子函数,同时降低开销。

注意

有关使用atomicCAS()实现fp64 atomicAdd()的示例,请参阅CUDA C++ Programming Guide

1.4.4. 动态并行

GK110引入了一项名为动态并行(Dynamic Parallelism)的新架构特性,允许GPU自主创建额外任务。CUDA 5.0中推出了利用此特性的编程模型增强功能,使运行在GK110上的内核能够在同一GPU上启动其他内核。

SMM通过在整个产品线中支持动态并行性(Dynamic Parallelism),包括GM107等低功耗芯片,将其带入主流。这将使开发者受益,因为这意味着应用程序不再需要为高端GPU设计特殊的算法实现,这些实现与在功耗受限环境中可用的算法不同。

2. 版本历史

版本 1.0

  • 首次公开发布

版本 1.1

  • 已针对第二代Maxwell架构(计算能力5.2)进行更新。

版本 1.2

  • 更新了CUDA C++编程指南和CUDA C++最佳实践指南的引用。

3. 通知

3.1. 注意事项

本文档仅供信息参考之用,不应视为对产品功能、状态或质量的保证。NVIDIA公司(“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对客户就本文所述产品的全部及累计责任应受产品销售条款的限制。

3.2. OpenCL

OpenCL是苹果公司的商标,经Khronos Group Inc.授权使用。

3.3. 商标

NVIDIA和NVIDIA标识是美国及其他国家NVIDIA公司的商标或注册商标。其他公司及产品名称可能是其各自关联公司的商标。

1

在本指南中,Fermi指计算能力2.x的设备,Kepler指计算能力3.x的设备,Maxwell指计算能力5.x的设备。

2

GM108的特性与GM107类似。