数据密集型应用在NVIDIA Fermi片内存储结构上的适应性分析*

2014-09-29 08:32任秀江张清波陈芳园
计算机工程与科学 2014年4期
关键词:存储空间密集型线程

舒 兵,任秀江,张清波,陈芳园

(江南计算技术研究所,江苏 无锡 214083)

1 引言

微处理器的发展已经进入了众核时代,NVIDIA的通用图形处理器(GPGPU)是典型的GPU众核架构,它在片上集成了大量简单的计算核心,通过简单运算部件的聚合提供超高计算性能。NVIDIA的Fermi[1]、Kepler[2,3]架 构 的 处 理器等是其中的典型代表。GPGPU大量的计算核心提供了并行加速的能力,适合数据的并行处理。随着2007年NVIDIA统一软件并行编程模型CUDA[4,5]的 推 出,在NVIDIA GPU上 的 应 用 与研究越来越多,广泛涉及生物、物理、天文、信号、医药、勘探等各个科学研究和工程领域。NVIDIA GPU的片上存储结构比较复杂,包括Register File和多级Cache结构以及Shared Memory等,这种复杂的存储结构可有效提升GPU对应用的适用性。

统计资料表明,众多科学领域的数据量随时间呈指数增长,且基数较大。以科学研究为例,生物医学、天文观测、信号处理、互联网络等等研究领域每年都会产生PB甚至ZB量级的数据,并且还在以指数函数的速度增长。除了数据量大的特点,这一类的数据一般还具有非结构化、可分性好、复用率较低、实时性要求等等特点。具有上述特点的应用可称之为数据密集型应用,对于数据密集型应用的处理大多集中在检索、查询、分析与挖掘这些方面,统称为数据密集型计算DIC(Data Intensive Computing)。数据密集型应用的计算访存比相对偏低,存储器操作成为应用性能的瓶颈,处理这类应用的重点在于数据的存储和传输。未来是数据的时代,数据密集型应用将占据越来越重要的比例,从处理器存储架构方面提升该类应用的性能具有现实意义。

本文主要通过分析数据密集型典型应用自身的数据特点及其在GPU上的数据映射关系,通过GPGPU-SIM所模拟的NVIDIA GT200、Fermi这两种架构上的应用表现分析GPU存储结构对该类应用的影响,对适应数据密集型应用的GPU众核处理器存储层次设计提出了建议,进而为通用众核处理器存储层次优化提供参考。

2 Fermi架构及GPGPU-SIM介绍

2.1 Fermi的整体架构

Fermi架构的CUDA核心数高达512个。512个CUDA核心组成16个流式多核处理器(SM),每个SM包含32个CUDA核心。芯片内部还包含六个64位的DRAM通道,每个通道的访存带宽约为32GB/s。GigaThread全局调度器负责分配线程块给SM。

2.2 Fermi的SM结构

SM中的计算核心分为四组,其中两组是流处理器阵列,每组包含16个CUDA Core,另外一组由16个load/store单元组成,还有一组四个特殊功能单元。另外,Fermi架构添加了对完整IEEE754-2008标准的支持,多个核心协同支持双精度浮点运算。

SM中,连续编号的32个并行线程组成一个warp,作为线程调度单元。每个SM拥有两个warp调度器和两个指令调度单位,并且两个warp可以同时执行和处理。Fermi的双warp调度器支持同时选择两个warp,并从每个warp向16个CUDA核心、16个加载/存储单元,或四个SFU发出操作指令。因为warp是独立执行的,Fermi的调度器并不需要检查指令流内的依赖性。使用双warp调度模型,Fermi可获得接近峰值的硬件性能。

为与SM中计算单元的数目增多相适应,Fermi架构中单SM中的寄存器文件规模也有了相应的增加,从GT200中的16 384个增加到了32 768个。由于CUDA编译器通常为每个线程分配10~20个寄存器[6],因而更多的寄存器通常意味着SM上可同时运行更多的线程,硬件的利用率也就更加充分。G80和GT200的每个SM都有16 KB的共享存储器SMEM(Shared MEMory)。在Fermi架构中,每个SM拥有64KB的片上存储空间,可以配置成48KB的SMEM和16KB的L1 Cache、或16KB的SMEM和48KB的L1Cache。L1Cache与Shared Memory的可配置关系增加了编程的灵活性和对应用的适应性,是在GT200基础上的一项重要创新。Fermi的L2Cache大小为768KB,由所有的SM所共享。

