此文是写给论坛的写给论坛的大鸟小鸟看的~!最近AMD在推APU异构运算,哥我看了只能一笑置之。AMD的异构运算相对于虽然已成概念,不过在应用方面却迟迟不见有什么突破。NV方,就比较成熟鸟。哥还记得有个小鸟曾经问NV的工程师,A卡可不可以运行CUDA程序。工程师说,如果A卡的向量阵列中,也拥有可编程的高速缓冲就可以扫去一切难题。这个缓存是什么可以跟帖问哥,下文也有提及的。
为了你能看懂下文,你大爷我给你解析一下:
1.Thread指的是一个线程,它是最基本的执行单位;
2.Block指的是一组合作进程的**,它们可以通过shared memory通信;
3.Grid指的是一个内核函数的线程总和,它由block块组成;
4.Warp指硬件层的线程并行度,也就是说指令的并行宽度,NVIDIA为了上下兼容硬件因此一般取值为32;
5.原子操作:视为一个不可分割的操作,作用是防止多线程的读写冲突
1.
GT200架构:代表显卡GTX 280
GT200为NVIDIA通用架构的第一次变化,和图形架构不同,GPU内部的渲染单元摇身一变成为了通用的运算单元。GT200一共具备了240个CUDA核心,在底层组成上每个SM阵列是一个拥有8个CUDA核心的单指令多数据流单元。因此,每条指令可以控制32个单元(因为每次执行的周期时为4个周期,因此8个物理单元正好是4×8=32)。
GT200通用计算架构 1.
Fermi架构代表显卡 GTX580
Fermi主要是内置CUDA核心得到了大幅提高,达到了512个。同时存储结构也得到了优化。在实现上由于需要兼容以往的硬件,因此指令宽度依然保持为32。物理的SM为32个CUDA核心,不过由于保持了双warp的调度器,因此如果保留32单个warp的宽度就可以让每个向量机阵列实现更多的激活线程块,从而提高执行效率。
Fermi通用运算架构 CUDA硬件对比 | 核心名称 | GT200 | Fermi | CUDA核心数 | 240 | 512 | CUDA核心频率 | 1300MHz | 1540MHz | GPU频率 | 602MHz | 720MHz | Warp大小 | 32 | 32 | Block允许的最大合作线程 | 512 | 1024 | Block的最大维度 | 512×512×64 | 1024×1024×64 | Grid维度 | 65535×65535×1 | 65535×65535×1 | 每个SM中的寄存器 | 16KB | | Shared memory容量 | 16KB | 48/16KB | 一级缓存 | N/A | 48/16KB | 二级缓存 | N/A | 768KB |
测试平台及环境 | 处理器 | Core i72500k OC
4GHz | 主板 | 华硕 z68 | 内存 | 2×2GB DDR3 at 1600MHz | 显卡 | GTX 580/GTX280 |
Histogram直方图测试
直方图算法是图像处理中一个最基本的运算。它的作用是把色阶相同的像素做统计分析。在图像处理中的直方图纵坐标一般是数量,横坐标为色阶也就是亮度值。CPU算法是依靠循环逐次计算每个像素的色阶值,然后用数组记录统计数量最后用于显示。
CUDA的并行实现分为先把整个图像在空间域上通过block分解到不同的合作线程块当中。每个block中的thread并行算出每个小块图像的统计值,最后由block来并行算出。此测试过程block内需要原子加操作,block之间需要DRAM原子加操作。因此可以检验Fermi体系中原子操作的提速。
测试程序调用两个内核函数,一个为多个block并行处理切割的图像,另一个为单block函数来并行处理色阶数值。值得注意的是G80架构并不支持shared memory上的原子操作,因此G80架构的显卡只能在在一个block内实现单线程。
计算每个像素来表达色阶函数
测试结果为像素吞吐量,单位是MB/s。GTX280测试中得到9GB/s的像素计算吞吐量。而采用Fermi架构的GTX580也没经过优化的状态下达到23GB/s的像素处理能力。这当然得益Fermi GPU数量庞大的CUDA核心,加上十倍速的原子操作能力。 矩阵乘法测试 矩阵相乘测试是测试并行机器最基本的算法。本次测试的程序采用CUDA runtime层的矩阵乘法。测试主要运用到显示核心当中的高速共享存储器作为缓存,从而减少对显存数据的操作。 程序采用瓷砖算法来对矩阵元素并行执行。一般简单的并行算法是每个线程执行一个元素的相乘,然后N为边长的方形矩阵相乘则需要N平方个线程来进行运算。CUDA的优势在于可以忽略各个线程具体分配到哪个CUDA核心,这项工作完全由GPU核心的调度器完成。 由于NVIDIA的核心具有相同的底层执行宽度,因此代码可以不用修改便运行在新一代的核心之上。不过需要注意的是由于Fermi相对于之前产品不仅增加了CUDA核心,而且加大了协助线程的数量,因此虽然稍加优化才能到最大的效能。
可以看到每个block里面是一个从矩阵划分出来的小矩阵,每个block中就可以高效地实现子矩阵的乘法运算,最后这些子矩阵的结果在线程上进行叠加就可以得到最终结果。
把在显存中的矩阵元素划分为block为单位的子快,然后block内通过高速存储器来进行线程交互。不过两代硬件SM中block的最大限制不同,因此最大限度地应用SM中的存储器单元将显著提高效能。
矩阵乘法测试结果 测试中GTX280拥有73G浮点的效能,而GTX580更达到了112G浮点操作的。虽然测结果相比CPU有较大提升,不过还是低于笔者预期。笔者猜测是矩阵数据的量没够让GPU中的CUDA核心在一段时间里满负荷,因此笔者将修改代码进行从新测试,结果在近期放出。 并行规约测试 并行规约来源于一系列串行数据的规约运算。例如n个数的求和也是一种规约的特例。它并行是类似树状规约来实现。本次测试具体是CUDA架构上执行。根据两代不同的架构可以看出执行效能的差异。 此次测试的CUDA版并行规约采用循环并行的算法。第一次并行是把N个数据划分block大小的合作线程,剩下的N/2数据继续同样方法并行执行,当剩下的数据小于等于block合作线程时用单block执行并输出结果。测试的规约元素为1600万个单精度浮点数,测试的正确性由CPU执行串行程序来比较。
并行规约的一个特例就是并行加法。如图通过树结构可以来实现N个数字的相加,由叶子节点开始到根节点结束。
在CUDA的具体实现当中,分别调度多block来进行树状算。
采用2的N次方线程与对半的线程相加可以大大减少SM阵列内的高速存储器的操作冲突
UDA版并行 规约的测试结果比较令人满意,GTX280达到115GB/s的数据吞吐量,GTX580为150GB/s吞吐量。在规约1600万个数据中,GTX280使用了7毫秒,而Fermi只用了2.8毫秒。此次测试既然应用到了浮点单元以及高速存储器,因此存储器体系更优越的Fermi表现出了更大的潜力。不过注意的是本次应用的延时不在运算上,而在于CPU内存与显卡显存数据的传输上。
N体模拟测试
N体问题是天文数学上一个历史悠久的问题。它代表N个物体,在已知位置和初速度时求只有万有引力下的运动状态。当N大于3时不能得到显式解析。但可以用计算机模拟,在计算中需要大量的运算,测试中将以CUDA环境实现。 现今并行模拟N体问题的最优复杂度为N×Log2(N),此次CUDA的模拟测试同样使用现今最优算法。在笔者挑选的测试环境中具备了CUDA、OpenCL以及Direct Compute11/10等几种实现。由于实现OpenCL以及Direct Compute需要CUDA底层,因此直接选取CUDA层做测试(AMD是通过ATI Stream来支持OpenCL和Direct Compute)。
N体模拟算法还可以适用于蛋白质折叠运算、液体仿真以及显卡的全局光照当中。此次测试模拟的是1.6万个粒子,在只受到万有引力的作用时的形态变化。借此可以模拟出星系的发展。
模拟测试采用CUDA C做软件层
GTX580测试结果为680GFlop/s,GTX280也达到了420GFlop/s。模拟粒子规模设定为16384个。GTX580的CUDA效能达到后者的1.6倍。 总结 测试可以看出,代码并没为 Fermi体系达到良好的优化。大多数只紧紧依靠Fermi GPU提升CUDA核心而提升效能。即便如此,GTX580的效能也有不错的提升。从Fermi架构的改变可以看出核心在渐渐倾向通用算法而改变。 听说NVIDIA未来的新架构“伽利略”和“麦克斯韦”表面上将在会倍数提升浮点性能。同时,我预测这两代架构将会在向量机层次上有从新组织,并且也带来更多层次的存储系统的诞生。 到时可以见到一个拥有高层次向量机模型的GPU,并且既有可能在GPU内集成更多的高速读写统一缓存以及更优异的分支预测性能。 |