1 CPU GPU
1.1 异构与主从
异构计算架构:GPU并行计算,GPU并不是一个独立运行的计算平台,而需要与CPU协同工作,可以看成是CPU的协处理器。
GPU与CPU通过PCIe总线连接在一起来协同工作,CPU所在位置称为为主机端(host),而GPU所在位置称为设备端(device)。
1.2 cpu gpu特定
GPU包括更多的运算核心,其特别适合数据并行的计算密集型任务,如大型矩阵运算。GPU由于存在很多核心,其线程是轻量级的。GPU重点处理数据密集型的并行计算程序。
CPU的运算核心较少,但是其可以实现复杂的逻辑运算,因此其适合控制密集型任务。CPU上的线程是重量级的,上下文切换开销大。CPU负责处理逻辑复杂的串行程序。
一个异构环境,通常有多个CPU多个GPU,他们都通过PCIe总线相互通信,也是通过PCIe总线分隔开的。所以我们要区分一下两种设备的内存:
-
主机:CPU及其内存
-
设备:GPU及其内存
1.3 CUDA编程概念
1.3.1 CUDA执行流程
CUDA编程模型是一个异构模型,需要CPU和GPU协同工作。
在CUDA中,host和device是两个重要的概念,我们用host指代CPU及其内存,而用device指代GPU及其内存。CUDA程序中既包含host程序,又包含device程序,它们分别在CPU和GPU上运行。同时,host与device之间可以进行通信,这样它们之间可以进行数据拷贝。典型的CUDA程序的执行流程如下:
-
分配host内存,并进行数据初始化;
-
分配device内存,并从host将数据拷贝到device上;
-
调用CUDA的核函数在device上完成指定的运算;
-
将device上的运算结果拷贝到host上;
-
释放device和host上分配的内存。
1.3.2 kernel
kernel是CUDA中一个重要的概念,kernel是在device上线程中并行执行的函数,核函数用__global__
符号声明,在调用时需要用<<<grid, block>>>
来指定kernel要执行的线程数量。
在CUDA中,每一个线程都要执行核函数,并且每个线程会分配一个唯一的线程号thread ID,这个ID值可以通过核函数的内置变量threadIdx
来获得。
1.3.3 关键字
由于GPU实际上是异构模型,所以需要区分host和device上的代码,在CUDA中是通过函数类型限定词开区别host和device上的函数,主要的三个函数类型限定词如下:
-
__global__
:在device上执行,从host中调用(一些特定的GPU也可以从device上调用),返回类型必须是void
,不支持可变参数参数,不能成为类成员函数。注意用__global__
定义的kernel是异步的,这意味着host不会等待kernel执行完就执行下一步。 -
__device__
:在device上执行,单仅可以从device中调用,不可以和__global__
同时用。 -
__host__
:在host上执行,仅可以从host上调用,一般省略不写,不可以和__global__
同时用,但可和__device__
,此时函数会在device和host都编译。