2.3 GPGPU-SIM介绍

GPGPU-SIM[7]于2007年由Fung W等人研发,它是一款时序精确的GPU性能模拟器。它模拟了NVIDIA统一架构GPU,并且对G80、GT200、Fermi等都有很高的模拟精度,针对不同型号的GPU都有相应的配置文件,参数修改方便。软件方面,这款模拟器配合CUDA编程模型,很好地支持了PTX(Parallel Thread eXecution)虚拟指令集和OpenGL。

与硬件结构相对应,GPGPU-SIM的功能模块由三个部分组成:着色器SC(Shader Core)、互连网络(Interconnection Network)以及存控(Memory Controller)。着色器核心通过片上互连网络连接到各个存储模块(存控)。

3 实验模拟及数据分析

3.1 应用选取

结合数据密集型应用的特点,本文选取访存指令占总指令百分比在20%以上的应用作为数据密集型应用的典型代表。为使测得的访存指令百分比具有代表性和满足数据密集型应用访存密集的特点,本文对应用程序的总指令数也设置了一个标准——1M条以上。

本文选取的应用均来自于GPGPU-SIM v3.1.1的基准测试程序[8]及CUDA SDK3.1[9]的程序。根据应用领域及其计算访存比的特点,选取如下六个应用程序作为典型算法进行分析:

(1)高级加密标准AES;(2)离散余弦变换DCT;(3)快速沃尔什变换FWT;(4)拉普拉斯变换LPS;(5)矩阵乘MatrixMul;(6)神经网络算法NN。

上面选取的六个应用程序分别涉及密码、图像、信号、数学等各个科学计算领域,较全面地涵盖了数据密集型应用的范畴,根据数据密集型应用的特点,本文设定访存总指令数大于1M、访存百分比为20%以上的应用属于数据密集型应用,删选的结果即如表1所示。

Table 1 Basic parameters of programs表1 选取的应用程序基本参数

根据指令所使用的存储部件不同,对应用程序的存储指令进行分类统计,如图1所示。图中“Param”指的是通过GPU内核call传输的参数,即所谓的Cache命中。

Figure 1 Sort instruction in programs图1 应用程序存储指令分类

3.2 数据密集型应用在可配置的L1Cache/SMEM上的适应性分析

可配置的L1Cache和Shared Memory结构是Fermi存储层次最大的亮点,给编程带来了较大的灵活性,也增加了Fermi结构对应用的适应性和通用性。通过图1对应用程序存储指令的分类,可以看出除NN外,另外几种应用都与Shared Memory有密切的关系。本节选取了SMEM分别为16KB、32KB、48KB和64KB四种情况,其中SMEM为48KB是基础情况。测试结果进行归一化得到应用加速比,如图2所示。

测试结果显示,有些应用对共享存储器(或L1 Cache)大小并不敏感,如FWT和DCT;而有的程序在共享存储器和L1Cache处于某些配置时性能最好,其他配置下性能下降,如LPS;还有一些应用随Shared Memory的变化呈现递增或递减的变化,如MatrixMul和AES。下面逐一分析这六个应用程序性能变化与硬件存储架构的关系。

(1)AES。

Figure 2 Speedup under different SMEM configurations图2 不同SMEM配置下应用程序加速比

根据图1中AES存储指令的分类可以看到,AES有80%的存储指令来自于SMEM,另外近20%的指令是访问Constant Memory和Texture Memory,访问Local Memory和Global Memory的诸如Load、Store等操作几乎可以忽略,而L1 Cache、L2Cache主要服务于Load、Store等操作,因此L1Cache、L2Cache对AES的影响几乎可以忽略。其次,UByte4所占的字节数为4+1×4=8,Shared Memory需要的存储空间大小为256×8×6=12KB。SMEM大于12KB就可以满足程序的要求,所以SMEM增大,AES性能变好,但当SMEM达到32KB或以上时,SMEM再增大时AES性能基本不变。

对于AES在SMEM为较小的16KB时,性能也达到了288.741 9,一方面是因为16KB的SMEM已经基本满足12KB的应用程序需求;另一方面,本模拟采用的是L1Cache和SMEM总和固定,L1Cache容量也能起到SMEM容量补充的作用。因此,在16KB配置下,性能还是比较高的。

(2)DCT。

