浅谈CUDA并行计算体系
叶毅嘉
摘要:近年来,图形处理器(Graphic Process Unit,GPU)的快速发展使得其逐步用于通用计算。在性能各异的并行计算平台中,英伟达(NVIDIA)公司推出的计算统一设备架构(compute Unified Device Architecture,CUDA)因为充分利用GPU(Graphic Processing Unit)强大的计算能力实现了通用并行计算而受到研究者们的青睐。
关键词:图形处理器;CUDA;并行处理
0 引言
CUDA(Compute Unified Device Architecture)模型是由英伟达(NVIDIA)公司推出的一种基于GPU通用计算的编程模型和计算体系。该架构不需要借助图像学API,直接使用类C语言即可完成并行计算,使得使用GPU处理图像中的复杂计算成为可能。
1 CUDA编程模型
CUDA将CPU串行处理和GPU并行处理完美的结合起来。一个完整的CUDA程序是由主机(CPU)程序和设备(GPU)程序共同组成,主机程序主要是为设备程序的运行做前期准备工作,主要包括数据初始化、数据拷贝、内核函数间数据交换等。而设备程序主要就是完成并行计算的任务。CUDA编程模型分为两个主要部分:CUDA软件架构和CUDA硬件架构。其中CUDA软件架构又包括了软件栈、通用编程模型和存储模型三个方面。下面将从上述内容对CUDA的编程模型进行介绍。
1.1 软件模型
根据NVIDIA的官方文档,CUDA的软件体系共分3个方面:CUDA设备驱动程序、CUDA运行时库和编程接口、CUDA官方函数库。其中,设备驱动器是直接作用于GPU上的,开发者可以通过CUDA运行时库和CUDA函数库中的函数调用来使用设备。CUDA编程模型可以根据不同的需求提供不同的API,开发者可根据对GPU的控制程度来使用。并且为了很好的利用CUDA架构,CUDA还提供了一系列的辅助开发、调试的工具。
1.2 硬件模型
软件程序的运行是建立在硬件的基础上的,而GPU之所以能够比CPU处理数据更加有效,在于GPU中有更多的晶体结构可用于计算。而在CUDA的硬件架构中,流处理器阵列是由多个线程处理器簇组成,而每个TPC又是由多个流处理器组成的。每个流处理器拥有一套完整的逻辑处理单元,就有一系列的功能,如取值、编码、译码等。每个流处理器是由8个流处理单元和2组超级函数单元构成。
2 线程模型
在CUDA编程模型中是通过大量的并行线程来实现计算的,因此CUDA架构下最小的执行单元线程(thread)。每个线程块中是由多个可以通信的线程组成,每个线程和线程块都有唯一的标示ID,则可以通过索引确切定位到每个线程。线程的索引和线程的ID是与线程块的维度所确定的,一维线程索引和ID是相同的,二维维度为(m,n)的线程块,线程索引(x,y)所对应的线程ID为x+y*m;三维维度为(m,n,k)的线程块,线程索引(x,y,z)所对应的线程ID为x+y*m+z*m*n。CUDA线程的开辟是根据所需解决问题的数据大小来确定的,而每个线程块内的线程数由于其共享一个核心处理器的存储器资源,则块内线程数量是有限制的,这个可以通过NVIDIA给出的资料查询。一般为了使每个线程块的调度达到最优值,每个块内的线程数一般设为16的倍数,但不能超过限定值。
3 存储器模型
CUDA内部存储器的结构是由寄存器、全局存储器、共享内存、本地寄存器、常量内存和纹理内存组成。下面是对这6个存储器的介绍:
寄存器位于GPU晶体片中,在各种CUDA存储结构中,它的访问速度快,因为它是线程所私有的,不允许其他线程访问和使用。但由于GPU硬件的限制,寄存器不是无限的,每个线程块中的寄存器是事先分配好的。但如果内核函数中分配的寄存器数量超过了寄存器的总数,编译器会默认的将数据转入设备端的本地内存中,这样就会大大降低程序数据访问的效率。
全局寄存器也称之为线性寄存器,占设备内存的DRAM的大部分空间,在内核函数运行时,所有的线程都可以读写其中的数据。正因如此,它的访问速度较慢,耗时较多,线程访问全局寄存器一般都要花费几百个时间周期。全局寄存器一般在CPU中完成数据空间的开辟、数据的拷贝和传输、数据的释放等操作。
常量存储器位于显存中,空间大小一般为64K,是一段只读的地址空间,由于其具有缓存并且无访问冲突的优势,常常用于常数的访问。
本地存储器是位于编译器分配的全局存储中,是归每个线程所私有的数据空间,与全局存储器相同,其在程序运行过程中不会缓存,所以其访问速度也较慢。本地存储器一般用来存放内核函数所声明的变量。
共享存储器是可以被同一块中的所有线程访问的可读写存储器,它的生存期就是块的生命期。在没有冲突的情况下,访问共享存储器几乎与访问寄存器一样快,是实现线程间通信的最好方法。在同一个块内,所有的线程都能够读共享存储器中的数据,相比于AMD的显卡来说,共享存储器是NVIDIA显卡的一项特色。其和寄存器一样位于GPU的晶体芯片中,所以其访问速度较之全局内存和本地内存来说,其效率较高,并且可以减少线程块中的线程通信的时间,一般只有2个时间周期。但由于其空间较小,一般每个SM有一个16K大小的共享寄存器,并且其数据只能在一个线程块中共享。这就容易导致各线程块中的数据不同步,容易引起数据混乱,为保证数据在程序执行中的同步性,CUDA中使用syncthreads()函数来实现线程块的同步。
纹理存储器是GPU中专门用来渲染纹理的图像处理单元,它是一块只读空间。在内核函数运行的过程中,使用纹理寄存器首先需将数据与纹理绑定。纹理存储器与常数存储器一样具有缓存机制。纹理存储器相较于其它存储器有两大优势:一是纹理存储器中的数据可以反复使用,避免了数据的重复读取,提高了效率;二是可以拾取坐标对应位置附近领域内的像元数据,该优势在对图像进行处理中,可以提高局部性数据读取效率。
4 结语
21世纪人类面临的众多重要科技课题,这些课题没有万亿次以上的计算能力是无法解决的。GPU与生俱来就有强大的计算能力,NVIDIA公司推出了cuDA架构使开发的难度大大降低,程序员可以很容易地利用GPU这个计算工具进行并行程序的开发。现在GPU在非图形领域得到了广泛的应用,基于GPU的通用计算研究也逐渐深入。