NVIDIA CUDA 高度并行处理器编程(一):CUDA简介
1. 数据并行性
数据并行性是一种属性,这种属性支持算数操作按照程序的数据结构同时安全的执行。CUDA设备通过采用大量的数据并行性的方式来加快应用程序的执行速度。
在并行编程中,数据并行并不是唯一一种广泛使用的并行性,任务并行性在并行编程中也有广泛的使用。任务并行性通常对应用进行任务分解得到。例如,对于向量加法和矩阵向量乘法的简单应用来说,每个操作都可以看做一个任务,如果这两个任务可以独立执行,那么就能得到任务并行性。
一般情况下,数据并行性是并行程序可拓展性地的主要来源。对于大型数据集很容易找到大量的数据并行性,以充分利用大规模并行处理器,随着每一代硬件提供更多执行单元,应用的性能也能大幅度提升。然而,任务并行性对于性能的提升也很重要,在介绍CUDA流的时候再介绍。

2. CUDA的程序结构
CUDA程序结构反映了在计算机中有一个主机(CPU)和一个或多个设备(GPU)。每个CUDA源文件包含主机代码和设备代码。默认情况下,任何只包含主机代码的C程序都可以看做CUDA程序。可以对任何C源文件添加设备函数和设备数据声明。针对设备的函数的数据声明都带有CUDA关键字标记。这些函数通常体现了丰富的数据并行性。
一旦设备函数和数据声明添加进C源文件中,编不能通过gcc或其他编译器的编译。这些代码需要用能够识别这些设备函数和数据声明的编译器编译,比如NVCC(NVIDIA C Compiler)。如下图上部所示

NVCC处理程序时通过CUDA关键字区分主机程序和设备程序。主机代码由主机标准的C或C++编译器编译,而设备代码用CUDA关键字来标示数据并行函数 (称为kernel) 。通常由NVCC编译器进一步编译,并在GUP上执行,如果没有GPU或者kernel更适合在CPU上执行,则可以通过MCUDA等工具将kernel函数转到CPU上执行。
典型的CUDA程序的执行过程如下图所示。这是个简化的执行过程,其中GPU和CPU的执行过程没有重叠,然而很多模型都会采用CPU和GPU重叠执行的模型,以充分利用两者。
执行过程始于主机,遇到kernel函数时函数转移到设备上大量线程同时执行。在调用kernel函数时生成的所有线程统称网络,下图就包含了两个网络。当kernel函数中所有线程都完成他们的执行任务后,相应的网格也会终止,在调用下一个kernel函数时程序会转到主机上继续执行。

3. 向量加法kernel函数
在主机代码的每一段中,给主机处理的变量名加上前缀h_,在设备要处理的变量名前加上前缀d_,以示区别。先看传统的C程序:
// Compute vector sum h_C = h_A+h_B
void vecAdd(float* h_A, float* h_B, float* h_C, int n)
{
for (inti= 0; i < n; i++) h_C[i] = h_A[i] + h_B[i];
}
int main()
{
// Memory allocation for h_A, h_B, and h_C
// I/O to read h_A and h_B, N elements each
…
vecAdd(h_A, h_B, h_C, N);
}
此程序通过for循环顺序执行向量加法,在第[i]轮循环中,计算A[i]和B[i]的和并存入C[i]。并行执行向量加法的简单方法是修改vecAdd函数: