异构并行计算包括两个方面的内容:异构和并行。异构是指:计算单元由不同的多种处理器组合,如X86 CPU+GPU、ARM CPU+GPU、X86 CPU+FPGA、ARM CPU+DSP等。并行是指:要发挥异构硬件平台的全部性能必须要使用并行的编程方式。通常包含两个层次的内容:
在2005年之前,大多数处理器都是单核的,一些处理器已经开始支持向量化(如X86处理器支持的MMX多媒体扩展)和SSE(流式SIMD扩展)指令集。但是绝大多数应用程序并没有进行向量化。
在2005年之后,单标量处理器的性能基本上达到了顶峰,很难进一步大幅度提升性能。
主要通过以下的方式提升性能:
五阶段流水线将指令的执行过程划分为:取指令(Instruction Fetch,IF)、指令解码(Instrcution Decode,ID)、执行(Execution,EX)、访存(Memory Access,MEM)和写回(Write Back,WB)。假设处理器支持两条流水线同时操作。每个周期内,都会有两条指令执行完成,两条新指令加入执行。执行的步骤如上图所示。从整体来看,若没有使用流水线执行,则原来需要5个周期才能完成2个在操作,而使用流水线执行后,则每个周期能够完成2个操作。
单核标量处理器的性能不能再以摩尔处理器的速速提升,主要的原因:
在提升指令级并行遇到瓶颈后,硬件设计师通过硬件寄存器的长度提升性能。例如原来的寄存器长度为32位,现在提供到128位,这意味着原来的一个寄存器能够存放一个单进度浮点数据,而现在一个寄存器能够保存4个这样的数据。
今天的绝大多数处理器,如X86多核CPU、ARM多核CPU、GPU以及DSP等,都已经是多核向量处理器。多核和向量化的出现满足了应用对计算机能力的需求。
多核通过复制处理器核心成倍了处理器的计算能力,多核的的出现除了消耗的原因外,还有很多其他原因。
随着数据量越来越大,处理大量数据需要的计算性能的需求也越来远大,但是处理器商没有办法提供性能更好的处理器、
如果代码使用128位向量化处理单精度数据,那么每次可以同时处理4个数据。
要同时发挥向量化和多核的计算能力,必须要编写向量化和多线程代码。主要有两种:
常见的编写语言,如C11/C+11和Java等语言本身已经内置了线程级并行能力,而其他的语言则需要使用语言自身到机制。要发挥多核向量处理器的向量计算能力,则需要使用能够硬件生产商提供了内联汇编(也称为内置函数)。例如Intel/AMD为其X86提供了SSE/AVX指令集的C语言内置函数,ARM也为其CPU处理器提供了NEON指令集的C语言内置函数。
一些新的C编程语言扩展,如CUDA和OpenCL,通过层次化的线程/编程模型使得一份代码同时支持向量化和多核。
OpenCL不但支持GPU,还支持X86 CPU和ARM,一些移动处理器的GPU也开始支持OpenCL、目前一些FPGA和DSP的厂商也提供了OpenCL的支持。
从2007年NVIDIA退出了CUDA计算环境开始,异构并行计算逐渐得到了大众的认同。异构并行计算包含两个子概念:异构和并行
异构并行计算出现的主要的两种问题:
在NVIDIA推出其CUDA计算环境之前,很多科学家就已经意识到如果能力利用GPU提供的强大计算能力计算一些通用运算,就能够获得很高的计算速度。在哪个时代,要使用GPU计算,则必须要将算法映射成图形的渲染过程,那时用来进行图形编程的主要应用编程接管口是OpenGL,即使用OpenGL将计算过程映射成为图形渲染过程,进而达成计算的目的,这称之为GPGPU。
在2007年,NVIDIA退出了GTX8800 GPU,与之前为图形渲染的每个阶段独立设计流水线不同,GTX8800采用统一的渲染架构。同一处理器会处理图形渲染的全部流水线,这不仅提升了硬件的利用率,获得图形渲染的高性能。
NVIDIA称CUDA是计算统一设备架构(Computing Unified Device Architecture)缩写,但是今天CUDA的范围已经远远超出了NVIDIA当初的定义,CUDA已经成为NVIDIA通用GPU并行计算编程平台和编程模型的抽象,一个符号,一个生态系统。
CUDA平台提供了CUDA C语言扩展,相比普通C语言,CUDA C增加了使用NVIDIA CPU进行通用计算必不可少的一些语言扩展,其他功能功能都通过函数库提供。CUDA C以C/C++语言为基础而设计,因此对熟悉的C系统语言的程序员来说,CUDA的语法比较容易掌握。另外CUDA只对 ANSI C 进行了最小的扩展,以实现其关键特性::形成按照两个层次进行组织、共享存储器(shared memory)和栅栏(barrier)同步。
由于CUDA由NIVDIA一家设计,并未被Intel和AMD接受,因此目前使用的CUDA编写的程序只支持NVIDIA GPU,而OpenGL的出现解决了这一问题。
OpenCL全称为Open Computing Language(开放计算语言),先由Apple设计,后来交由Khronos Group维护,是异构平台并行编程的开发的标准,也是编程架构。OpenCL的设计借鉴了CUDA的成功经验,并尽可能地支持多核CPU,GPU或其他加速器,OpenCL不断支持数据并行,还支持任务并行。同时OpenCL内建了多GPU并行的支持。OpenCL API 基于纯C语言进行编写,所以OpenCL API的函数名比较长,参数也比较多(不支持函数重载),因此函数名相对难以记忆。
OpenCL涵盖的领域不但包括GPU,还包括其他的多种处理器芯片。到现在为止,支持OpenCL的硬件主要局限在CPU、GPU、DSP和FPGA上,目前在桌面端和服务器端提供OpenCL开发环境的主要有Apple,NVIDIA、AMD、ARM和Intel,其中Apple提供了一个独立的OpenCL开发环境并与自家的OS X系统完整地融合在一起,NVIDIA和AMD都提供了基于自家的GPU的OpenCL在Windows和OpenCL实现。
OpenCL包含两个部分,一是OpenCL C语言(OpenCL 2.1将开始使用OpenCL C++作为内核编程语言)和主机端API。二是硬件架构的抽象,OpenCL只是给C11进行了非常小的扩展,以提供控制并行计算设备的API以及一些声明计算内核的呢管理。软件开发人员可以利用OpenCL开发并行程序,并且可获得比较好的多种设备上运行的可移植性。
为了使得OpenCL程序能够在各种硬件平台运行,OpenCL提供了一个硬件平台层,同时各种不同设备上的存储器并不相同,相应地,OpenCL提供了一个存储器抽象模型。不但包括一门编程语言,还包括一个完整的并行编程框架,通过编程语言、API以及运行时系统来支持软件在整个平台上的运行。
近年来,从私有的CUDA、C++AMP、Direct3D、Metal API,到开放的OpenCL、OpenACC、OpenGL。而传统的共享存储器编程环境OpenMP和分布式编程环境MPI也增加的对异构计算的支持。
OpenCL的特点如下:
经典的分布式存储并行标准MPI在其版本3中明确了允许在数据传输函数调用时使用异构平台上的指针内容,并且同时在标准中扫清了相关的数据匹配等问题。这使得MPI在进行数据传输时,能够直接传递指向GPU或其他硬件上内存地址的指针。但是MPI 3对异构的支持几乎为0。
经典共享存储器并行编程环境OpenMP在其4.0版本标准中增加了很多支持异构计算的构造,如target、target data等。
AMD不但在其GPU上全面支持OpenCL,还在去X86 CPU上支持OpenCL,是第一个提供CPU+GPU全面支持OpenCL的厂家。AMD转向OpenCL后,和OpenCL的编程模型紧密结合,推出了GCN系统的GPU。Intel推出了其OpenCL支持方案,但是这种支持是全面的一劳永逸的,无论是Intel的X86 CPU,MIC GPU,还是Intel X86 CPU集成的GEN架构GPU都得到了支持。
2013/2014,主流的移动处理器厂都退出了基于其移动GPU的OpenCL编译运行环境,如Imageination Technology的PowerVR系列移动GPU、高通的Adreno系列的移动GPU、ARM的Mali系统的GPU都支持了OpenCL。与此同时,主流的FPGA厂商Altera和Xilin也推出了OpenCL编译运行环境。