使用Cuda进行GPU编程

——GPU高性能编程Cuda实战    第四章C并行编程总结

 

开始学习Cuda和GPU编程的相关知识啦。

感觉GPU编程会越来越重视,尤其是在移动端的计算复杂度优化方面。掌握GPU编程,以后实习找工作也会方便很多。

最近一有时间就会学习GPU高性能编程Cuda实战这本书,也会写一些总结发表到博客里。

期望是:摸熟GPU这一领域,这是以前从来没接触过得地方;通过使用Cuda进行优化三维重建的项目,为简历填上一笔硬通货。

 

Cuda的思想是:

按照类似于CPU的方法,对GPU提供通用计算的编程界面。

CPU的计算体系是:

在程序中运行的指令和临时变量,一般是保存在内存中的。CPU把数据从内存中取出来计算,再存入到内存中。

简要来说两个部分:数据的存储和计算。

GPU类似于CPU,只不过有更多的算术逻辑处理单元,更适合采用并行处理的算法来解决问题。

在考虑时,把GPU与CPU类似考虑,区别在于:

1.    内存位置的不同。

2.    计算方式的不同。

 

1.    内存位置的不同:

变量存储在内存中,其物理地址,有的对应的是CPU的内存,有的是对应GPU的内存。(方便起见,暂时不考虑CPU的高速缓存机制)

 

放在CPU内存中的数据,只能被CPU读写;放在GPU内存中的数据,只能被GPU读写。

当然可以通过CudaMemcpy的方式,把CPU内存中的数据与GPU内存总的数据做交换。

考虑CPU和GPU的区别时,把CPU和CPU对应的内存当做主机,而GPU和GPU对应的内存当做设备device

 

在CPU中声明一个指针的方法是:

int *a = new int[10];

这样a就对应着CPU内存中一个长度为10的int数组的首地址

 

在GPU中分配内存则是:

int *dev_a;

cudaMalloc( (void **) &dev_a, 10 * sizeof(int) );

dev_a是一个指针,指向一段int型数组的首地址;

&dev_a 是 指向dev_a的指针,通过cudaMalloc的函数,可以改变dev_a指向的位置。

分配完空间之后,dev_a指向的也就是GPU内存中一段int型数组的首地址。

 

 

2.    计算方式的不同

在GPU中执行的函数被称为核函数, 使用如下:kernel<<<1,1>>>>(params);

举例来说:

声明GPU的函数,需要用如下的方式:

__global __ void add(int *a, int *b){    

}

使用时,add<<<N,1>>>(dev_a, dev_b);

声明为global函数之后,才可以在主机上调用。

 

第一个参数表示,设备在执行核函数时使用的并行线程块的数量。在函数中,可以通过blockIdx.x获得当前线程块的id

(备注:cuda可以支持二维索引,通过grid实现)

简单的并行处理就可以通过调用add函数来完成了。

 

不过真正的并行处理,还需要考虑到不同线程之间的通信、同步情况,这些内容留着学习下一章的时候再做介绍吧。