使用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函数来完成了。
不过真正的并行处理,还需要考虑到不同线程之间的通信、同步情况,这些内容留着学习下一章的时候再做介绍吧。