该应用的性能都随SMEM的增大有轻度的下降。DCT只需要两个8×8Blocks的Shared Memory存储空间,即8×8×2×4=1KB(CUDA中一个单精度浮点数据占四个字节)。测试的SMEM配置中SMEM大小对该应用程序是足够的,所以SMEM的增大对应用程序的影响几乎可以忽略。但是,SMEM增大的同时L1Cache随之减小,这个应用有一定量的Load/Store和Param指令(约12%),这些指令对L1Cache有一定的依赖性。因此,L1Cache的减小会导致这两个应用程序性能的损失,但这种损失被大容量的L2 Cache所弥补,因此最后表现出的现象是性能的微幅下降。

(3)FWT。

FWT一条线程负责四个数据为一组的基-4 FWT计算(加减运算),程序中输入数据的规模是223个浮点数据,共享存储器中以一个基-4FWT的四个输入数据的首地址索引进行存储,占一个单精度浮点的存储空间。因此,共需要221×4B=8MB的存储空间才能一次性加载所有输入数据。但是Fermi的SMEM最大为64KB,远远小于8MB。因此,Fermi采用分块存取。Fermi一次流水调度两个warp(双warp调度),一个warp有32个线程,一个线程需要存储一个float数据(一组的四个数据的首地址),所以双warp需要读取64×4B=256B的数据,这个大小远小于SMEM最小情况的16KB。每次流水线从全局存储器拷贝256B的数据块到SMEM,并且通过预取传送可以达到隐藏访存延迟的目的;另外,存入共享存储器中的原始数据经过计算之后原位存储,这样达到了存储空间的最大化利用,并且大量的Load/Store(40%)操作拥有较高的Cache命中(Param),这也对FWT的性能起到了积极的作用。上述两个因素是FWT性能不随SMEM明显变化并且其IPC可以达到较高水平的根本原因。

(4)LPS。

当SMEM为32KB或48KB时,LPS性能最好;而SMEM为64KB(没有L1Cache)或者SMEM为16KB时,LPS性能损失达到35%~38%。LPS使用SMEM存储空间,共需(32+2)×(4+2)×3×4≈2.4KB共享存储器空间。所以,SMEM不是应用性能的限制因素,SMEM为64KB时,没有L1Cache,LPS有35%左右的Load/Store和Param指令,L1Cache的缺失势必导致LPS性能的下降,而且下降的幅度恰好接近35%,与存储指令的分类数据完全吻合;SMEM为16KB时,L1Cache大小为48KB,此时两个存储结构大小完全满足需求。但是,LPS性能仍然下降,这是因为L1Cache较大时,GPU需要花费较多的额外周期,以完成管理Cache等操作,而且L1 Cache越大,这种额外开销越明显,因此体现在性能上为IPC下降。

(5)MatrixMul。

该应用的表现与DCT比较类似,性能随SMEM增大而微幅下降。因为MatrixMul需要两个16×16的Blocks的存储空间,用于存储两个相乘矩阵的块数据,因此需要的存储空间为:16×16×2×4=2KB。SMEM大小足够满足应用程序的需求,但6%的Load/Store以及Param操作使得IPC随L1Cache减小而下降,同时大容量L2 Cache会缩小这种变化,所以性能表现出微幅下降。MatrixMul与DCT不同之处在于MatrixMul的绝对IPC很低,原因在于该应用的CUDA程序是与GT200相适应的,当在Fermi上运行时,Fermi存储部件结构不同造成对齐访问机制失效,产生了严重的Bank冲突,因此IPC非常低下。

(6)NN。

该应用比较特殊,它没有与Shared Memory的交互操作,它的存储指令有97%属于Load/Store和Param操作(其中Load指令就占近80%),剩下的3%左右是Constant Memory的访存操作,所以当把L1Cache取消时,NN的IPC性能只有原来的20%,其他情况下L1Cache都大于或等于16KB,完全满足要求,因此性能基本不变。可以预见,当L1Cache低于某一临界值时,随着L1Cache的减小,NN的性能将会有显著的损失,这是因为此时L1Cache成为其性能的主要限制因素。另外,NN的IPC非常低,只有35左右。与MatrixMul的性能低下原因不同,NN性能较低是因为包含大量(80%)的Load操作,此类操作与片外存储部件交互,延迟很高,达到了400~500个cycles,因此性能非常差。

3.3 数据密集型应用在可配置的L2Cache上的适应性分析

