各工具或库的版本:
IDE:VS2008
QT:4.8.0 (使用MSVC编译器)
CUDA:3.2
单独使用CUDA文件在vccc下进行编译很多书上都讲过。这里主要讲在QT中如何的使用CUDA,QT在VS2008环境下开发。
下面以宽为1024的举证乘法为例,再辅以QT GUI说明如何在VS2008的QT工程中使用CUDA,VS2010没试过,不过应该是差不多的步骤。
1.新建VS2008下QT工程
这个就不多说了,熟悉VS2008下进行QT开发的都知道怎么弄,新建一个Qt GUI程序,基类我选择的QDialog,如下:
2.设置项目属性
需要设置的项目属性包括:更改生成规则(添加对CUDA文件的编译连接支持)、添加使用CUDA需要用到的链接库(.lib文件)
首先添加生成规则:右键工程——>自定义生成规则,添加CUDA Runtime API Build Rule (v3.2),如下图:
然后添加链接库:项目——>属性——>链接器——>常规,在附加库目录中添加ToolKit和SDK目录里的lib,在输入的附加库目录下添加需要用到的lib文件。这一步和在单独使用CUDA时的做法是一样的,详见http://www.cnblogs.com/Romi/archive/2012/04/20/2459669.html
3.编写CUDA文件(.cu)
在项目中新建一个.cu的文件,加上如下代码,完成在GPU设备上进行矩阵乘法:
1 //CUDAtest.cu
2
3 #include "cuda_runtime.h"
4
5 #define TILE_WIDTH 64
6
7 //核函数
8 __global__ static void MatrixMulKernel(const float* Md,const float* Nd,float* Pd,int Width)
9 {
10 //计算Pd和Md中元素的行索引
11 int Row = blockIdx.y*TILE_WIDTH+threadIdx.y; //行
12 int Col = blockIdx.x*TILE_WIDTH+threadIdx.x; //列
13
14 float Pvalue = 0.0;
15 for (int k=0;k<Width;k++)
16 {
17 Pvalue +=Md[Row*Width+k]*Nd[k*Width+Col];
18 }
19 //每个线程负责计算P中的一个元素
20 Pd[Row*Width+Col]=Pvalue;
21 }
22
23 //矩阵乘法(CUDA中)
24 //在外部调用,使用extern
25 extern "C" void MatrixMultiplication_CUDA(const float* M,const float* N,float* P,int Width)
26 {
27 cudaSetDevice(0); //设置目标GPU
28
29 float *Md,*Nd,*Pd;
30 int size = Width*Width*sizeof(float);//字节长度
31
32 cudaMalloc((void**)&Md,size);
33 cudaMalloc((void**)&Nd,size);
34 cudaMalloc((void**)&Pd,size);
35
36 //Copies a matrix from the memory* area pointed to by src to the memory area pointed to by dst
37 cudaMemcpy(Md,M,size,cudaMemcpyHostToDevice);
38 cudaMemcpy(Nd,N,size,cudaMemcpyHostToDevice);
39
40 //
41 dim3 dimGrid(Width/TILE_WIDTH,Width/TILE_WIDTH); //网格的维度
42 dim3 dimBlock(TILE_WIDTH,TILE_WIDTH); //块的维度
43 MatrixMulKernel<<<dimGrid,dimBlock>>> (Md,Nd,Pd,Width);
44
45 cudaMemcpy(P,Pd,size,cudaMemcpyDeviceToHost);
46 //释放设备上的矩阵
47 cudaFree(Md);
48 cudaFree(Nd);
49 cudaFree(Pd);
50 }
这里使用extern以声明函数可以在外部被调用。如果是在调用该函数的原文件中使用include “XXX.cu”,我这会出现编译错误,暂没有解决,所以使用extern
4.在Qt响应源文件中添加CUDA的引用
Qt GUI设计如下图,点击“GPU计算”按钮进行CUDA计算,后面显示计算的时间:
源文件如下(包含用到的自定义函数和按钮响应函数):
1 //cudainqt.cpp源文件
2
3 #include "cudainqt.h"
4 #include <QProgressDialog>
5 #include <time.h>
6
7 //这里不要忘了加引用声明
8 extern "C" void MatrixMultiplication_CUDA(const float* M,const float* N,float* P,int Width);
9
10 //构造函数...
11 //析构函数...
12
13 //产生矩阵,矩阵中元素0~1
14 void matgen(float* a,int Width)
15 {
16 int i,j;
17 for (i=0;i<Width;i++)
18 {
19 for (j=0;j<Width;j++)
20 {
21 a[i*Width+j]=(float)rand()/RAND_MAX + (float)rand()/(RAND_MAX*RAND_MAX);
22 }
23 }
24 }
25
26 //矩阵乘法(CPU验证)
27 void MatrixMultiplication(const float* M,const float* N,float* P,int Width)
28 {
29 QProgressDialog progress("Progress", "Cancel", 0, 100);
30 int i,j,k;
31 for (i=0;i<Width;i++)
32 {
33 for (j=0;j<Width;j++)
34 {
35 double sum=0;
36 for (k=0;k<Width;k++)
37 {
38 sum += M[i*Width+k]*N[k*Width+j];
39 }
40 P[i*Width+j]=sum;
41 }
42 if(0==i%5)
43 progress.setValue(100*i/(Width-1));
44 }
45 }
46
47 void cudaInQt::OnButtonClicked_GPU()
48 {
49 float *M,*N,*Pg;
50 int Width=1024; //1024×1024矩阵乘法
51 M=(float*)malloc(sizeof(float)*Width*Width);
52 N=(float*)malloc(sizeof(float)*Width*Width);
53 Pg=(float*)malloc(sizeof(float)*Width*Width); //保存GPU计算结果
54
55 srand(0);
56
57 matgen(M,Width); //产生矩阵M
58 matgen(N,Width); //产生矩阵N
59
60 double timeStart,timeEnd; //定义时间,求时间差用
61 timeStart = clock();
62 MatrixMultiplication_CUDA(M,N,Pg,Width); //GPU上计算
63 timeEnd = clock();
64 ui.textEdit_GPU->setText(QString::number(timeEnd-timeStart)+"ms");
65
66 free(M);
67 free(N);
68 free(Pg);
69 }
70
71 void cudaInQt::OnButtonClicked_CPU()
72 {
73 float *M,*N,*Pc;
74 int Width=1024; //1024×1024矩阵乘法
75 M=(float*)malloc(sizeof(float)*Width*Width);
76 N=(float*)malloc(sizeof(float)*Width*Width);
77 Pc=(float*)malloc(sizeof(float)*Width*Width); //保存CPU计算结果
78
79 srand(0);
80
81 matgen(M,Width); //产生矩阵M
82 matgen(N,Width); //产生矩阵N
83
84 double timeStart,timeEnd; //定义时间,求时间差用
85 timeStart = clock();
86 MatrixMultiplication(M,N,Pc,Width); //CPU上计算
87 timeEnd = clock();
88 ui.textEdit_CPU->setText(QString::number(timeEnd-timeStart)+"ms");
89
90 free(M);
91 free(N);
92 free(Pc);
93 }
5.测试结果
测试时开了其他的应用程序,另外本机配置很戳,看看吧,使用CUDA进行加速甩了使用传统方法几条街呢
后注:代码中有点问题,测试结果也不对,后来发现了,改过的结果见该文http://www.cnblogs.com/Romi/archive/2012/05/17/2506787.html