CUDA学习

4 篇文章 0 订阅
本文深入探讨了CUDA编程环境的搭建及基本使用,通过展示CUDA5.0自带的demo程序,详细解释了如何在GPU上执行并行任务。重点介绍了CUDA的核心概念如线程、块和网格,以及如何优化数据复制过程以提高性能。同时,文章还提供了关于CUDA版本差异性的注意事项,帮助开发者在不同环境下顺利进行并行计算。
摘要由CSDN通过智能技术生成

CUDA的学习

      前面几天写了三维重建中的特征提取部分,下面接着写,不过今天写一下CUDA的内容,这个下面要用到,要学习,首先装环境,装了CUDA5.0,网上有一个windows7+CUDA5.0的教程,挺好,按照那个基本上没有问题,不过实际在运行的过程中发现了一个问题,就是不同通过windows的远程桌面连接,远程桌面不能调用显卡。

     于是想远程操作的则可以下载一个Symantec pcAnywhere,远程控制软件。好了不多说,我们就先看第一个程序。也就是CUDA5.0自带的demo。

     把整个程序列上来,然后加了点注释,这个也只是参考加上本人的理解,也不知道正确与否。望大家指正。

[cpp]  view plain copy
  1. #include "cuda_runtime.h" //使用 runtime API  
  2.   
  3. #include "device_launch_parameters.h"  
  4.   
  5. #include <stdio.h>  
  6.   
  7. cudaError_t addWithCuda(int *c, const int *a, const int *b, size_t size);  
  8.   
  9. // 显示芯片上执行的程序。在 CUDA 中,在函式前面加上  
  10.   
  11. // __global__ 表示这个函式是要在显示芯片上执行的。  
  12.   
  13. // 在显示芯片上执行的程序有一些限制,例如它不能有传回值。  
  14.   
  15. // 接下来是要让 CUDA 执行这个函式。  
  16.   
  17. __global__ void addKernel(int *c, const int *a, const int *b)  
  18.   
  19. {  
  20.   
  21. // threadIdx  是 CUDA 的一个内部的变量,表示目前的 thread 是  
  22.   
  23. //第几个 thread(由 0 开始计算)这边会有 size =5 个 threads  
  24.   
  25. //每一个的 threadIdx.x  则分别会是 0 ~ 5。利用这个变量,我们  
  26.   
  27. //就可以让每一份函式执行时,对整个数据不同的部分进行相加。  
  28.   
  29. int i = threadIdx.x;  
  30.   
  31. c[i] = a[i] + b[i];  
  32.   
  33. }  
  34.   
  35. int main()  
  36.   
  37. {  
  38.   
  39. const int arraySize = 5;  
  40.   
  41. const int a[arraySize] = { 1, 2, 3, 4, 5 };  
  42.   
  43. const int b[arraySize] = { 10, 20, 30, 40, 50 };  
  44.   
  45. int c[arraySize] = { 0 };  
  46.   
  47. // Add vectors in parallel.  
  48.   
  49. cudaError_t cudaStatus = addWithCuda(c, a, b, arraySize);  
  50.   
  51. if (cudaStatus != cudaSuccess) {  
  52.   
  53. fprintf(stderr, "addWithCuda failed!");  
  54.   
  55. return 1;  
  56.   
  57. }  
  58.   
  59. printf("{1,2,3,4,5} + {10,20,30,40,50} = {%d,%d,%d,%d,%d}\n",  
  60.   
  61. c[0], c[1], c[2], c[3], c[4]);  
  62.   
  63. // cudaDeviceReset must be called before exiting in order for profiling and  
  64.   
  65. // tracing tools such as Nsight and Visual Profiler to show complete traces.  
  66.   
  67. cudaStatus = cudaDeviceReset();  
  68.   
  69. if (cudaStatus != cudaSuccess) {  
  70.   
  71. fprintf(stderr, "cudaDeviceReset failed!");  
  72.   
  73. return 1;  
  74.   
  75. }  
  76.   
  77. return 0;  
  78.   
  79. }  
  80.   
  81. // Helper function for using CUDA to add vectors in parallel.  
  82.   
  83. cudaError_t addWithCuda(int *c, const int *a, const int *b, size_t size)  
  84.   
  85. {  
  86.   
  87. int *dev_a = 0;  
  88.   
  89. int *dev_b = 0;  
  90.   
  91. int *dev_c = 0;  
  92.   
  93. cudaError_t cudaStatus;  
  94.   
  95. // Choose which GPU to run on, change this on a multi-GPU system.  
  96.   
  97. // 选择哪个GPU去运行,这个在多GPU系统上修改。  
  98.   
  99. cudaStatus = cudaSetDevice(0);  
  100.   
  101. if (cudaStatus != cudaSuccess) {  
  102.   
  103. fprintf(stderr, "cudaSetDevice failed!  Do you have a CUDA-capable GPU installed?");  
  104.   
  105. goto Error;  
  106.   
  107. }  
  108.   
  109. // Allocate GPU buffers for three vectors (two input, one output)  
  110.   
  111. // 给三个向量(两个输入,一个输出)分配GPU缓存.  
  112.   
  113. // 要利用 CUDA 进行计算之前,要先把数据复制到显卡内存中,// 才能让显示芯片使用。因此,  
  114.   
  115. // 需要取得一块适当大小的显卡内存,再把产生好的数据复制进去  
  116.   
  117. cudaStatus = cudaMalloc((void**)&dev_c, size * sizeof(int));  
  118.   
  119. if (cudaStatus != cudaSuccess) {  
  120.   
  121. fprintf(stderr, "cudaMalloc failed!");  
  122.   
  123. goto Error;  
  124.   
  125. }  
  126.   
  127. cudaStatus = cudaMalloc((void**)&dev_a, size * sizeof(int));  
  128.   
  129. if (cudaStatus != cudaSuccess) {  
  130.   
  131. fprintf(stderr, "cudaMalloc failed!");  
  132.   
  133. goto Error;  
  134.   
  135. }  
  136.   
  137. cudaStatus = cudaMalloc((void**)&dev_b, size * sizeof(int));  
  138.   
  139. if (cudaStatus != cudaSuccess) {  
  140.   
  141. fprintf(stderr, "cudaMalloc failed!");  
  142.   
  143. goto Error;  
  144.   
  145. }  
  146.   
  147. // Copy input vectors from host memory to GPU buffers.  
  148.   
  149. // 复制输入向量从主存到显卡内存。  
  150.   
  151. // 通过调用cudaMalloc 取得一块显卡内存,然后通过过  
  152.   
  153. // cudaMemcpy 将上述两个数组复制到显卡内存中.  
  154.   
  155. // cudaMalloc 和 cudaMemcpy 的用法和一般的 malloc 及  
  156.   
  157. // memcpy 类似,不过 cudaMemcpy 则多出一个参数,指示复制内// 存的方向。在这里因为是从主内存复制到显卡内存,所以使用  
  158.   
  159. // cudaMemcpyHostToDevice。如果是从显卡内存到主内存,则使用 // cudaMemcpyDeviceToHost。  
  160.   
  161. cudaStatus = cudaMemcpy(dev_a, a, size * sizeof(int), cudaMemcpyHostToDevice);  
  162.   
  163. if (cudaStatus != cudaSuccess) {  
  164.   
  165. fprintf(stderr, "cudaMemcpy failed!");  
  166.   
  167. goto Error;  
  168.   
  169. }  
  170.   
  171. cudaStatus = cudaMemcpy(dev_b, b, size * sizeof(int), cudaMemcpyHostToDevice);  
  172.   
  173. if (cudaStatus != cudaSuccess) {  
  174.   
  175. fprintf(stderr, "cudaMemcpy failed!");  
  176.   
  177. goto Error;  
  178.   
  179. }  
  180.   
  181. // Launch a kernel on the GPU with one thread for each element.  
  182.   
  183. // 函式名称<<<block 数目, thread 数目, shared memory 大小  
  184.   
  185. // >>>(参数...);   
  186.   
  187. //在 CUDA 中,thread 是可以分组的,也就是 block。一个 block 中//的 thread,具有一个共享的 shared memory,也可以进行同步工作。//不同 block 之间的 thread 则不行。在我们的程序中,其实不太需//要进行 thread 的同步动作,因此我们可以使用多个 block 来进一//步增加 thread 的数目。就是把这个1改变  
  188.   
  189. addKernel<<<1, size>>>(dev_c, dev_a, dev_b);  
  190.   
  191. // cudaDeviceSynchronize waits for the kernel to finish, and returns  
  192.   
  193. // any errors encountered during the launch.  
  194.   
  195. cudaStatus = cudaDeviceSynchronize();  
  196.   
  197. if (cudaStatus != cudaSuccess) {  
  198.   
  199. fprintf(stderr, "cudaDeviceSynchronize returned error code %d after launching addKernel!\n", cudaStatus);  
  200.   
  201. goto Error;  
  202.   
  203. }  
  204.   
  205. // Copy output vector from GPU buffer to host memory.  
  206.   
  207. cudaStatus = cudaMemcpy(c, dev_c, size * sizeof(int), cudaMemcpyDeviceToHost);  
  208.   
  209. if (cudaStatus != cudaSuccess) {  
  210.   
  211. fprintf(stderr, "cudaMemcpy failed!");  
  212.   
  213. goto Error;  
  214.   
  215. }  
  216.   
  217. Error:  
  218.   
  219. cudaFree(dev_c);  
  220.   
  221. cudaFree(dev_a);  
  222.   
  223. cudaFree(dev_b);  
  224.   
  225. return cudaStatus;  
  226.   
  227. }  


使用5.0的时候要注意跟以前版本的不一样的地方,一个是这个版本里面没有了

#include "cuda_util.h"

也就是以前使用的向CUDA_SAFE_CALL之类的就不好使用了

修改以前版本的可以去掉通过上面的方法使用cudaError_t,也可以使用

#include <helper_functions.h>

#include <helper_cuda.h>

不过不是C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v5.0\include

下的头文件最好不要引用,以免跟上面一样。

在对于CUDA 的操作中,开始的时候要将主存上的数据复制到GPU上,而GPU上又分为好几种

几种的区别以及何时用,也就是一个优化的过程,这个是个难点。

clipboard

下面就主要的是一个并行算法的问题,这个也是最关键的。

下面再把Blocks 和 Threads和grid的关系图放上来

clipboard[1]

这样一个基本的CUDA程序就基本上了解了,不过要理解的还有很多,先写这么多。

http://www.cnblogs.com/fengbing/category/417672.html
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值