Bare in mind:
- 不管你的数据是一维的二维的还是更高维度的,在GPU端,高维被扁平化,都将被看成一维的,所以么有必要在Device上开辟,比如,一个二维数组。
- CUDA code 需要你并行地思考:
Think parallel
. - 当你在写CUDA code, 实际上你是在为一个thread 写串行code,而每一个thread都执行这个段相同的串行code。看下图体会。
- 可以这样理解,对于简单问题,把CPU code的for 循环去掉,其实就得到了GPU code。每个thread 有自己唯一的ID,其他都一样。
配置kernel
当GPU可用的thread非常多,而当前所需解决的任务规模并不大时,可以一次invoke 足量的threads,这样便不用更新threads ID。如下:
1
2
3
4
5
6
...
int block(1024);
int grid ((N + block.x - 1) / block.x );
kernal_func <<<grid, block >>>(d_c, d_a, d_b);或者二维的configuration:
1
2
3
4
5
6
...
dim3 block (1024, 1024);
dim3 grid (( N + block.x -1) / block.x, (N + block.y -1) / block.y );
kernel_func <<<grid, block >>>(dev_m, dev_mt);当然所有的configuration都应该在你的GPU硬件极限内。
当数据量很大时,所有CUDA cores 就需要工作不止一波,第一波后,就需要更新threads ID 继续工作下一波:
1
2
3
4
5
6
7
8__global__ void add(int *a, int *b, int *c) {
int tid = threadIdx.x + blockIdx.x * blockDim.x;
while (tid < N) {
c[tid] = a[tid] + b[tid];
// OPERATIONS
tid += blockDim.x * gridDim.x; // update id when #threads are less than #elements
}
}此处的
while
循环 表示,只要threads ID 还小于元素个数N,就更新ID。