一、并行计算概述
在计算机术语中,并行性描述了把一个复杂问题分解成多个能同时处理的子问题的能力。要实现并行计算,首先我们要有物理上能够实现并行计算的硬件设备,比如多核CPU,每个核能同时实现算术或逻辑运算。 在GPU并行计算中,通常我们实现两类并行计算: 任务并行:把一个问题分解为能够同时执行的多个任务。 数据并行:同一个任务内,它的各个部分同时执行。 下面我们通过一个农场主雇佣工人摘苹果的例子来描述不同种类的并行计算。
数据并行就好比农场主雇佣了好多工人来摘完一个树上的苹果(多个处理单元并行完成一个任务中的数据),这样就能很快摘完一颗树上的苹果。 农场主也可以为每棵树分配一个人,这就好比任务并行。在每个任务内,由于只有一个工人,所以是执行串行的,但任务之间是并行的。 对一个复杂问题,影响并行计算的因素很多。通常,我们都是通过分解问题的方式来实施并算法行。 这又包括两方面内容:
这有点类似于我们数据结构中的有向无环图,两个没有连通路径的任务之间可以并行执行。下面再给一个烤面包的例子,如果所示,预热烤箱和购买面粉糖两个任务之间可以并行执行。 对大多数科学计算和工程应用来说,数据分解一般都是基于输出数据,例如:
也有的数据分解算法是基于输入数据的,这时,输入数据和输出数据一般是一对多的关系,比如求图像的直方图,我们要把每个像素放到对应的槽中(bins,对于灰度图,bin数量通常是256)。一个搜索函数,输入可能是多个数据,输出却只有一个值。对于这类应用,我们一般用每个线程计算输出的一部分,然后通过同步以及原子操作得到最终的值,OpenCL中求最小值的kernel函数就是典型代表[可以看下ATI Stream Computing OpenCL programming guide第二章中求最小值的kernel例子]。 通常来说,怎样分解问题和具体算法有关,而且还要考虑自己使用的硬件和软件,比如AMD GPU平台和Nvdia GPU平台的优化就有很多不同。 二、常用基于硬件和软件的并行 在上个实际90年代,并行计算主要研究如何在cpu上实施指自动的指令级并行。
现代的GPU有很多独立的运算核(processor)组成,在AMD GPU上就是stream core,这些core能够执行SIMD操作(单指令,多数据),所以特别适合数据并行操作。通常GPU上执行一个任务,都是把任务中的数据分配到各个独立的core中执行。 在GPU上,我们一般通过循环展开,Loop strip mining 技术,来把串行代码改成并行执行的。比如在CPU上,如果我们实现一个向量加法,代码通常如下: 普通浏览复制代码保存代码打印代码
普通浏览复制代码保存代码打印代码
上面这个图展示了向量加法的SPMD(单指令多线程)实现,从图中可以看出如何实施Loop strip mining 操作的。 GPU的程序一般称作Kernel程序,它是一种SPMD的编程模型(the Single Program Multiple Data )。SPMD执行同一段代码的多个实例,每个实例对数据的不同部分进行操作。在数据并行应用中,用loop strip mining来实现SPMD是最常用的方法:
GPU上并行编程的硬件一般称作SIMD。通常,发射一条指令后,它要在多个ALU单元中执行(ALU的数量即使simd的宽度),这种设计减少了控制流单元以级ALU相关的其他硬件数量。 SIMD的硬件如下图所示: 在向量加法中,宽度为4的SIMD单元,可以把整个循环分为四个部分同时执行。在工人摘苹果的例子中,工人的双手类似于SIMD的宽度为2。另外,我们要知道,现在的GPU硬件上都是基于SIMD设计,GPU硬件隐式的把SPMD线程映射到SIMD core上。对开发有人员来说,我们并不需要硬件是否正确,我们只需要关注它的性能。 CPU一般都支持并行级的原子操作,这些操作保证不同的线程读写数据,相互之间不会干扰。有些GPU支持系统范围的并行操作,但会有很大开销,比如Global memory的同步。 |
|