L2Cache由所有SM所共享,通过片内互连网络与DRAM连接,主要用于缓存从Global Memory中获取的数据。当SM需要读取输入数据时,首先从L1Cache中查找,若未命中,则到L2 Cache中查找,L2Cache未命中才会从Global Memory中读取。L1Cache和L2Cache的命中率一般都可以达到80%左右,作为片内存储器,L2 Cache一般采用访问速度较快的SRAM设计,访存速度远快于片外存储器,且容量一般比L1 Cache大得多,弥补了L1Cache容量不足和DRAM访问速度慢的缺点。为了测试L2Cache对数据密集型应用的影响,实验中选取了L2容量从0到1 536KB等多个大小,其中L2Cache为768KB是基础情况。归一化后的结果如图3所示。

L2Cache作为连接DRAM和L1Cache的纽带,补充了DRAM访问延迟高和L1Cache容量小的缺点。从测试的结果来看,各个应用都对L2 Cache有一定的性能表现,其中DCT、FWT、LPS和NN的曲线相对比较明显,AES和MatrixMul则对L2Cache不太敏感。具体的原因做如下分析:

(1)AES和MatrixMul。

Figure 3 Speedup under different L2configurations图3 不同L2配置下应用程序加速比

从图3可以看出,这两个应用对L2Cache不太敏感。主要是因为这两种应用的存储指令绝大多数为Shared Memory的读写指令,其中AES的这类指令占到了总存储指令的80%,而Matrix-Mul则高达近95%,这两种应用是六个应用中Shared Memory指令所占百分比最高的两种。这种指令分布决定了它们对L2Cache乃至L1 Cache都不敏感,但这两类应用毕竟存在少量的Load/Store以及Param指令,所以当取消L2 Cache时,它们的性能又会有所下降,并且下降幅度随这三类指令所占百分比呈线性递减。

(2)DCT和NN。

DCT和NN的性能随着L2Cache从无到有、从小到大在宏观上呈现出增长的趋势。这与它们的Load/Store、Param指令所占百分比较高有直接关系。比如,DCT的这类指令占到了23%多,NN的这类指令占到了90%以上,所以这两种应用是六个应用中对L2最敏感的应用。在细节方面,DCT的IPC在L2Cache低于192KB时处于低水平平缓状态,达到768KB时增幅较大,此后L2 Cache增大,其性能依然上升;而NN则随着L2 Cache增大性能平缓上升,在L2Cache超过768KB后性能保持稳定不变。造成这种现象的原因与它们的存储指令数量有关,如表2所示。

Table 2 Load/Store、Param instructions of DCT and NN表2 DCT和NN的Load/Store、Param指令

DCT的Load/Store、Param指令是NN的三倍多,并且两者都是对单精度浮点数据进行操作。更多的存储指令需要更大的Cache才能达到较高的命中率。所以,L2Cache较小时,对DCT的影响比较小,并且处于一个较低的水平,而对NN而言,L2Cache较小时就可以比较明显地影响其性能;当L2Cache增大到一定程度时,L2Cache对DCT的影响开始凸显,随L2Cache增大其性能也明显提升,而对于NN,L2Cache渐渐达到饱和,所以其性能趋于平缓。

(3)FWT和LPS。

这两种应用的性能表现有一定相似性,当L2 Cache不存在或者L2Cache较大(大于或等于768KB)时,其性能都是最高的,而当L2Cache处于中间值时,两者的性能都有一定的损失,如L2 Cache为24KB时,FWT相比于基础情况性能损失了13.4%,LPS损失了7.3%。L2Cache为0时,L1Cache完全可以满足Load/Store等指令的需求,并且节省了L2Cache的管理开销,因而性能没有降低;当L2较小时,如24KB,L1Cache与L2 Cache的大小处于同一个数量级,也就是说,L1 Cache只能部分映射到L2Cache,这样会导致大量的MISS,直接影响应用的性能,这就是为什么L2 Cache从无到有时,性能不升反降的原因。

L2Cache的大小主要与工艺有关,由于L2 Cache结构比DRAM要复杂得多,因此成本很高,在芯片上所占的面积也很大,因此一般片上二级Cache容量不能做得很大,Fermi的L2Cache大小为768KB,平均每个SM可分摊约50KB的L2 Cache;最新的Kepler架构拥有1 536KB的统一L2Cache,每个SM可分摊约100KB的L2Cache,相比于Fermi整整提高了一倍,但是Kepler的核心数目是Fermi核心数目的6倍。所以,GPU核心计算能力的提升和二级Cache层次的存储容量提升是不匹配的,存储不能匹配计算。另外,Fermi或Kepler每个SM分摊的L2Cache容量与片上L1Cache与SMEM总体容量相比远没有达到数量级的提升,其二级存储容量对一级存储容量的包容不是很明显,因此本实验数据从总体上看,L2大小从0到1 536KB,六个应用性能变化总体不是很大。

