Romi-知行合一

轻轻的风轻轻的梦,轻轻的晨晨昏昏, 淡淡的云淡淡的泪,淡淡的年年岁岁。
  博客园  :: 首页  :: 新随笔  :: 订阅 订阅  :: 管理

VS2008+QT中使用CUDA的示例

Posted on 2012-05-09 19:38  romi  阅读(3960)  评论(1编辑  收藏  举报

各工具或库的版本:

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设备上进行矩阵乘法:

View Code
 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计算,后面显示计算的时间:

源文件如下(包含用到的自定义函数和按钮响应函数):

View Code
 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