1. 理解GPU
5. 最简单的CUDA程序
这是一个计算一组数字的平方的CUDA程序__global__修饰符表示这是一个CUDA函数,也叫kernel function。
整个程序简单易懂,注释清晰,不做过多的解释了
#include <stdio.h> __global__ void square(float * d_out, float * d_in) { int idx = threadIdx.x; float f = d_in[idx]; d_out[idx] = f * f; } int main(int argc, char ** argv) { const int ARRAY_SIZE = 64; const int ARRAY_BYTES = ARRAY_SIZE * sizeof(float); // generate the input array on the host float h_in[ARRAY_SIZE]; for (int i = 0; i < ARRAY_SIZE; i++) { h_in[i] = float(i); } float h_out[ARRAY_SIZE]; // declare GPU memory pointers float *d_in; float *d_out; // allocate GPU memory cudaMalloc((void**) &d_in, ARRAY_BYTES); cudaMalloc((void**) &d_out, ARRAY_BYTES); // transfer the array to the GPU cudaMemcpy(d_in, h_in, ARRAY_BYTES, cudaMemcpyHostToDevice); // launch the kernel square<<<1, ARRAY_SIZE>>>(d_out, d_in); // copy back the result array to the CPU cudaMemcpy(h_out, d_out, ARRAY_BYTES, cudaMemcpyDeviceToHost); // print out the resulting array for (int i =0; i < ARRAY_SIZE; i++) { printf("%f", h_out[i]); printf(((i % 4) != 3) ? "\t" : "\n"); } cudaFree(d_in); cudaFree(d_out); return 0; }
__global__ void foo(float *x,float *y,float *z) { __shared__ float a,b,c; float s,t,u; s = *x;//1 t = s;//2 a = b;//3 *y = *z;//4 }
__global__ void foo(float *x,float *y,float *z){ __shared__ float a,b,c; float s,t,u; s = *x;//1 t = s;//2 a = b;//3 *y = *z;//4 }答案是:依此为1的速度是3,2行速度是1,3是2,4是4
同步(Synchronise)
就像给代码设置一个障碍一样
现在我们要做这样一件事,有一个数组,我们想将这个数组每一项向前移动一位(忽略第一项),也就是array[x] = array[x+1]
一个简略的函数框架可能是这样的:
__global__ void shift(){ int idx = threadIdx.x; __shared__ int array[128]; array[idx] = threadIdx.x; if (idx < 127) { array[idx] = array[idx + 1]; } }
__global__ void shift(){ int idx = threadIdx.x; __shared__ int array[128]; array[idx] = threadIdx.x; if (idx < 127) { array[idx] = array[idx + 1]; } }稍微理解并发执行,明白上面的代码不可能顺利执行,比如在线程20执行时,
array[20] = 20;可以执行
array[20] = array[20+1];如果线程21在线程20之后执行,显然这句话的赋值是错误的
那么正确的运行上述程序,需要给代码设置几个“障碍”,如下
__global__ void shift(){ int idx = threadIdx.x; __shared__ int array[128]; array[idx] = threadIdx.x; __syncthreads();//执行至此,数组中的每一个元素都被正确的赋值 if (idx < 127) { int temp = array[idx + 1]; __syncthreads();//将一行代码拆分成两行来设置一个barrier,这种技巧非常实用,执行至此,每一个线程都正确的取值 array[idx] = temp; __syncthreads();//确保后续使用array的正确性 } }
__global__ void shift(){ int idx = threadIdx.x; __shared__ int array[128]; array[idx] = threadIdx.x; __syncthreads();//执行至此,数组中的每一个元素都被正确的赋值 if (idx < 127) { int temp = array[idx + 1]; __syncthreads();//将一行代码拆分成两行来设置一个barrier,这种技巧非常实用,执行至此,每一个线程都正确的取值 array[idx] = temp; __syncthreads();//确保后续使用array的正确性 } }