Cuda技术革命一瞥
当前在老百姓眼中有关计算机技术的最时髦的词汇莫过于“多核”了。从前年起,“多核”这个东西就走进了家用的行列,现在购置的计算机基本上都是双核心或者是四核心的。由于“硅芯片主频的物理极限已经达到,CPU将来的发展即将走向多核方向”,得到的结果就是AMD和Intel两家公司的竞争进入了进一步的白热化阶段。
其实一台计算机多个计算单元的现象很早就出现了。古代有所谓的“解霸卡”,这是一个专门为视频解压处理而设计的处理器,原理基本就是一个为浮点优化的CPU。把视频解压的工作分给解霸卡,而CPU则留下进行更重要的工作。之后Intel推出了MMX指令集,这种卡旋即消失。后来著名的就是Voodoo卡(以及同时代的各类3D加速卡),这是现代显卡的雏形。他把浮点计算分离出来,并且直接加入了贴图和灯光的特性,使得3D游戏开始普及。伴随着DirectX技术的成熟,就产生了现代显卡。现代显卡指的是支持一定的渲染标准的显卡,如OpenGL标准、DirectX标准等。通过这种设计,程序员可以方便的通过OpenGL和DirectX接口来编制程序,而不需要考虑具体的硬件类型。这是一个跨时代的突破。
在普通的情况下用显卡进行渲染,速度要比用普通的CPU计算快上几千倍,而且图像大小(像素数)越大,加速的比例就越大。这是显卡的自身特性造成的。显卡当中,相当于封装了成百上千个“核心”,所有的“核心”可以一起处理。由于GPU的计算是一种特殊的计算任务,即所计算的每一个像素之间不需要(或者用方法使它不需要)考虑先后顺序,那么如果有了上百万个线程,就可以让所有的像素同时渲染,这样所有的像素就可以在一个像素的时间内计算完成。而实际上在CPU上的运算通常是做了一件才能再做一件,这样就算有一万个核心,在前一个结果计算出来之前,其他的线程只能傻傻等待,这就相当于一个核心了,因此CPU多核心的发展要比GPU慢得多。由于两者计算的目的不同,造成他们的构架不同。因此显卡与CPU的计算任务通常是分离的。
实际上,假如你知道你现在的将要做的计算是可以高度并行的密集型计算,那么就应该使用GPU来进行运算。然而一般的显卡却没有这样的功能,它通常只能处理矩阵、贴图、采样等等的已经有实际图形学意义的问题,而对其他的运算,只能转换成图形运算才能进行。利用GPU进行通用目的计算(General Purpose Computing)的想法很早就有了,成熟的产品有GPGPU语言等。我曾经历尽千辛万苦编写了一份在显卡上进行FFT计算的程序,其代码量之庞大简直是骇人听闻。普通的FFT在150行以内就可以完成,而GPU的FFT计算则需要至少千行(利用GPGPU语言的话代码量会少很多,但是相对于FFT程序,这个语言产品本身的空间就不小)。之所以有如此之多的代码量,是因为需要将各种数据通过一个图形接口(一般是扩展的OpenGL)发送到GPU,计算之后,再通过这个图形接口接收结果。
另外,程序员从娘胎里带出来的“一根筋”(单线程,算完一个再用结果来算另一个)的思维习惯是非常不容易改变的。除非是像渲染 这种明显就应该是并行运行的东西,其他的东西找出成熟的并行算法非常困难。这就意味着,多核的潜力还必须得到进一步的开发。当然有一个简单的方法就是运行很多的进程,可以以此把CPU塞满。
原理
nVidia公司一直以来是显卡界的两位登峰造极者(nVidia和ATI,后者前些日子与AMD公司合并为AMD&ATI公司) 之中更时尚的一位。2006年11月8日,nVidia抛出了他们的通用目的GPU计算的方案CUDA——Compute Unified Device Architecture 即计算统一的设备架构。这是业界第一个可以用C语言进行编程的通用目GPU计算解决方案。实际上走在了时间的前头。
CUDA的原理基本如下:
把 大量的线程(这个概念与一般的不同,他是更轻量级的,更快速的)分布在一个个的“块”中。每个块共享一段指令和数据,而块中的每一个线程只能访问到本块的 数据以及外层的共享数据,访问不到块之间的数据。外部的驱动程序负责把所有的数据和指令拷贝到块中,然后所有的线程开始同时运行。当最后一个线程结束后运 行结束。 #p#page_title#e#
这样,指令也相同,数据也相同,因此既不会有换页问题,也没有缓存刷新问题(考虑到实际上GPU是不具备与内存速度不同的缓存的,这个速度的提升是靠多点同时访问和显卡版内的超大带宽得到的——总之就是比那么多个CPU要快啦!囧)。仅仅这样,我们就可以得到前所未有的强大速度提升,这靠的是无以伦比的超大线程数!
在编程方面,如果我们想向一个块中写入指令,只需要像C/C++一样编写一个函数,然后用CUDA的简写方法进行调用(可以自由设置块数和线程数)。之后CUDA编译器nvcc自动将代码编译成CPU代码和GPU代码,并让GPU代码可以自动的发送到适当的快中。期间的一切硬件问题程序员都不需要管,结果就是写一个CUDA程序和写一个普通的C程序一样方便。
我现在的显卡的参数是这样的(不是什么高端的显卡,每个人的显卡都有类似的能力):14个多核处理器,每个多核理器112个核心,每个核心65536*65536*1个格点(这个不能达到最大值。实际使用中取决于显卡的当前状态),每个格点有512*512*64块,每块同时可以运行512个线程(同时每块具有8k个寄存器)。可以粗略计算一下,就算我们只用到了一个格点,我们就可以得到85亿个线程。这就是说只要我们的显存(才十亿字节)足够,那么我们就可以想开多少个线程就开多少个线程。
根据官方发布的资料,如果是更高端的Tesla卡的话,可以每秒进行500G次浮点运算。CPU浮点运算平均大约消耗400周期的话,那么CPU每秒可以进行2*3G/400=0.15G次浮点运算。相比之下大约能快3000倍左右。但是在这种构架只下,最花费时间的操作不再是运算,而是把指令和数据从内存中拷贝到显存中的过程。现在的GPU(PCI-E)带宽在4G/s左右,这就是我们每毫秒可以把4百万字节数据从内存调入到显卡中,这对于大部分的应用而言可能足够了,但是如果需要更高端的计算性能,恐怕只有等待显卡的插槽更新换代了。
应用
我有幸参加了CUDA技术的创始人之一David Kirk博士在清华进行的讲座。讲座中提到了CUDA从开始到现在不足两年的时间里的大量应用。实际上有些是令人比较失望的——在一般的状况下,CUDA的运行速度只达到了CPU的一百倍到一千倍左右,并没有达到那么夸张的地步——不过这依然足够改变人们的工作方式了。
- 神经网络模拟。有一个人建立了一个巨大的神经网络,用来模拟真实生物的神经活动。众所周知,每个神经细胞都可以当作是并行运行的,因此这个模型非常适用于CUDA。
- 股票分析软件。它是以复杂计算为基础,进行整个美国股市的实时分析的一个软件。由于股票之间的情况异常复杂,造成经济学上的公式无法准确预测时间稍微一点的大盘情况。然而,有了CUDA,我们就可以在几百毫秒之内计算出当前的全美的大盘走势,这通常将花费数分钟时间,等我们得到结果之后,它已经没用了。CUDA让股票分析软件从不可能成为了可能。
- 分子流体模拟。这是中科院物理所的一位老师做的。他就是把分子的范德化力(其模型相对复杂)考虑进去。他制作了一个包含几亿个分子水滴,然后进行 模拟。由于每个水滴之间的范德华力只在周围的范围内有效,因此可以把每个分子的受力状况看做是不相干的或弱相干的。这也很适于CUDA。
- 地震研究与模拟。地震研究方面的一个重要问题就是如何快速的处理地震数据。这让我想起了当时MRI刚被发明的时候,虽然有了实验数据,但是算不出结果来。动用了当时最先进的军用超级计算机才得到一张图像。现在的医学器械里,MRI是太常见的东西了。这说明将来我们有可能处理更多的地震数据,解开地震规律之谜。
展望
CUDA是一项以提高计算性能为目的的新兴技术,但是其影响将远远超出“计算”的范围。GPGPU是一个神奇的事物,因为如果处理得好的话,那么可以几千倍的打破摩尔定律,而跳跃到下一个时代。GPGPU的问题就在于编程的痛苦性太高,而 #p#page_title#e#CUDA就是为此目的而设计。就如同David Kirk所言,计算性能提高十倍会使现在的工具变得很方便,计算性能提高一百倍会使现在的软件更新换代。而计算性能提高一千倍,则会彻底改变人们的工作方式。曾经不可能的慢慢变为可能。我们期待着CUDA技术以及未来的新的GPGPU技术能够带领我们(程序员和用户)走向新的时代!