3. 第二代的并行线程执行(PTX)指令集(ISA)架构
Fremi 是第一个支持并行线程计算PTX2.0(Parallel ThreadExecution 2.0)指令集的架构。PTX 是一个底层的虚拟机和ISA,其支持并行线程处理。在程序运行的时候,PTX 指令被GPU 驱动程序翻译为机器指令从而被执行。
PTX的主要目标:
? 提供稳定的ISA,可以在多种GPU 卡上运行。
? 在编译的时候,可以达到GPU 最高的性能。
? 提供与机器平台无关的ISA,支持C,C++,Fortran 等。
? 为应用程序和中间件开发者提供分布式代码ISA。
? 提供通用的ISA,以优化PTX 翻译成不同平台的目标机器语言
? PTX 类似汇编语言,有利于从底层编辑库和kernel,方便程序开发
? 提供可扩展的编程模型,可以支持不同数量内核的GPU。
PTX2.0 引入了几个新的特性可以大大改善GPU 的可编程性、精度和性能,主要包括:完整支持IEEE32-bit 浮点数计算、统一的地址空间以支持所有的变量和指针、支持64-bit 寻址并为OpenCL 和DirectCompute 增加了新指令。最重要的是,PTX2.0 进行了专门的设计完全支持C++编程语言。
3.1 统一的地址空间,完整支持C++
Fermi 和PTX2.0 ISA 实现了统一的地址空间,将三种不同的地址空间(线程私有的local 内存,共享内存和全局内存)合并为统一的地址,实现统一的存取操作。在PTX1.0 中,存取指令需要指定三种地址空间的一个,因为程序在编译的时候需要存取指定的那个地址空间内的值,正是因为如此,完全支持C和C++指针是不可能的,因为对于C 和C++的有些指针在编译的时候不一定能够知道其所指向的地址而是在运行的时候动态的决定其所指向的地址。
PTX2.0 版本中,统一的地址空间把三种地址空间统一成一个连续的地址空间,这样就可以借助在该连续空间上的单一的存取指令操作隐藏以前的三种不同的存取指令操作(local、shared 和globle)。40-bit 的统一地址空间可以支持1TB 的内存寻址空间,存取ISA 指令架构未来可以扩展到支持64-bit 的内存寻址。
使用统一地址空间,Fermi 可以完整支持C++编程。在C++中,所有的变量和函数都是以对象形式组织的,对象是通过指针传递的。在PTX2.0 版本中,使用统一的指针可以在统一的地址空间中找到其它空间上的对象,然后统一地址空间中的对象再由Fermi 硬件自动正确的映射到实际的三种不同的地址空间上。
3.2 对OpenCL和DirectCompute进行了优化
OpenCL 和 DirectCompute 与CUDA 编程模型很相似,它们使用非常相似的模式如线程、线程块、网格、栅栏同步、共享内存、全局内存和原子操作等。Fermi 是第三代的CUDA架构,Fermi对OpenCL 和DirectCompute 的接口指令通过格式转换实现了从硬件层面上的支持。PTX2.0 ISA还增加了支持DirectCompute 的一些指令:population count、append 和bit-reverse。
3.3 IEEE 32-bit浮点数精度
单精度浮点数指令支持IEEE754—2008 取整模式(近似、取零、正无穷大和负无穷大),Fermi 架构新增支持subnormal 数据,subnormal 数据是介于零和浮点数系统所能表示的最小规格化数值之间的数值。以前的GPU 把subnormal 数值按0 处理,显然造成了精度的损失。CPU 可以处理subnormal 数值,但是需要额外的程序来处理而且耗费几千个时钟周期。Fermi 浮点数单元FPU从硬件层面上处理subnormal 数据并且没有性能损失。
在计算机图形、线性代数和科学应用方面最频繁使用的操作是两个数相乘,然后加到第c 三个数上,比如,D=A xB,以前的GPU 使用MAD 乘加指令执行这样的函数运算,可以在一个时钟周期内完成一个MAD 操作即一个乘法和一个加法操作。MAD 执行乘法操作的结果采用了截断方法,而后在执行加法操作时又采用了近似值方法。Fermi 架构使用新的乘加指令FMA,其支持32-bit 单精度和64-bit 双精度浮点数,FMA 在MAD 的基础上进行了改进,主要是在对乘法的中间结果并没有截断而是完全保留了中间结果的精度。
3.4 通过分支判断改进条件分支性能
在Fermi ISA 中,可以从指令级的水平上管理分支线程的判断功能。分支判断可以使某些较短的条件代码有效率的执行而不会发生额外的分支指令开销。(这里的分支判断和CPU 的分支预测不是一回事,这里的分支判断predication 是PTX 类汇编语言中使用的一个变量类型,类似于高级语言中的布尔型变量,用于判断条件为真还是为假,可以简单的认为分支判断是分支预测的雏形)。
4. 内存子系统的改进
4.1 并行数据的缓存:可配置的L1 Cache 和统一的L2 Cache
最好的存储器层次应该是既能够提供共享内存也能够提供缓存,并且允许程序员对其大小进行一定程度的划分。Fermi 内存层次就实现了这两种编程风格。
传统的GPU 架构读写路径是分开(比如纹理存储器读路径中有缓存机制,而写路径是另外一种路径),这种方法不能很好的执行C 和C++编写的线程程序,因为这些程序要求读和写具有一致性。举个例子:开始将一个数据存入到纹理存储器中,读的时候这个数据缓存到cache 中,然后对该数据执行一次写操作之后,由于cache中缓存的数据并没有及时更新,所以读取的数据仍然是修改之前的数据而不是修改之后的数据,这样就导致了读路径中的缓存和实际写入存储器的数据不一致(之前的架构如果对纹理存储器进行了修改,就必须重启kernel 才能将cache 更新)。
Fermi 架构解决了这个读写不一致问题,存取数据采用统一的存储路径即每个SM 中使用可配置的L1 缓存,全局内存使用统一的L2 缓存。每个SM 中L1 缓存是可配置的既支持共享内存的使用也支持对local 和globle 操作的缓存:64KB 的缓存可以被配置为48 KB 的共享内存和16KB的L1 缓存,或者是16KB 的共享内存和48KB 的L1 缓存。
不管哪种配置,当寄存器变量不够用的时候,L1 缓存可以充当临时寄存器的作用,而以前的GPU 架构就会把溢出的寄存器变量存放到DRAM 中,增加了延迟。Fermi 中,L1 缓存的使用使得临时寄存器的数量增多了,程序的性能当然也就好了。
Fermi 拥有768KB 的统一的L2 缓存,可以供存、取和纹理操作使用。L2与所有的SM 相通,为全局存储器提供高效的、快速的数据传输。
4.2 第一代支持ECC的GPU
Fermi 是第一款支持基于存储器数据保护的错误检查与纠正功能(ECC:Error CorrectingCode )的GPU 架构,ECC 可以提高数据的一致性。
在存储器中存储数据的时候,激光束可能会引起bit 层面的改变,从而导致软件层面的错误。ECC 技术在错误影响到系统之前便检测并修复单个bit 引起的错误。
Fermi 支持单bit 错误的修复和双bit 错误的检测(Single-Error Correct Double-ErrorDetect:SECDED)。SECDED ECC 可以修复任何单bit 引起的错误。同时,确保能够检测出所有双bit 和多bit 引起的错误并报告提示以便重新运行程序而不是带着错误的数据继续执行程序。
Fermi 的寄存器文件、共享内存、L1 缓存、L2 缓存和DRAM 都支持ECC的保护,这不仅使得GPU 变得非常强大,而且非常的可靠。另外,Fermi 对于片上的数据传输支持数据校验。所有的NVIDIA GPU 都支持PCI-E 标准,支持链接层面数据再发送的循环冗余校验(CRC)。Fermi 还支持存储器总线上数据再发送的CRC 校验。
4.3 快速的原子内存操作
原子内存操作允许并发的线程同时对共享数据进行读-修改-写操作。原子操作(如加、最小值、最大值、比较和交换)在执行读-修改-写操作的时候不会被其它线程打断,这样确保了数据的一致性。原子内存操作类似锁机制(lock),可以实现线程的串行执行,即对同一个原子内存操作指令一次仅允许一个线程执行。
Fermi 架构中,由于在硬件层面上有很多的原子单元再加上L2 高速缓存,原子操作性能可以达到GT200 的20 倍。
5. 千兆线程调度引擎
Fermi 架构最重要的技术之一是对两层的分布式线程调度机制进行了改进。在芯片的层面上,全局分布式线程调度引擎负责调度线程块给不同的SM,而在SM 层面上,warp 调度引擎负责将32 个线程为一组的warp 分发给执行单元。Fermi 架构经过改善,可以实时调度24576 个线程,更重要的是Fermi 架构可以快速的实现上下文切换、并发线程执行和改善的线程块调度。
5.1 10倍的应用程序上下文切换
GPU 通过上下文切换也支持多任务执行,即每个程序都可以获得处理器资源的一部分时间(采用分时的方式利用处理器的计算资源)。Fermi架构的指令流水线经过优化可以将应用程序上下文切换时间降低到25ms 以下。除了性能的改进,这种快速切换可以使开发者创建更好的需要进行频繁的kernel-to-kernel 通信的应用程序。
5.2 并发的kernel执行
Fermi 支持并发kernel 的执行,同一应用程序上下文的不同kernel 可以同时在GPU 上执行。并发kernel 可以使程序同时执行一定数量的小的kernel 以便充分利用整个GPU 的资源。在Fermi 架构中,相同CUDA 上下文的不同kernel 可以并发执行以最大化的利用GPU 的资源。由于Fermi 架构提高了上下文切换性能,不同上下文的kernel 可以高效的串行执行。
6. Fermi架构总结
6.1 Fermi架构的全新设计
Fermi 主要针对以下方面进行了全新的设计:
? 改善双精度编程与计算能力
? ECC 支持
n ECC可以确保敏感性数据受到保护,免于内存错误而产生软件级的错误。
? 真正的支持多级缓存
n 在内存中加入缓存来提访问速度。
? 更多的共享存储器
n 共享存储器超过16KB。
? 快速原子操作
n 更快的读-修改-写的原子操作,提高并行效率。
6.2 Fermi架构的主要亮点
Fermi 架构的主要亮点是:
? 第三代流多处理器SM
n 每个SM 有32 个CUDA 核心(GT200只有8个)
n 双精度浮点数的峰值计算能力是GT200 的8x
n 双warp 调度机制可以同时启动两个独立的warp,并独立分发指令
n 64KB 的RAM,可以实现共享存储器和L1 缓存之间的协调配置
? 第二代的线程并行ISA 标准
n 统一的地址空间,完全支持C++编程
n 优化的OpenCL 和DirectCompute
n 完全支持IEEE754-2008 标准的32-bit 和64-bit 精度计算
n 完全支持32-bit 整数计算并支持64-bit 扩展
n 内存访问指令支持64-bit 寻址
n 支持分支预测
? 优秀的内存操作子系统
n 支持两个层次的数据缓存:可配置的L1 缓存和统一的L2 缓存
n 第一次支持ECC
n 改善了原子内存操作性能
? NVIDIA 千兆线程调度管理引擎
n 10倍的应用程序上下文切换能力
n 并发kernel 执行
n 支持block 更大程度的乱序执行
n 双重叠内存传输引擎