资源描述
,单击此处编辑母版标题样式,单击此处编辑母版文本样式,第二级,第三级,第四级,第五级,#,CUDA,基本介绍,基于,Nvidia GPU,的通用计算开发,GPU,的优势,强大的处理能力 GPU接近1Tflops/s,高带宽 140GB/s,低成本 Gflop/$和Gflops/w高于CPU,当前世界超级计算机五百强的入门门槛为12,Tflops/s,一个三节点,每节点4,GPU,的集群,总处理能力就超过12,Tflops/s,,如果使用GTX280只需10万元左右,使用专用的Tesla也只需20万左右,1.GPU,高性能计算,GPU,VS,CPU:,计算能力,8x double precision,ECC,L1,L2 Caches,1 TF Single Precision,4GB Memory,NVIDIA GPU,X86 CPU,GPU/CPU,架构比较,延迟与吞吐量,CPU:,通过大的缓存保证线程访问内存的低延迟,但内存带宽小,执行单元太少,数据吞吐量小,需要硬件机制保证缓存命中率和数据一致性,GPU:,高显存带宽和很强的处理能力提供了很大的数据吞吐量,缓存不检查数据一致性,直接访问显存延时可达数百乃至上千时钟周期,单核,CPU,已经走到了尽头,频率提高遇到了瓶颈 从p4时代至今主流处理器频率一直在2,GHz,-3,GHz,左右,架构上已无潜力可挖。超线程 多流水线 复杂的分支预测 大缓存等技术已经将性能发挥到了极致,但是通用计算中的指令级并行仍然偏低,上述技术占用了芯片上的绝大多数晶体管和面积,目的却只是让极少数的执行单元能够满负荷工作,GPU,能够更好的利用摩尔定律提供的晶体管,图形渲染过程高度并行,因此硬件也是高度并行的,少量的控制单元,大量的执行单元,显存被固化在了,PCB,上,拥有更好的,EMI,性能,因此运行频率高于内存 通过更大的位宽实现了高带宽,当前的单核并行计算产品,IBM Cell,应用主要见于,PS3,SUN Niarraga NPU,NV/ATI GPU,大规模应用,GPU,最为常见,受市场牵引发展最快,性价比最高,架构比较,硬件,CPU,GPU,FPGA,AES-128,解,密实测速度,(,GByte/s),0.119,(,Core2,E6700,中单核),1.78,(,FX9800GTX+),1.02,(互联网资料中单片,FPGA,最大值),开发难度,小,较小,大,增加功能,容易,容易,难,硬件升级,无需修改代码,无需修改代码,需要修改代码,与主控端通信,不需要,通过,PCI-E,,实际速度一般为3,G,左右,通过,API,实现,较简单,需要为,FPGA,编写额外的驱动程序,实现通信协议需要额外的硬件资源,性能/成本,高,低,高,片外存储器,内存,容量大,速度低,显存,容量较大,速度高,FPGA,板上内存,一般为,DDRII,速度低,开发周期,短,短,长,CPU GPU FPGA,实现比较,CPU GPU FPGA,实现比较,当前的,GPU,开发环境,Cg:,优秀的图形学开发环境,但不适合,GPU,通用计算开发,ATI stream:,硬件上已经有了基础,但只有低层次汇编能够使用所有资源。高层次抽象,Brook,本质上是基于上一代,GPU,的,缺乏良好的编程模型,OpenCL:,联合制定的标准,抽象层次较低,对硬件直接操作更多,代码需要根据不同硬件优化,CUDA:,目前最佳选择,未来的发展趋势,GPU通用计算进一步发展:更高版本的CUDA,O,penCL,新产品涌现:Nvidia和AMD的下一代产品,Intel的LarraBee,CPU+GPU产品:减少了CPU-GPU通信成本,但存储器带宽和功耗面积等可能将制约集成度。在较低端的应用中将有用武之地。,CUDA,的硬件架构适合通用计算,G8x,系,G9x,系,GT200,系列,标量机架构提高了处理效率,更加适合通用计算,增加了,shared memory,和同步机制,实现线程间通信,以通用的处理器矩阵为主,辅以专用图形单元,GTX280,性能,933,Gflops(MAD),单精度,116,Gflops,双精度(,MAD),512bit,位宽,ddr3,显存,提供了140,GB/s,的带宽,1,G,的显存,GT200,框图,TPC,3 SM,Instruction and constant cache,Texture,Load/,s,tore,SM,ROP,ROP,对,DRAM,进行访问,TEXTURE,机制,对,global,的,atomic,操作,微架构比较,执行流水线,工作在通用计算模式下的,GT200,SM,架构,DUAL-Issue,并发,每二周期可以发射,一次指令,FPU,和,SFU,指令延迟,是四周期,某些情况下可以让,FPU,和,SFU,并发执行,实现超标量,理论处理能力峰值没有计算,dual-issue,双精度浮点计算不能,dual-issue,CUDA,架构,GPU,硬件特点,硬件资源模块化,根据市场定位裁减,高度并行 存在,TPC SM,两层 每个,SM,又有8,SP,SM,内存在高速的,shared memory,和同步机制,原子操作有利于实现通用计算中的数据顺序一致性,shared memory Texture cache constant cache,等高速片内存储器有助于提高数据访问速度,节省带宽,如何选购硬件,目前(2008.12)只有,CUDA,能够完全发挥新一代,GPU,的全部计算能力。,Nvidia,的,G80,以上的,GPU,能够支持,CUDA。,GT200,系列不仅性能更强,而且具有很多实用的新特性,Tesla,专用流处理器拥有更大的显存和更高的核心频率,通过降低显存频率,屏蔽不需要的图形单元和改善散热获得了更好的稳定性,适合服务器或者集群使用,适合的应用,GPU,只有在计算高度数据并行任务时才能发挥作用。在这类任务中,需要处理大量的数据,数据的储存形式类似于规则的网格,而对这写数据的进行的处理则基本相同。这类数据并行问题的经典例子有:图像处理,物理模型模拟(如计算流体力学),工程和金融模拟与分析,搜索,排序。,在很多应用中取得了1-2个数量级的加速,不适合的应用,需要复杂数据结构的计算如树,相关矩阵,链表,空间细分结构等,则不适用于使用,GPU,进行计算。,串行和事务性处理较多的程序,并行规模很小的应用,如只有数个并行线程,需要,ms,量级实时性的程序,需要重新设计算法和数据结构或者打包处理,CUDA,执行模型,重点是将,CPU,做为终端,(,Host),,,而,GPU,做为服务器,(,Server),或协处理器,(,Coprocessor),,,或者设备(,Device,),,从而让,GPU,来运行一些能够被高度线程化的程序。,CUDA,的基本思想是尽量得开发线程级并行(,Thread Level Parallel),,这些线程能够在硬件中被动态的调度和执行。,CUDA,执行模型,调用核程序时,CPU,调用,API,将显卡端程序的二进,制代码传到,GPU,grid,运行在,SPA,上,block,运行在,SM,上,thread,运行在,SP,上,grid block thread,Kernel,不是一个完整的程序,而只是其中的一个关键并行计算步,Kernel,以一个网格(,Grid),的形式执行,每个网格由若干个线程块(,block),组成,每一个线程块又由最多512个线程(,thread),组成。,grid block thread,一个,grid,最多可以有65535*65535个,block,一个,block,总共最多可以有512个,thread,,在三个维度上的最大值分别为512,512和64,grid block thread,grid,之间通过,global memory,交换数据,block,之间不能相互通信,只能通过,global memory,共享数据,不要让多个,block,写同一区段内容(不保证数据一致性和顺序一致性),同一,block,内的,thread,可以通过,shared memory,和同步实现通信,block,间粗粒度并行,,block,内,thread,细粒度并行,warp,Warp,是硬件特性带来的概念,在,CUDA C,语言中是透明的(除vote函数),但应用中不能忽略,一个,warp,中有32个线程,这是因为,SM,中有8个,SP,,执行一条指令的延迟是4个周期,使用了流水线技术,一个,half warp,中有16个线程,这是因为执行单元的频率是其他单元的两倍,每两个周期才进行一次数据传输,SIMT,编程模型,SIMT,是对,SIMD,(,Single Instruction,Multiple Data,,,单指令多数据)的一种变形。,两者的区别在于:,SIMD,的向量宽度是显式的,固定的,数据必须打包成向量才能进行处理;而,SIMT,中,执行宽度则完全由硬件自动处理了。,(每个,block,中的,thread,数量不一定是32),而,SIMT,中的,warp,中的每个线程的寄存器都是私有的,它们只能通过,shared memory,来进行通信。,分支性能,与现代的微处理器不同,,Nvidia,的,SM,没有预测执行机制,-,没有分支预测单元,(,Branch Predicator),。,在需要分支时,只有当,warp,中所有的线程都计算出各自的分支的地址,并且完成取指以后,,warp,才能继续往下执行。,如果一个,warp,内需要执行,N,个分支,那么,SM,就需要把每一个分支的指令发射到每一个,SP,上,再由,SP,根据线程的逻辑决定需不需要执行。这是一个串行过程,此时,SIMT,完成分支的时间是多个分支时间之和。,存储器模型,Register,Local,shared,Global,Constant,Texture,Host memory,Pinned host memory,寄存器与,local memory,对每个线程来说,寄存器都是线程私有的,-,这与,CPU,中一样。如果寄存器被消耗完,数据将被存储在本地存储器,(,local memory),。,Local memory,对每个线程也是私有的,但是,local memory,中的数据是被保存在显存中,而不是片内的寄存器或者缓存中,速度很慢。线程的输入和中间输出变量将被保存在寄存器或者本地存储器中。,Shared memory,用于线程间通信的共享存储器。共享存储器是一块可以被同一,block,中的所有,thread,访问的可读写存储器。,访问共享存储器几乎和访问寄存器一样快,是实现线程间通信的延迟最小的方法。,共享存储器可以实现许多不同的功能,如用于保存共用的计数器,(,例如计算循环次数,),或者,block,的公用结果,(,例如计算,512,个数的平均值,并用于以后的计算,),。,constant memory,texture memory,利用,GPU,用于图形计算的专用单元发展而来的高速只读缓存,速度与命中率有关,不命中时将进行对显存的访问,常数存储器空间较小(只有64k),支持随机访问。从,host,端只写,从,device,端只读,纹理存储器尺寸则大得多,并且支持二维寻址。(一个数据的“上下左右”的数据都能被读入缓存)适合实现图像处理算法和查找表,全局存储器,使用的是普通的显存,无缓存,可读写,速度慢,整个网格中的任意线程都能读写全局存储器的任意位置,并且既可以从,CPU,访问,也可以从,CPU,访问。,各种存储器的延迟,register:1,周期,shared memory:1,周期(无,bank conflict)-16,周期(发生16路,bank conflict),texture memory:1(,命中)-数百周期(不命中),constant memory:1(,命中)-数百周期(不命中),global local memory:,数百周期,各存储器大小,每个,SM,中有64,K(GT200),或者32,K(G8x,G9x),寄存器,寄存器的最小单位是32,bit,的,register file,每个,SM,中有16,K shared memory,一共可以声明64,K,的,constant memory,,但每个,SM,的,cache,序列只有8,K,可以声明很大的,texture memory,,但是实际上的,texture cache,序列为每,SM 6-8K,使用存储器时可能出现的问题,致命问题:无法产生正确结果,多个,block,访问,global,同一块,以及,block,内,thread,间线程通信时的数据一致性问题,Texture,的工作模式设置错误,效率问题:大大增加访存延迟,Shared bank conflict,问题,Global,合并访问问题,Bank conflict,Shared memory,被分为了16个,bank,,单位是32-,bit,,相邻数据在不同,bank,中,对16余数相同的数据在同一,bank,Half warp,中的16个线程访问,shared memory,时最好一一对应,如果多个,thread,同时访问属于同一,bank,的数据将发生,bank conflict,16,个线程读同一数据时,,,会发生一次广播,只用一个,cycle,,没有,bank conflict,合并访问,访问显存时要遵守严格的合并访问规则,将,half warp,访问,global,的起始位置严格的对齐到16的整数倍,在,G8x,G9x,硬件上,thread,访问显存的位置必须逐一递增,GT200,有了很大的改进,对齐和次序比较灵活,好的合并访问可以将存储器访问次数减少十几倍,CUDA API,CUDA C,语言,由,Nvidia,的,CUDA,编译器,(,nvcc),编译,CUDA C,不是,C,语言,而是对,C,语言进行扩展形成的变种。,CUDA,对,C,的扩展:函数限定符,对函数有了限定符,用来规定函数是在,host,还是在,device,上执行,以及这个函数是从,host,调用还是从,device,调用。这些限定符是:,_,device_,,,_host_,和,_,global_,。,CUDA,对,C,的扩展:函数限定符,_,device_,函数在,device,端执行,并且也只能从,device,端调用,即作为,device,端的子函数来使用,_,global_,函数即,kernel,函数,它在设备上执行,但是要从,host,端调用,_,host_,函数在,host,端执行,也只能从,host,端调用,与一般的,C,函数相同,CUDA,对,C,的扩展:变量限定符,对变量类型的限定符,用来规定变量被存储在哪一种存储器上。,传统的在,CPU,上运行的程序中,编译器就能自动决定将变量存储在,CPU,的寄存器还是在计算机的内存中。,而在,CUDA,中,不仅要使用,host,端的内存,而且也要使用显卡上的显存和,GPU,上的几种寄存器和缓存。在,CUDA,编程模型中,一共抽象出来了多达,8,种不同的存储器!,CUDA,对,C,的扩展:变量限定符,_,device_,_device_,限定符声明的变量存在于,device,端,其他的变量限定符声明的变量虽然存在于不同的存储器里,但总体来说也都在,device,端。所以,_,device_,限定符可以与其他的限定符联用。当单独使用,_,device_,限定符修饰变量时,这个变量:,存在于,global memory,中;,变量生命周期与整个程序一样长;,可以被,grid,中所有的线程都可以访问,也可以从,host,端通过运行时库中的函数访问。,CUDA,对,C,的扩展:变量限定符,_,constant_,_constant_,限定符,可以与,_,device_,联用,即,_,device_ _constant_,,,此时等同于单独使用,_,constant_,。,使用,_,constant_,限定符修饰的变量:,存在于,constant memory,中,访问时速度一般比使用,global memory,略快;,变量生命周期与整个程序一样长;,可以被,grid,中所有的线程读,从,host,端通过运行时库中的函数写。,CUDA,对,C,的扩展:变量限定符,_,shared_,_shared_,限定符,可以与,_,device_,联用,即,_,device_ _shared_,,,此时等同于单独使用,_,shared_,。,使用,_,shared_,限定符修饰的变量:,存在于,block,中的,shared memory,中,;,变量生命周期与,block,相同,;,只有同一,block,内的,thread,才能访问。,CUDA对C的扩展:,kernel,执行参数,运算符,用来传递一些,kernel,执行参数,Grid的大小和维度,Block的大小和维度,外部声明的,shared memory,大小,stream,编号,CUDA,对,C,的扩展:内建变量,Dim3 ThreadIdx(,三维),Dim3 ThreadDim(,三维),Dim3 BlockIdx(,二维),Dim3 BlockDim(,三维),执行参数与内建变量的作用,各个,thread,和,block,之间的唯一不同就是,threadID,和,BlockID,通过内建变量控制各个线程处理的指令和数据,CPU,运行核函数时的执行参数确定,GPU,在,SPA,上分配多少个,block,,在,SM,上分配多少个,thread,CUDA API,CUDA API,需要,CUDA driver API,才能运行,新版本的,Nvidia,驱动已经包含了,CUDA driver API,CUDA runtime API,是,CUDA API,的可选组件,它是一种动态编译器,(,JIT),,,能够直接访问实际中的底层硬件架构。,CUDA API,功能,设备管理(,Device management,),上下文管理,(,Context management),存储器管理,(,Memory management),代码块管理,(,Code Module management),执行控制,(,Excution Control),纹理索引管理,(,Texture Reference management),与,OpenGL,和,Direct3D,的互操作,(,Interoperity with OpenGL and Direct3D),NVCC,编译器,生成三种不同的输出:,PTX,,,CUDA,二进制序列和标准,C,NVCC,编译器,PTX,PTX(Parallel Thread eXecution),作用类似于汇编,是为动态编译器,(,包含在标准的,Nvidia,驱动中,),设计的输入指令序列。这样,不同的显卡使用不同的机器语言,而动态编译器却可以运行相同的,PTX,。,这样做使,PTX,成为了一个稳定的接口,带来了很多好处:后向兼容性,更长的寿命,更好的可扩展性和更高的性能,但在一定程度上也限制了工程上的自由发挥。这种技术保证了兼容型,但也使新一代的产品必须拥有上代产品的所有能力,这样才能让今天的,PTX,代码在未来的系统上仍然可以运行。,NVCC,编译器,CUBIN,虽然,PTX,和,JIT,编译器提供了很高的性能,但也不是在所有的场合都适用。某些独立软件开发商倾向于牺牲性能,以获得更好的可确定性和可验证性。,JIT,编译器的输出随着目标硬件和一些其他因素会发生变化。对于需要能够确定的代码的独立软件开发商,(,比如很多财经软件开发商,),,它们可以将代码直接编译成,CUDA,二进制代码,这样就能避免,JIT,过程的不确定性。直接编译得到的,CUDA,二进制代码是与特定的硬件和驱动相关的。,NVCC,编译器,C,Nvcc,的输出还包括标准,C,。,由,nvcc,生成的,C,代码将被重定向到其他编译器进行编译,比如,ICC,,,GCC,或者其他合适的高性能编译器。,CUDA,中明确的表示了程序中的并行度没不仅在用于编写运行在,Nvidia GPU,上的代码时非常有效,而且为多核,CPU,生成高性能代码。在某些应用中,,CUDA,生成的代码比标准的,x86,编译器生成的代码的性能提高了,4,倍。,CUDA API,库函数,CUFFT GPU,进行傅立叶变换的函数库,提供了与广泛使用的,FFTW,库相似的接口。,CUBLAS(CUDA Basic Linear Algorithm Subprogrammes),库是一个基本的矩阵与向量的运算库,提供了与,BLAS,相似的接口,可以用于简单的矩阵计算,也可以作为基础构建更加复杂的函数包,如,LAPACK,等。,CUDPP(CUDA Data parallel primitives),库提供了很多基本的常用并行操作函数,如排序、搜索等,可以作为基本组件快速的搭建出并行计算程序。,如何编写,CUDA,程序,硬件实现不完全透明,需要掌握硬件实现的原理,并行度高,适合,CPU,的小规模并行算法不一定适用,需要重新设计算法或者参考在集群上使用的并行算法,如何编写,CUDA,程序?,确定适合,GPU,的算法,找出算法中的并行部分,根据需要使用正确的存储器,减少对GPU片外的显存的读取,提高计算密集度,编写调试,实现算法功能,验证结果的准确性,优化,提高执行单元利用率,隐藏访存延时,实现流操作,协调与,CPU,的操作,编写,CPU,调用接口,实现节点内多,GPU,并行和集群中多节点并行,优化原则:,active block,一个,SM,中可以有多个,block,等待处理,在一个,warp,需要访问存储器或者同步时,另外一个,warp,可以使用执行单元的资源,增加,active block,对提高,SM,利用率有好处,增加,active block,只是手段,不是最终的评价标准。最终目的是要隐藏延迟,优化原则:,active block,每个,SM,最多可以有768(,G8x,G9x),或者1024(,GT200),个,active thread,这些,active thread,最多可以属于8个,block,还有受到,SM,中,shared memory,和,register,的制约,最后的,active block,数量是由以上四个条件中的,“,短板,”,决定,优化原则:指令优化,选用计算复杂度较小的算法,处理字长为32,bit,并行度高,粗粒度并行多,细粒度并行有局部性,分支映射成固定运算,展开代码避免循环,在精度允许的前提下使用带有_前缀的快速算法,只在必要的部分使用双精度和64-,bit int,使用移位运算代替整数除法和求余,使用,vote,atomic,red,等,intrinsic,函数,实现算法,只在线程间通信前进行同步,优化原则:存储器访问优化,对显存的,I/O,成本很高,提高两次对显存访问之间的计算量,通过同时计算与访存隐藏延时,把适合的数据放入纹理和常数缓存等缓解带宽压力,提高读取速度,避免,bank conflict,,非合并访问或,cpu-gpu,数据传输 使用数组的结构体,而不是结构体数组,使用对齐,类型转换等手段实现合并访问,相关资源,CUDA toolkit,文件夹下的,doc,目录提供了文档,CUDA SDK,中提供了很多有益的例子,CUDA QQ,讨论群,开勇的,blog CSDN,darkstorm2111203,的,blog CSDN,
展开阅读全文