4 结束语

本文通过对六个数据密集型应用在NVIDIA的GT200、Fermi、Kepler三代GPGPU上的大量实验,对比了不同存储结构设计对数据密集型应用性能的影响。通过分析,对于数据密集型应用的GPU众核存储层次优化提出一些建议:

(1)对于数据密集型应用,L1Cache/SMEM、L2Cache和片上存储器(纹理Cache、常量Cache等)的总容量是至关重要的,随着集成电路工艺的进步,片上存储的容量需要不断提升。

(2)从Fermi到Kepler的体系结构的变化来看,片内存储容量的扩大没有很好地与片内计算性能的提升相匹配,甚至有若干倍的差异,这种差异达到一定程度会对某些数据密集型应用的性能产生较大的影响。所以,随着片上计算性能的提升,单位计算所得到的片上存储容量需要得到进一步重视。

(3)GPU的访存事务(合并访问机制)就是通过多个线程同时访问存储空间的同一个Bank达到隐藏访存延迟的目的,对于数据量较大,SMEM不够满足一次性加载所有输入数据的数据密集型应用(例如FWT),分块存取和预取技术可以很好地隐藏访存延迟并且实现SMEM的最大化利用。

(4)应用开发以及性能优化与硬件结构是密不可分的,应用程序需要契合存储层次进行合理的代码设计。对于数据密集但规则访问的一些应用,采用片上存储器模式(SMEM)而不是Cache模式,可以使应用开发者更容易进行性能优化。

(5)考虑到众核或GPU的可编程性,对于一些数据密集但不规则的应用,创新存储层次与Cache设计,可以提高其适应性。Fermi提出的可配置L1Cache/SMEM是一个伟大的创新,同时在Kepler架构上进一步提高了二级Cache的容量,这些都对扩展GPU的适应性、开放性和可编程性十分有益。

[1] NVIDIA Corporation.NVIDIA’s next generation CUDA compute architecture:Fermi[Z].Version 1.1.2009.

[2] NVIDIA Corporation.GeForce GTX 680:The fastest,most efficient GPU ever built[Z].Version 1.0.2012.

[3] NVIDIA Corporation.NVIDIA’s next generation CUDA compute architecture:Kepler GK110—The fastest,most efficient GPU ever built[Z].Version 1.0.2012.

[4] NVIDIA Corporation.NVIDIA CUDA reference manual[Z].Version 3.2Beta.2010.

[5] NVIDIA Corporation.NVIDIA CUDA API reference manual[Z].Version 4.2.2012.

[6] Cai Jing.GPGPU architecture key technology demonstration and simulator research and extension[D].Changsha:National University of Defense Technology,2009.(in Chinese)

[7] Aammodt M,Bakhoda A,Fung W.Tutorial on GPGPU-Sim:A performance simulator for massively multithreaded processor research[C]∥Proc of the 42nd Annual IEEE/ACM International Symposium on Microarchitecture,2009:1.

[8] Che Shuai,Boyer M,Meng Jia-yuan,et al.A benchmark suite for heterogeneous computing[C]∥Proc of IEEE International Symposium on in Workload Characterization,2009:1.

[9] NVIDIA Corporation.NVIDIA CUDA SDK3.1code samples[EB/OL].[2011-05-16].http://docs.nvidia.com/cuda/cuda-samples/index.html.

附中文参考文献:

[6] 蔡晶.GPGPU体系结构关键技术论证及模拟器研究与扩展[D].长沙:国防科学技术大学,2009.

猜你喜欢
存储空间密集型线程
基于多种群协同进化算法的数据并行聚类算法
压痛点密集型银质针温针灸治疗肱骨外上髁炎的临床观察
苹果订阅捆绑服务Apple One正式上线
基于国产化环境的线程池模型研究与实现
用好Windows 10保留的存储空间
密集型快速冷却技术在热轧带钢生产线的应用
密集型自动化立体仓库解析
浅谈linux多线程协作
知识密集型组织的商业模式创新策略——以网络教育组织为例
线程池技术在B/S网络管理软件架构中的应用