為了避免每次都要鍵入nvcc的命令,要准備一個makefile。makefile如下:
CUFLAG = -g -Xcompiler -v \
-gencode=arch=compute_20,code=sm_20\
-gencode=arch=compute_20,code=compute_20\
-O2
IFLAGS = -I$(CUDA_DIR)/include -I$(CUDA_SDK_DIR)/C/common/inc -I../include
LFLAGS = -L$(CUDA_DIR)/lib64 -L$(CUDA_SDK_DIR)/C/lib
PRG = cuda_test
$(PRG) : main.cu
nvcc main.cu -o $(PRG) $(CUFLAG) $(IFLAGS) $(LFLAGS)
Ubuntu 12.04 下 CUDA 編程 http://www.linuxidc.com/linux/2014-06/103056.htm
Ubuntu 12.04 安裝 CUDA-5.5 http://www.linuxidc.com/Linux/2013-10/91101.htm
Ubuntu 11.10 上安裝CUDA開發環境 http://www.linuxidc.com/Linux/2012-04/58913.htm
Fedora 15系統下配置CUDA環境 http://www.linuxidc.com/Linux/2011-12/49874.htm
Ubuntu 11.04 安裝 NVIDIA CUDA 4.0 RC2 http://www.linuxidc.com/Linux/2011-10/46304.htm
Linux Mint 13/Ubuntu 12.04 配置CUDA 4.2 & OpenCV 2.4.2 方法 http://www.linuxidc.com/Linux/2013-10/91102.htm
宏觀上看,GPU執行代碼的流程如下:
例1: Hello World
#include<stdio.h>
#include<stdlib.h>
#include<cuda.h>
#include<cutil.h>
__global__ void mykernel(void) {
}
int main(void) {
mykernel<<<1,1>>>();
printf("Hello World!\n");
return 0;
}
上述代碼編譯後運行生成可執行文件cuda_test,運行cuda_test後將輸出:
Hello World!
注意:
CUDA C/C++中引入的新關鍵字__global__所修飾的函數有以下兩方面含義:
nvcc將源代碼分為設備函數和主機函數兩大類:
例2: 整數相加
#include<stdio.h>
#include<stdlib.h>
#include<cuda.h>
#include<cutil.h>
__global__ void integer_add(int * a, int * b, int * c) {
*c = *a + *b;
}
int main(void) {
int a,b,c;
int * d_a, * d_b, * d_c;
int size = sizeof(int);
cudaMalloc((void**)&d_a,size);
cudaMalloc((void**)&d_b,size);
cudaMalloc((void**)&d_c,size);
printf("Enter two integers with a space to separate them:\n");
scanf("%d %d",&a,&b);
cudaMemcpy(d_a,&a,size,cudaMemcpyHostToDevice);
cudaMemcpy(d_b,&b,size,cudaMemcpyHostToDevice);
integer_add<<<1,1>>>(d_a,d_b,d_c);
cudaMemcpy(&c,d_c,size,cudaMemcpyDeviceToHost);
cudaFree(d_a);
cudaFree(d_b);
cudaFree(d_c);
printf("Sum is %d\n",c);
return 0;
}
__global__修飾的integer_add函數說明:
#include<stdio.h>
#include<stdlib.h>
#include<cuda.h>
#include<cutil.h>
#include<time.h>
#define N 512
__global__ void vec_block_add(int * a, int * b, int * c) {
c[blockIdx.x] = a[blockIdx.x] + b[blockIdx.x];
}
void rand_ints(int * arr, int count) {
srand(time(NULL));
for(int i=0;i<count;i++) {
arr[i] = rand() % 100;
}
}
int main(void) {
int * a,* b,* c;
int * d_a, * d_b, * d_c;
int size = N * sizeof(int);
cudaMalloc((void**)&d_a,size);
cudaMalloc((void**)&d_b,size);
cudaMalloc((void**)&d_c,size);
a = (int *) malloc(size);
rand_ints(a,N);
b = (int *) malloc(size);
rand_ints(b,N);
c = (int *) malloc(size);
cudaMemcpy(d_a,a,size,cudaMemcpyHostToDevice);
cudaMemcpy(d_b,b,size,cudaMemcpyHostToDevice);
vec_block_add<<<N,1>>>(d_a,d_b,d_c);
cudaMemcpy(c,d_c,size,cudaMemcpyDeviceToHost);
#if 1
for(int i=0;i<N;i++) {
printf("%-5d: a:%-5d b:%-5d c:%-5d\n",i,a[i],b[i],c[i]);
}
#endif
cudaFree(d_a);
cudaFree(d_b);
cudaFree(d_c);
free(a);
free(b);
free(c);
return 0;
}
例3中最關鍵的代碼為如下幾行:
__global__ void vec_block_add(int * a, int * b, int * c) {
c[blockIdx.x] = a[blockIdx.x] + b[blockIdx.x];
}
由於函數是並行執行的,和傳統的串行程序在integer_add函數中使用循環來完成加法相比,相當於由GPU這個加速器使用硬件的方式進行了循環展開,展開後便可以並行執行了。所以在編寫這段代碼時,需要使用blockIdx.x來定位當前執行的是循環的哪個部分。
從硬件的角度看,相當於同時有多個塊在並行執行: 塊0: c[0]=a[0]+b[0] 塊1: c[1]=a[1]+b[1] 塊2: c[2]=a[2]+b[2] 塊3: c[3]=a[3]+b[3] ....更多詳情見請繼續閱讀下一頁的精彩內容: http://www.linuxidc.com/Linux/2014-07/104328p2.htm