多CPU程序开发: OpenMP-MPI(机群)和CUDA(GPU)
CPU和GPU擅长和不擅长的方面
从它们执行运算的速度与效率的方面来探讨这个论题。
CPU和GPU都是具有运算能力的芯片,CPU更像“通才”——指令运算(执行)为重+ 数值运算,GPU更像“专才”——图形类数值计算为核心。在不同类型的运算方面的速度也就决定了它们的能力——“擅长和不擅长”。芯片的速度主要取决于三个方面:微架构,主频和IPC(每个时钟周期执行的指令数)。
1.微架构
从微架构上看,CPU和GPU看起来完全不是按照相同的设计思路设计的,当代CPU的微架构是按照兼顾“指令并行执行”和“数据并行运算”的思路而设计,就是要兼顾程序执行和数据运算的并行性、通用性以及它们的平衡性。CPU的微架构偏重于程序执行的效率,不会一味追求某种运算极致速度而牺牲程序执行的效率。
CPU微架构的设计是面向指令执行高效率而设计的,因而CPU是计算机中设计最复杂的芯片。和GPU相比,CPU核心的重复设计部分不多,这种复杂性不能仅以晶体管的多寡来衡量,这种复杂性来自于实现:如程序分支预测,推测执行,多重嵌套分支执行,并行执行时候的指令相关性和数据相关性,多核协同处理时候的数据一致性等等复杂逻辑。
GPU其实是由硬件实现的一组图形函数的集合,这些函数主要用于绘制各种图形所需要的运算。这些和像素,光影处理,3D 坐标变换等相关的运算由GPU硬件加速来实现。图形运算的特点是大量同类型数据的密集运算——如图形数据的矩阵运算,GPU的微架构就是面向适合于矩阵类型的数值计算而设计的,大量重复设计的计算单元,这类计算可以分成众多独立的数值计算——大量数值运算的线程,而且数据之间没有像程序执行的那种逻辑关联性。
GPU微架构复杂度不高,尽管晶体管的数量不少。从应用的角度看,如何运用好GPU的并行计算能力主要的工作是开发好它的驱动程序。GPU驱动程序的优劣很大程度左右了GPU实际性能的发挥。
因此从微架构上看,CPU擅长的是像操作系统、系统软件和通用应用程序这类拥有复杂指令调度、循环、分支、逻辑判断以及执行等的程序任务。它的并行优势是程序执行层面的,程序逻辑的复杂度也限定了程序执行的指令并行性,上百个并行程序执行的线程基本看不到。GPU擅长的是图形类的或者是非图形类的高度并行数值计算,GPU可以容纳上千个没有逻辑关系的数值计算线程,它的优势是无逻辑关系数据的并行计算。
2.主频
另外,GPU执行每个数值计算的速度并没有比CPU快,从目前主流CPU和GPU的主频就可以看出了,CPU的主频都超过了1GHz,2GHz,甚至3GHz,而GPU的主频最高还不到1GHz,主流的也就500~600MHz。要知道1GHz = 1000MHz。所以GPU在执行少量线程的数值计算时并不能超过CPU。
目前GPU数值计算的优势主要是浮点运算,它执行浮点运算快是靠大量并行,但是这种数值运算的并行性在面对程序的逻辑执行时毫无用处。
3.IPC(每个时钟周期执行的指令数)
这个方面,CPU和GPU无法比较,因为GPU大多数指令都是面向数值计算的,少量的控制指令也无法被操作系统和软件直接使用。如果比较数据指令的IPC,GPU显然要高过CPU,因为并行的原因。但是,如果比较控制指令的IPC,自然是CPU的要高的多。原因很简单,CPU着重的是指令执行的并行性。
另外,目前有些GPU也能够支持比较复杂的控制指令,比如条件转移、分支、循环和子程序调用等,但是GPU程序控制这方面的增加,和支持操作系统所需要的能力CPU相比还是天壤之别,而且指令执行的效率也无法和CPU相提并论。
最后总结一下:
CPU擅长的:操作系统,系统软件,应用程序,通用计算,系统控制等等;游戏中人工智能,物理模拟等等;3D建模-光线追踪渲染;虚拟化技术——抽象硬件,同时运行多个操作系统或者一个操作系统的多个副本等等。
GPU擅长的:图形类矩阵运算,非图形类并行数值计算,高端3D游戏。
综上所述,在一台均衡计算的计算机系统中,CPU和GPU还是各司其职,除了图形运算,GPU将来可能主要集中在高效率低成本的高性能并行数值计算,帮助CPU分担这种类型的计算,提高系统这方面的性能。而当前的典型应用还是高端3D游戏,一个高效的GPU配合一个高效的CPU,3D游戏的整体效率才能得到保证。“高端3D游戏只需要高端显卡”或者“高端3D游戏只需要CPU”都是无稽之谈。
OpenMP
OpenMP是由OpenMP Architecture Review Board牵头提出的,并已被广泛接受的,用于共享内存并行系统的多线程程序设计的一套指导性注释(Compiler Directive)。OpenMP支持的编程语言包括C语言、C++和Fortran;而支持OpenMP的编译器包括Sun
Compiler,GNU Compiler和Intel Compiler等。OpenMP提供了对并行算法的高层的抽象描述,程序员通过在源代码中加入专用的pragma来指明自己的意图,由此编译器可以自动将程序进行并行化,并在必要之处加入同步互斥以及通信。当选择忽略这些pragma,或者编译器不支持OpenMP时,程序又可退化为通常的程序(一般为串行),代码仍然可以正常运作,只是不能利用多线程来加速程序执行。
OpenMP提供的这种对于并行描述的高层抽象降低了并行编程的难度和复杂度,这样程序员可以把更多的精力投入到并行算法本身,而非其具体实现细节。对基于数据分集的多线程程序设计,OpenMP是一个很好的选择。同时,使用OpenMP也提供了更强的灵活性,可以较容易的适应不同的并行系统配置。线程粒度和负载平衡等是传统多线程程序设计中的难题,但在OpenMP中,OpenMP库从程序员手中接管了部分这两方面的工作。
但是,作为高层抽象,OpenMP并不适合需要复杂的线程间同步和互斥的场合。OpenMP的另一个缺点是不能在非共享内存系统(如计算机集群)上使用。在这样的系统上,MPI使用较多。
多执行绪的概念
OpenMP是作为共享存储标准而问世的。它是为在多处理机上编写并行程序而设计的一个应用编程接口。它包括一套编译指导语句和一个用来支持它的函数库。
目前双核、四核的 CPU 当道,而六核的CPU也已经面世多时,所以在多处理机上编写、运行并行程序会变得相当普遍。
对於一般单一执行绪(single thread)的程式,多核心的处理器并没有办法提升它的处理效能;不过对於多执行绪(multi thread)的程式,就可以透过不同的核心同时计算,来达到加速的目的了!简单的例子,以单执行绪的程式来说,一件事做一次要十秒的话,要做十次,都丢给同一颗核心做的话,自然就是
10 秒 * 10 次,也就是 100 秒了;但是以多执行绪的程式来说,它可以把这一件事,分给两颗核心各自做,每颗核心各做 5 次,所以所需要的时间就只需要 50 秒!
当然,多执行绪的程式实际上没这么简单。在工作的切割、结合上,也是要多花时间的,所以在现实中,即使最佳状况,双核心的效能也不会是 1 + 1 = 2 这样的理想化。除此之外,也不是所有工作都是可以切割的!很多工作是有关联性的,这样如果直接切割给不同的处理核心各自去平行运算,出来的结果是肯定有问题的。而且,多执行绪的程式在编写、维护上,也都比单一执行绪的程式复杂上不少。
不过,如果电脑本身是多处理器、多核心处理器,或是处理器拥有像 Intel Hyper-Threading Technology
这类的能在同一个时间处理多个执行绪的功能的话,那把各自独立的工作由单一执行绪改成多执行绪,在执行的效率上,大多还是会有增进的!
多执行绪的程式
写程式的时候该怎么去写多执行绪的程式呢?一般的方法,就是真的利用 thread 的控制,去实际在程式中去产生其他的 thread 来处理。像 POSIX Threads 这套 library,就是用来产生、控制执行绪的函式库。而像 Microsoft VisualStudio 2005 中,也有提供控制
thread 的功能。这种方法,大多就是产生多个 thread,而再由主要的 thread 把工作拆开,分给各 thread 去运算,最後再由主要的 thread 回收结果、整合。
但是,实际上要去控制 thread 是满麻烦的~在程式的编写上,也会复杂不少;而如果我们只是想要把一些简单的回圈平行化处理,用 thread library 来控制,实在有点杀鸡用牛刀的感觉。这时候,用 Open MP 就简单多了!OpenMP 是一种能透过高阶指令,很简单地将程式平行化、多执行绪化的
API;在最简单的情形,甚至可以只加一行指令,就可以将回圈内的程式平行化处理了!
OpenMP 的基本使用
要在Visual
C++ 2005 中使用OpenMP其实不难,只要将 Project 的Properties中C/C++里Language的OpenMP Support开启(参数为 /openmp),就可以让VC++2005 在编译时支持OpenMP 的语法了;而在编写使用OpenMP
的程序时,则需要先include OpenMP的头文件:omp.h。
而要将 for 回圈平行化处理,该怎么做呢?非常简单,只要在前面加上一行
#pragma omp parallel for
就够了!
也可以实际用一段简单的程序,来弄清楚它的运作方式。
#include <STDIO.H>
#include <STDLIB.H>
void Test(int n) {
for (int i = 0; i < 10000; ++i)
{
//do nothing, just waste time
}
printf("%d, ", n);
}
int main(int argc, char* argv[])
{
for (int i = 0; i < 10; ++i)
Test(i);
system("pause");
}
上面的程序,在 main() 是一个很简单的回圈,跑十次,每次都会调用Test()这个函数,并把是回圈的执行次数(i)传进Test() 并打印出来。想当然,它的结果会是:
0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
而如果想利用 OpenMP把 main() 里面的回圈平行化处理呢?只需要修改成下面的样子:
#include <omp.h>
#include <stdio.h>
#include <stdlib.h>
void Test (int n) {
for (int i = 0; i < 10000; ++i) {
//do nothing, just waste time
}
printf("%d, ", n);
}
int main(int argc, char* argv[]) {
#pragma omp parallel for
for (int i = 0; i < 10; ++i)
Test( i );
system("pause");
}
够简单吧?重头到尾,只加了两行!而执行后,可以发现结果也变了!
0, 5, 1, 6, 2, 7, 3, 8, 4, 9,
可以从结果很明显的发现,他没有照着0到9的顺序跑了!而上面的顺序怎么来的?其实很简单,OpenMP只是把回圈 0 - 9 共十个步骤,拆成 0 - 4, 5 - 9 两部份,丢给不同的执行绪去跑,所以数字才会出现这样交错性的输出~
而要怎么确定真的有跑多执行绪呢?如果本来有多处理器、多核心处理器或有 Hyper Thread 的话,一个单执行绪程序,最多只会把一颗核心的使用量吃完;像比如说在 Pentium 4 HT 上跑,单一执行绪的程序,在工作管理员中看到的 CPU 使用率最多就是
50%。而利用 OpenMP 把回圈进行平行化处理后,就可以在执行回圈时,把两颗核心的 CPU 都榨光了!也就是CPU 使用率是100%。
http://txl716.blog.163.com/blog/static/19353158200841792312627/
http://www.txrjy.com/baike/view.asp?OpenMP
MPI
1.Message
Passing Interface
三个英文单词首字母的简称。具有代表性的有Message Passing Interface ,Multi Point Interface ,Multi points injection等。
对MPI的定义是多种多样的,但不外乎下面三个方面,它们限定了MPI的内涵和外延: 1、MPI是一个库,而不是一门语言。许多人认为,MPI就是一种并行语言,这是不准确的。但是,按照并行语言的分类,可以把FORTRAN+MPI或C+MPI看作是一种在原来串行语言基础之上扩展后得到的,并行语言MPI库可以被FORTRAN77/C/Fortran90/C++调用,从语法上说,它遵守所有对库函数/过程的调用规则,和一般的函数/过程没有什么区别; 2、MPI是一种标准或规范的代表,而不特指某一个对它的具体实现,迄今为止,所有的并行计算机制造商都提供对MPI的支持,可以在网上免费得到MPI在不同并行计算机上的实现,一个正确的MPI程序可以不加修改地在所有的并行机上运行; 3、MPI是一种消息传递编程模型,并成为这种编程模型的代表。事实上,标准MPI虽然很庞大,但是它的最终目的是服务于进程间通信这一目标的; 解释来源于《高性能计算之并行编程技术——
MPI并行程序设计》都志辉 编著
4、MPI是多点接口(Multi Point Interface)的简称,是西门子公司开发的用于PLC之间通讯的保密的协议。MPI通讯是当通信速率要求不高、通信数据量不大时,可以采用的一种简单经济的通讯方式。MPI通信可使用PLC S7-200/300/400、操作面板TP/OP及上位机MPI/PROFIBUS通信卡,如CP5512/CP5611/CP5613等进行数据交换。MPI网络的通信速率为19.2Kbps~12Mbps,最多可以连接32个节点,最大通讯距离为50m,但是可能通过中断器来扩展长度。
解释来源于《西门子工业网络通信指南》(上册) 崔坚 主编
MPI(Message Passing Interface)是消息传递并行程序设计的标准之一,当前通用的是MPI1.1规范。正在制定的MPI2.0规范除支持消息传递外,还支持MPI的I/O规范和进程管理规范。MPI正成为并行程序设计事实上的工业标准。
MPI的实现包括MPICH、LAM、IBM MPL等多个版本,最常用和稳定的是MPICH,曙光天潮系列的MPI以MPICH为基础进行了定制和优化。
MPICH含三层结构,最上层是MPI的API,基本是点到点通信,和在点到点通信基础上构造的集群通信(Collective Communication);中间层是ADI层(Abstract
Device Interface),其中device可以简单地理解为某一种底层通信库,ADI就是对各种不同的底层通信库的不同接口的统一标准;底层是具体的底层通信库,例如工作站机群上的p4通信库、曙光1000上的NX库、曙光3000上的BCL通信库等。
MPICH的1.0.12版本以下都采用第一代ADI接口的实现方法,利用底层device提供的通信原语和有关服务函数实现所有的ADI接口,可以直接实现,也可以依靠一定的模板间接实现。自1.0.13版本开始,MPICH采用第二代ADI接口。
我们将MPICH移植到曙光3000高效通信库BCL(Basic Communication Library)上(简称MPI_BCL)。MPI_BCL的接口标准与MPICH版本1.1完全一致,满足MPI1.1标准。同时,也支持ch_p4的通信库,即利用TCP/IP通信机制。从网络硬件角度说,MPI_BCL针对系统网络,MPI_ch_p4针对高速以太网。
书名: MPI并行程序设计实例教程
作 者:张武生李建江 出版社: 清华大学出版社 出版时间:
2009 ISBN:
9787302186472 开本: 16 定价:
39.50 元
内容简介
《MPI并行程序设计实例教程》旨在通过示例全面介绍MP1并行程序开发库的使用方法、程序设计技巧等方面的内容,力争完整讨论MP1规范所定义的各种特征。主要也括MPI环境下开发并行程序常用的方法、模式、技巧等内容。在内容组织上力求全面综合地反映MPl-1和MPI-2规范。对MPI所定义的各种功能、特征分别给出可验证和测试其工作细节的示例程序
编辑推荐
◆书中内容侧重于以MPI库为基础开发并行应用程序,对MP规范定义的各项功能和特征在阐述其特点基础上均配以实例加以说明和印证。 ◆书中所附实例尽量采用独立的功能划分,其中的代码片段可直接用于并行应用程序开发 ◆在讲述基本原理的同时,注重对各项消息传递和管理操作的功能及局限性、适用性进行分析从而使熟读此书的读者能够编写出适合应用特点,易维护、高效率的并行程序。 ◆与《MPI并行程序设计实例教程》配套的电子教案可在清华大学出版社网站下载。
目录
第1章MPI并行环境及编程模型 1.1MPICH2环境及安装和测试 1.1.1编译及安装 1.1.2配置及验汪 1.1.3应用程序的编译、链接 1.1.4运行及调试 1.1.5MPD中的安全问题 1.2MPI环境编程模型 1.2.1并行系统介绍 1.2.2并行编程模式 1.2.3MPI程序工作模式 1.3MPI消息传递通信的基本概念 1.3.1消息 1.3.2缓冲区 1.3.3通信子 1.3.4进样号和l进程纰 1.3.5通价胁议 1.3.6隐形对象 第2章点到点通信 2.1阻糍通信 2.1.1标准通信模式 2.1.2缓冲通信模式 2.1.3就绪通信模式 2.1.4同步通信模式 2.1.5小结 2.2非阻塞通信 2.2.1通信结束测试 2.2.2非重复的非阻塞通信 2.2.3可醺复的非阻塞通信 2.2.4Probe和Cancel 2.3组合发送接收 2.3.1MPl_Send,MPI_RecvoMPl_Sendreev 2.3.2MPI_Bsend←→MPl_Sendrecv 2.3.3MPI_Rsend←→MPI_Sendrecv 2.3.4MPl_Ssend←→MPl_Sendrecv 2.3.5MPl_lsend←→MP1一Sendrecv 2.3.6MPl_Ibsend←→MPI_Sendrecv 2.3.7MPI_Irsend←→MPI_Sendrecv 2.3.8MPl_Issend,MPI_Irecv←→MPI_Sendrecv 2.3.9MPISend_init←→MPl_Sendrecv 2.3.10MPI一Bsendjinit←→MPl_Sendrecv 2.3.11MPI_Rsend_init←→MPI_Sendrecv 2.3.12MPl_Ssend_init,MPl_Recv_init←→MPl_Sendrecv 2.4点到点通信总结 2.4.1关于预防死锁 2.4.2关于阻塞与非阻塞、同步与异步 2.4.3关于操作的执行顺序及“公平性” 第3章组与通信子 3.1简介 3.2组管理API 3.2.1组的构建及取消 3.2.2访问组的相关信息和属性 3.3组问通信 3.3.1创建与取消 3.3.2访问通信子信息 3.4组间通信 3.4.1访问函数 3.4.2构造和取消函数 3.5属性 3.5.1创建及释放属性操作 3.5.2访问属性操作 3.5.3设置及删除属性操作 3.5.4命名通信子对象 3.6错误处理 3.7组及通信子的小结 第4章集合通信 4.11←→N 4.1.1MPI_Bcast 4.1.2MPI_Scatter/MPI_Scatterv 4.2N←→1 4.2.1MPl_Gather/MPI_Gatherv 4.2.2MPI_Reduce 4.3N←→N 4.3.1MPI_Allgather/MPI_Allgatherv. 4.3.2MPI_Allreduce 4.3.3MPl_Reducescatter 4.3.4MPI_Alltoall/MPIAlltoallv/MPI_Alltoallw 4.3.5MPI_Scan/MPI_Exscan 4.4同步操作--MPI_Barrier 第5章数据类型 5.1类型图 5.2与数据类型相关的API函数 5.2.1创建 5.2.2访问 5.2.3注册与取消 5.3数据类型在通信函数缓冲区的构成 5.4数据类型的属性 5.4.1属性创建与释放 5.4.2属性操作 5.4.3复制数据类型 5.4.4类型属性举例 5.4.5数据类型命名 5.5数据类型的析构 5.5.1获取创建数据类型MPI函数所使用参数数量信息 5.5.2获取创建数据类型MPI函数所使用实际参数信息 5.5.3示例 5.6打包/解包 第6章进程拓扑 第7章动态进程管理 第8章单向通信/远端内存访问 第9章并行I/O 第10章MPI与外部环境的信息交互 第11章MPE 参考文献
MPI并行程序设计
http://wenku.baidu.com/view/3d1a6df80242a8956bece43c.html
CUDA
CUDA(Compute Unified Device Architecture),显卡厂商NVidia推出的运算平台。 CUDA™是一种由NVIDIA推出的通用并行计算架构,该架构使GPU能够解决复杂的计算问题。它包含了CUDA指令集架构(ISA)以及GPU内部的并行计算引擎。开发人员现在可以使用C语言来为CUDA™架构编写程序,C语言是应用最广泛的一种高级编程语言。所编写出的程序于是就可以在支持CUDA™的处理器上以超高性能运行。将来还会支持其它语言,包括FORTRAN以及C++。
简介 计算行业正在从只使用CPU的“*处理”向CPU与GPU并用的“协同处理”发展。为打造这一全新的计算典范,NVIDIA®(英伟达™)发明了CUDA(Compute
Unified Device Architecturem,统一计算设备架构)这一编程模型,是想在应用程序中充分利用CPU和GPU各自的优点。现在,该架构现已应用于GeForce®(精视™)、ION™(翼扬™)、Quadro以及Tesla GPU(图形处理器)上,对应用程序开发人员来说,这是一个巨大的市场。
在消费级市场上,几乎每一款重要的消费级视频应用程序都已经使用CUDA加速或很快将会利用CUDA来加速,其中不乏Elemental Technologies公司、MotionDSP公司以及LoiLo公司的产品。
在科研界,CUDA一直受到热捧。例如,CUDA现已能够对AMBER进行加速。AMBER是一款分子动力学模拟程序,全世界在学术界与制药企业中有超过60,000名研究人员使用该程序来加速新药的探索工作。
在金融市场,Numerix以及CompatibL针对一款全新的对手风险应用程序发布了CUDA支持并取得了18倍速度提升。Numerix为近400家金融机构所广泛使用。
CUDA的广泛应用造就了GPU计算专用Tesla GPU的崛起。全球财富五百强企业现在已经安装了700多个GPU集群,这些企业涉及各个领域,例如能源领域的斯伦贝谢与雪佛龙以及银行业的法国巴黎银行。
随着微软Windows
7与苹果Snow Leopard操作系统的问世,GPU计算必将成为主流。在这些全新的操作系统中,GPU将不仅仅是图形处理器,它还将成为所有应用程序均可使用的通用并行处理器。
发展历程
随着显卡的发展,GPU越来越强大,而且GPU为显示图像做了优化。在计算上已经超越了通用的CPU。如此强大的芯片如果只是作为显卡就太浪费了,因此NVidia推出CUDA,让显卡可以用于图像计算以外的目的。
目前只有G80、G92、G94、G96、GT200、GF100平台(即Geforce 8~Gecorce GTX480)的NVidia显卡才能使用CUDA,工具集的核心是一个C语言编译器。G80中拥有128个单独的ALU,因此非常适合并行计算,而且数值计算的速度远远优于CPU。
CUDA的SDK中的编译器和开发平台支持Windows、Linux系统,可以与Visual Studio2005集成在一起。
Geforce8CUDA(Compute Unified Device Architecture)是一个新的基础架构,这个架构可以使用GPU来解决商业、工业以及科学方面的复杂计算问题。它是一个完整的GPGPU解决方案,提供了硬件的直接访问接口,而不必像传统方式一样必须依赖图形API接口来实现GPU的访问。在架构上采用了一种全新的计算体系结构来使用GPU提供的硬件资源,从而给大规模的数据计算应用提供了一种比CPU更加强大的计算能力。CUDA采用C语言作为编程语言提供大量的高性能计算指令开发能力,使开发者能够在GPU的强大计算能力的基础上建立起一种效率更高的密集数据计算解决方案。
从CUDA体系结构的组成来说,包含了三个部分:开发库、运行期环境和驱动(表2)。
开发库是基于CUDA技术所提供的应用开发库。目前CUDA的1.1版提供了两个标准的数学运算库——CUFFT(离散快速傅立叶变换)和CUBLAS(离散基本线性计算)的实现。这两个数学运算库所解决的是典型的大规模的并行计算问题,也是在密集数据计算中非常常见的计算类型。开发人员在开发库的基础上可以快速、方便的建立起自己的计算应用。此外,开发人员也可以在CUDA的技术基础上实现出更多的开发库。
运行期环境提供了应用开发接口和运行期组件,包括基本数据类型的定义和各类计算、类型转换、内存管理、设备访问和执行调度等函数。基于CUDA开发的程序代码在实际执行中分为两种,一种是运行在CPU上的宿主代码(Host
Code),一种是运行在GPU上的设备代码(Device Code)。不同类型的代码由于其运行的物理位置不同,能够访问到的资源不同,因此对应的运行期组件也分为公共组件、宿主组件和设备组件三个部分,基本上囊括了所有在GPGPU开发中所需要的功能和能够使用到的资源接口,开发人员可以通过运行期环境的编程接口实现各种类型的计算。
由于目前存在着多种GPU版本的NVidia显卡,不同版本的GPU之间都有不同的差异,因此驱动部分基本上可以理解为是CUDA-enable的GPU的设备抽象层,提供硬件设备的抽象访问接口。CUDA提供运行期环境也是通过这一层来实现各种功能的。目前基于CUDA开发的应用必须有NVIDIA CUDA-enable的硬件支持,NVidia公司GPU运算事业部总经理Andy
Keane在一次活动中表示:一个充满生命力的技术平台应该是开放的,CUDA未来也会向这个方向发展。由于CUDA的体系结构中有硬件抽象层的存在,因此今后也有可能发展成为一个通用的GPGPU标准接口,兼容不同厂商的GPU产品
CUDA™
工具包
是一种针对支持CUDA功能的GPU(图形处理器)的C语言开发环境。CUDA开发环境包括:
·
nvcc C语言编译器
· 适用于GPU(图形处理器)的CUDA FFT和BLAS库
·
分析器
· 适用于GPU(图形处理器)的gdb调试器(在2008年3月推出alpha版)
· CUDA运行时(CUDA runtime)驱动程序(目前在标准的NVIDIA GPU驱动中也提供)
CUDA编程手册
CUDA开发者软件开发包(SDK)提供了一些范例(附有源代码),以帮助使用者开始CUDA编程。这些范例包括:
· 并行双调排序
· 矩阵乘法
· 矩阵转置
· 利用计时器进行性能评价
· 并行大数组的前缀和(扫描)
· 图像卷积
· 使用Haar小波的一维DWT
· OpenGL和Direct3D图形互操作示例
· CUDA BLAS和FFT库的使用示例
· CPU-GPU C—和C++—代码集成
· 二项式期权定价模型
· Monte-Carlo期权定价模型
· 并行Mersenne Twister(随机数生成)
· 并行直方图
· 图像去噪
· Sobel边缘检测滤波器
· MathWorks MATLAB®
新的基于1.1版CUDA的SDK 范例现在也已经发布了。
技术功能
· 在GPU(图形处理器)上提供标准C编程语言
· 为在支持CUDA的NVIDIA GPU(图形处理器)上进行并行计算而提供了统一的软硬件解决方案
· CUDA兼容的GPU(图形处理器)包括很多:从低功耗的笔记本上用的GPU到高性能的,多GPU的系统。
· 支持CUDA的GPU(图形处理器)支持并行数据缓存和线程执行管理器
· 标准FFT(快速傅立叶变换)和BLAS(基本线性代数子程序)数值程序库
· 针对计算的专用CUDA驱动
· 经过优化的,从*处理器(CPU)到支持CUDA的GPU(图形处理器)的直接上传、下载通道
· CUDA驱动可与OpenGL和DirectX图形驱动程序实现互操作
· 支持Linux 32位/64位以及Windows XP 32位/64位 操作系统
· 为了研究以及开发语言的目的,CUDA提供对驱动程序的直接访问,以及汇编语言级的访问
其他信息
NVIDIA进军高性能计算领域,推出了Tesla&CUDA高性能计算系列解决方案,CUDA技术,一种基于NVIDIA图形处理器(GPU)上全新的并行计算体系架构,让科学家、工程师和其他专业技术人员能够解决以前无法解决的问题,作为一个专用高性能GPU计算解决方案,NVIDIA把超级计算能够带给任何工作站或服务器,以及标准、基于CPU的服务器集群
CUDA是用于GPU计算的开发环境,它是一个全新的软硬件架构,可以将GPU视为一个并行数据计算的设备,对所进行的计算进行分配和管理。在CUDA的架构中,这些计算不再像过去所谓的GPGPU架构那样必须将计算映射到图形API(OpenGL和Direct 3D)中,因此对于开发者来说,CUDA的开发门槛大大降低了。CUDA的GPU编程语言基于标准的C语言,因此任何有C语言基础的用户都很容易地开发CUDA的应用程序。
由于GPU的特点是处理密集型数据和并行数据计算,因此CUDA非常适合需要大规模并行计算的领域。目前CUDA除了可以用C语言开发,也已经提供FORTRAN的应用接口,未来可以预计CUDA会支持C++、Java、Python等各类语言。可广泛的应用在图形动画、科学计算、地质、生物、物理模拟等领域。
2008年NVIDIA推出CUDA SDK2.0版本,大幅提升了CUDA的使用范围。使得CUDA技术愈发成熟
目前
支持CUDA的GPU销量已逾1亿,数以千计的软件开发人员正在使用免费的CUDA软件开发工具来解决各种专业以及家用应用程序中的问题。这些应用程序从视频与音频处理和物理效果模拟到石油天然气勘探、产品设计、医学成像以及科学研究,涵盖了各个领域。目前市面上已经部署了超过一亿颗支持CUDA的GPU,数以千计的软件开发人员正在使用免费的CUDA软件工具来为各种应用程序加速。
CUDA 的核心有三个重要抽象概念: 线程组层次结构、共享存储器、屏蔽同步( barrier
synchronization),可轻松将其作为C 语言的最小扩展级公开给程序员。
CUDA 软件堆栈由几层组成,一个硬件驱动程序,一个应用程序编程接口(API)
和它的Runtime,还有二个高级的通用数学库,CUFFT 和CUBLAS。硬件被设计成支持轻
量级的驱动和Runtime 层面,因而提高性能。
所支持的OS(operating system)
CUDA目前支持linux和Windows操作系统。进行CUDA开发需要依次安装驱动、toolkit、SDK三个软件。在安装目录/C/src目录下有很多的例程可以进行学习。
- 扩展阅读:
-
-
英伟摩达(NVIDIA摩机社区):http://www.nvmod.cn
-
《大规模并行处理器编程实战》(英伟达官方网站推荐书籍)
-
《CUDA范例精解》(英伟达官方网站推荐书籍)
-
NVIDIA CUDA技术亮点何在
作为图形芯片领域的领头羊, NVIDIA(英伟达)认为GPU较CPU具有更强的浮点运算能力以及更大的带宽等诸多优势,甚至连晶体管数量目前都是GPU略胜一筹,未来GPU将越来越多地取代CPU的数据处理职能。因此,英伟达在07年就提出了独特的GPGPU(通用图形处理器)概念。目前 NVIDIA(英伟达)新一代GPU都采用了统一渲染架构,这种架构相比以往使GPU的运算单元变得通用,并可以根据图形渲染处理的负载灵活地改变运算单元的任务。这种架构集成了多个支持顶点坐标计算及三角形着色等多级处理的运算单元,各运算单元的任务可以根据各级处理的负载进行调整。新架构的出现也使得在以浮点运算为中心的通用处理中使用GPU成为可能。
在这种趋势下, NVIDIA(英伟达)定制了一个解决方案,被称作Compute Unified Device Architecture,简称CUDA。这也就是今天我们介绍的主角!
CUDA的编译
CUDA的本质是NVIDIA为自家的GPU编写了一套编译器NVCC极其相关的库文件。CUDA的应用程序扩展名可以选择是.cu,而不是.cpp等。NVCC是一个预处理器和编译器的混合体。当遇到CUDA代码的时候,自动编译为GPU执行的代码,也就是生成调用CUDA Driver的代码。如果碰到Host C++代码,则调用平台自己的C++编译器进行编译,比如Visual Studio C++自己的Microsoft C++ Compiler。然后调用Linker把编译好的模块组合在一起,和CUDA库与标准CC++库链接成为最终的CUDA
Application。由此可见,NVCC模仿了类似于GCC一样的通用编译器的工作原理(GCC编译CC++代码本质上就是调用cc和g++)。整个CUDA平台是通过运用显卡内的流处理器进行数学运算,并通过GPU内部的缓存共享数据,流处理器之间甚至可以互相通信,同时对数据的存储也不再约束于以GPU的纹理方式,存取更加灵活,可以充分利用统一架构的流输出(stream out)特性,大大提高应用效率。
CUDA技术特色
CUDA的运算
目前的CUDA所用的运算方法是分开的,一部分由CPU负责,而另一部分通过CUDA编译器使用GPU进行运算。在CUDA的架构下,一个程序分为两个部份:host 端和device 端。Host 端是指在CPU 上执行的部份,而device 端则是在显示芯片上执行的部份。Device端的程序又称为 “kernel”。通常host端程序会将数据准备好后,复制到显卡的内存中,再由显示芯片执行device端程序,完成后再由host端程序将结果从显卡的内存中取回。
由于显示芯片大量并行计算的特性,它处理一些问题的方式,和一般CPU是不同的。比如在内存存取latency 的问题上,CPU 通常使用cache 来减少存取主内存的次数,以避免内存latency 影响到执行效率,而显示芯片则多半没有cache(或很小),而利用并行化执行的方式来隐藏内存的latency(即,当第一个 thread 需要等待内存读取结果时,则开始执行第二个thread,依此类推),效率提高不少。正如 NVIDIA(英伟达)公司Tesla GPU计算事业部高级产品经理Sumit Gupta先生曾经推过一个形象的例子,CPU的顺序指令执行操作好比是一间办公室里的多个职员,如果每人需要将杯子里的水倒入同一个桶内时,他们需要排成长队按顺序进行。而对于GPU来说,这些职员无需排队,只要同时走到桶前将水倒入即可。所以,最适合利用CUDA处理的问题,是可以大量并行化的问题,才能有效隐藏内存的latency,并有效利用显示芯片上的大量执行单元。使用CUDA
时,同时有上千个thread在执行是很正常的。因此,如果不能大量并行化的问题,使用CUDA就没办法达到最好的效率了。
GPU并行计算过程
CPU存取显卡内存时只能透过PCI Express 接口,因此速度较慢(PCI Express x16 的理论带宽是双向各4GB/s),因此不能过多进行这类动作,以免降低效率。在CUDA架构下,显示芯片执行时的最小单位是thread。数个thread 可以组成一个block。一个block 中的thread 能存取同一块共享的内存,而且可以快速进行同步的动作。每一个block 所能包含的thread 数目是有限的,不过执行相同程序的block,可以组成grid。不同block中的thread无法存取同一个共享的内存,因此无法直接互通或进行同步。因此,不同block中的thread能合作的程度是比较低的。不过,利用这个模式,可以让程序不用担心显示芯片实际上能同时执行的thread数目限制。例如,一个具有很少量执行单元的显示芯片,可能会把各个block中的thread顺序执行,而非同时执行。不同的grid则可以执行不同的程序。
在目前支持CUDA的GPU中,其流处理器个数是不能和CPU现在拥有的内核数量作类比的。CPU的每一个核心都是一个完整的独立处理架构,而GPU中的每个流处理器并不完全是这样,而是以子组合方式运作,比如每8个流处理器组成一个Stream Multiprocessors (SM),其中分为四个流处理器又分为1小组,也可以看成是有两组4D的SIMD处理器。需要说明的是,若用户拥有超过两张或以上支持CUDA的显卡,驱动程序将通过PCIe总线自动分配工作负载,进一步提升效能。
当然CUDA也有其弱势的地方,并不是所有的事情CUDA都能够很好地解决,比如像操作系统这样复杂的指令和纷繁的分支循环而又用很少的线程来处理,这显然就不是CUDA的强项了。高度并行的计算是CUDA的技术特性之一。
那些GPU支持CUDA?
在推出GeForce GTX 200系列前,CUDA短短两年时间就已经发展了四个版本:
不同CUDA版本对比
目前,NVIDIA(英伟达)推出的GPU中,G80系列支持CUDA 1.0,而之后推出的G84、G86、G92、G94和G96 则支持CUDA 1.1。
GeForce显卡规格对比
CUDA 2.0—随GeForce GTX 200登场
而NVIDIA(英伟达)在6月17日GeForce GTX 200系列发布之时也推出了CUDA 2.0,加入双精度运算支持,为应用提供更准确的运算结果,而这项技术源自于多重处理器的专用单元。
多重处理器的专用单元框架
每一个多重处理器都包含了8个主要的FMAD处理器和8和MUL处理器来实现一些特殊功能的计算等。这样,一个64位的FMAD处理器就产生了。但是这样的处理器对于64位的计算能力相当低下,8X的低速FMAD和16X的低速FMUL都是导致计算能力低下的原因。这个支持64位也意味着可以以它为模板为将来的更高级和新一代的GPU发展提供代码或者应用程序的支持,从而得到更好的甚至超过一个以上的64位处理器。每一个多重处理器都具有两个流处理线,这样就不必依赖周期而同时处理两个信号。
引入双精度运算能力,可以在一定程度上增强GT200在科学计算领域的适用性.尽管在实际的相关领域中其实有部分甚至只需要16位精度就足够了,但GTX200核心的每一个SM都包括了一个双精度64Bit浮点运算单元,所以每个周期GT200能达成1MAD*30SM=30MAD,在1.5GHz的shader频率下可以达到90 GFLOPS(MAD)的双精度浮点性能, NVIDIA(英伟达)对其称之为可以与8核Xeon处理器(我想应该是指45nm Hypertown内核Xeon E5440 2.83GHz)的水平。不过需要注意的是,Xeon每个内核的浮点单元组合是每两个周期完成一个ADDPD或者一个周期完成一个MULPD,在双精度浮点峰值性能上"含金量"方面似乎要比GT200每个SM单周期MAD高一些。
NVIDIA(英伟达)的对手AMD在RV670上实现了硬件(非模拟)的FP64支持,双精度MAD性能为单精度MAD的1/5,GT200架构的双精度浮点支持应该是 NVIDIA(英伟达)迈向双精度浮点加速器的第一步,未来的架构很可能会把浮点双精度的性能做到单精度的1/2水平,这将是非常可观的。
CUDA将成为又一个标准API接口
选择CUDA的理由
目前CUDA已经应用在很多领域,包括在通用计算中的一些GPU加速,游戏中的物理模拟等等,而在科学计算中,CUDA可发挥的功效就更大了。比如有限元的计算、神经元的研究计算、地质分析等等科学研究的领域;当然目前GPU计算的应用还是处于一个早期的阶段,大部分CUDA应用都是专业人员和相关的程序员在开发,随着CUDA的广泛推行,以后会有实际的基于CUDA的程序,更多的程序员能够加入进来,并且开发一些可以给大家日常应用带来好处的程序,只要有支持CUDA的GPU就能够利用到GPU计算的好处。
提高多GPU编程与执行效率 CUDA 4.0初探
CUDA 4.0提高多GPU效率
● CUDA带给GPU行业无限可能
2007年可以说是GPU发展史上翻天覆地的一年,在这一年微软推出了DirectX 10 API标准,将传统的Pixel Shader(顶点着色器)、Vertex Shader(像素着色器)和Geometry Shader(几何着色器),三种硬件逻辑被整合为一个全功能的统一着色器Shader。
这种API发展思路背后是微软和NVIDIA、AMD对于整个GPU发展历程的思考与转型。它标志着微软开始支持GPU走向更强的可编程性,也标志着Intel等传统CPU制造厂商在未来几年将要面对GPU的强硬挑战,越来越多的高性能计算机和超级计算机已经开始以GPU作为其运算能力提升的重要配件。
天河一号-A所采用的NVIDIA Tesla GPU
2007年同样是NVIDIA值得回忆的一年,NVIDIA公司在这一年正式推出了CUDA整套方案,它是一个完整的通用计算产品。CUDA是Compute Unified Device Architecture(统一计算架构)的简称,是建立在GPU基础之上的通用计算开发平台,它是一个全新的软硬件架构,可以将GPU视为一个并行数据计算的设备,对所进行的计算进行分配和管理。
NVIDIA提出的CUDA通用计算方案
简单分析可知,CUDA是一种以C语言为基础的平台,主要是利用显卡强大的浮点运算能力来完成以往需要CPU才可以完成的任务。这种整套方案的提出意味着程序员再也不用去钻研繁杂的底层汇编程序,而是在C语言的基础上稍加学习就能掌握CUDA并通过它来调用GPU强大的浮点运算能力。
CUDA 4.0的3个显著提升
这一版本的CUDA大幅度降低了编程难度,同时提升了GPU的编程和执行效率。CUDA 4.0主要的功能能够在Fermi架构的最新GPU上被发挥出来,同时它可以让G80、G92、GT200架构的GPU也拥有编程方式上的飞跃。
GPU统一虚拟寻址
● GPU统一虚拟寻址
在2011年2月28日,NVIDIA发布了最新版本的CUDA工具包——CUDA 4.0。借助该工具包,开发人员能够开发出在GPU上运行的并行应用程序。本次NVIDIA历经两年时间发布了CUDA 4.0版本,这一版本为我们带来了3个核心的编程与执行方式提升,它们分别是:
1、统一的虚拟寻址;
2、更直接的GPU间通信;
3、增强型C++模板库。
这3个关键性提升让更多开发人员能够利用GPU计算,它们也成为CUDA 4.0的核心提升之处。接下来我们通过NVIDIA官方公布的资料来简单分析CUDA 4.0的不同之处。
多个GPU及其显存可以被视为一体
首先提出的是“GPU统一虚拟寻址”概念,我们第一次见到这一概念在Fermi架构发布的报道中,Fermi架构带领GPU全面走向高性能计算的重要表现就在于存储体系的结构完善和GPU统一的虚拟寻址,结构部分中关村在线显卡频道之前进行了大量分析,细心的读者肯定收藏了我们的技术分析类文章。
Fermi的发布彻底统一了GPU寻址空间,将不同的寻址简化为一种指令,这在以前的的GPU中是不敢想象的,内存地址取决于存储位置:最低位是本地,然后是共享,剩下的是全局。这种统一寻址空间也是支持C++的必需前提。
本次CUDA 4.0版本的发布可以让多个GPU以及CPU统一调用GPU显存以及CPU内存,并将处理器(CPU+GPU)和存储器(内存+显存)视为统一整体。在最大显存为6GB的Tesla产品中,多CPU和多GPU融合之后可以为整个系统带来大容量存储设备并且进行统一寻址。
GPU通信和C++模板库
● GPU通信和C++模板库
多GPU通信在以前的CUDA版本中代价很大,只有专业的并行编程环境才能驱动多款GPU在同一系统内执行一个任务,而目前桌面级应用中,如果用户的多块显卡同时存在于系统中,一个CUDA加速程序往往只能调用其中一个GPU核心。
从DirectX 10到DirectX 11的多线程变化
虽然我们看到GPU在图形操作时可以有SLI速力或者CF交火能力,也有DirectX 提出的多线程渲染技术,但是高并行度的GPU通用计算领域在PC桌面级应用中反倒不能实现多款GPU联合加速。
旧版的GPU Direct 1.0主要用于应用程序在网络间通信,新版的GPU Direct 2.0则转入节点内通信,支持P2P内存访问、传输和同步,代码更少,编程效率更高。在此之前,同一节点内的不同GPU互相访问,需要绕道系统内存并进行两次拷贝。就不用理会系统内存了,不同GPU可以直接进行传输,只需要一个统一的存储体系协议NVIDIA就搞定了整个问题。
说到GPU支持C++编程大家一定不会陌生,在Fermi架构发布之时,C++模板库模板库就已经被NVIDIA不断升级。Fermi是首款支持第二代PTX指令的GPU架构,我们知道PTX 2.0使得GPU具备更强的可编程性、更精确和提供更高的性能。
Thrust C++模板化算法与数据结构
通过上图可知,Thrust C++模板化算法与数据结构提供了强大的开源C++并行算法和数据结构。类似C++ STL标准模板库;可在编译时自动选择最快的代码路径,在多核心CPU与GPU之间分配工作。
C/C++语言中所有变量和函数都是通过指针才能确定对象,这样存在编译时分离的寻址空间无法确定指针的位置而导致无法支持C/C++语言。PTX 2.0最为突出的地方在于它提供的统一寻址空间的意义,将GPU当成“共享地址空间”的并行计算机。大量的算法是基于共享地址空间平台的,这样能够显著推动GPU并行计算的发展。
CUDA 4.0引领行业如何发展
● CUDA 4.0引领行业如何发展
2011年2月28日,NVIDIA官方发布了CUDA 4.0以及全新计算开发包的各项特性,而3月5日NVIDIA正式发布了GPU通用计算开发包的CUDA 4.0 RC候选版,并提供给开发人员下载使用。
NVIDIA对自己的定位发生变化
从官方公布的资料看来,NVIDIA的确是早有打算并雄心勃勃进入并行计算市场,目前NVIDIA拥有了从Tegra到Tesla的整套芯片产品线。而这条产品线从节能高效到高性能计算全面涵盖,这的确是一家处于产业链上游的“超级”计算芯片公司。
CUDA从发布开始,到目前已经到了4.0版,从NVIDIA提出CUDA这个概念,已经有将近四年的时间,在最近一年时间CUDA发展迅速,主要是Fermi架构推出之后GPU可编程性急剧提升,GPU和CPU的差距已经越来越近,两者关系也越来越紧密。
CUDA 4个版本发展历程
上图描述了NVIDIA CUDA发布以来,从1.0版本官方大力宣传和爱好者尝试,到2.0版专用领域开始应用CUDA进行编程开发,3.0版本已经引来整个行业的关注,大量软件开始基于CUDA进行基于GPU的加速开发,到今天推出4.0版本继续降低开发难度提升开发效率。
除了上述叙述之外,我们通过资料得到CUDA 4.0架构版本还包含大量其它特性与功能,其中包括:
1、MPI与CUDA应用程序相结合——当应用程序发出MPI收发调用指令时,例如OpenMPI等改编的MPI软件可通过Infiniband与显卡显存自动收发数据。
2、GPU多线程共享——多个CPU主线程能够在一颗GPU上共享运行环境,从而使多线程应用程序共享一颗GPU变得更加轻松。
3、单CPU线程共享多GPU——一个CPU主线程可以访问系统内的所有GPU。 开发人员能够轻而易举地协调多颗GPU上的工作负荷,满足应用程序中“halo”交换等任务的需要。
4、全新的NPP图像与计算机视觉库——其中大量图像变换操作让开发人员能够快速开发出成像以及计算机视觉应用程序。
5、全新、改良的功能
Visual Profiler中的自动性能分析功能
Cuda-gdb中的新特性以及新增了对MacOS的支持
新增了对C++特性的支持,这些特性包括新建/删除以及虚拟等功能
全新的GPU二进制反汇编程序
3大核心提升能否带来CUDA 4.0飞跃式发展
目前CUDA能够有效利用GPU强劲的处理能力和巨大的存储器带宽进行图形渲染以外的计算,广泛应用于图像处理、视频传播、信号处理、人工智能、模式识别、金融分析、数值计算、石油勘探、天文计算、流体力学、生物计算、分子动力学计算、数据库管理、编码加密等领域,并在这些领域中对CPU获得了一到两个数量级的加速,取得了令人瞩目的成绩。