由上一节可知,在main函数中,cuda程序的并行能力是在add<<<N,1>>>( dev_a, dev_b, dev_c )函数中体现的,这里面设置的是由N个block的构成的计算网络即grid,每一个block里面有1个thread存在。那么这种选取有什么用意呢,如何针对自己的计算问题设置计算网络呢?

  首先要说明这两个数的选取没有固定的方法,完全是根据自身需求。其实它的完整形式是Kernel<<<Dg,Db, Ns, S>>>(param list);<<<>>>运算符内是核函数的执行参数,告诉编译器运行时如何启动核函数,用于说明内核函数中的线程数量,以及线程是如何组织的。

  参数Dg用于定义整个grid的维度和尺寸,即一个grid有多少个block。为dim3类型。Dim3 Dg(Dg.x, Dg.y, 1)表示grid中每行有Dg.x个block,每列有Dg.y个block,第三维恒为1。整个grid中共有Dg.x*Dg.y个block,其中Dg.x和Dg.y最大值为65535。

  参数Db用于定义一个block的维度和尺寸,即一个block有多少个thread。为dim3类型。Dim3 Db(Db.x, Db.y, Db.z)表示整个block中每行有Db.x个thread,每列有Db.y个thread,高度为Db.z。Db.x和Db.y最大值为512,Db.z最大值为62。 一个block中共有Db.x*Db.y*Db.z个thread。计算能力为1.0,1.1的硬件该乘积的最大值为768,计算能力为1.2,1.3的硬件支持的最大值为1024。

  参数Ns是一个可选参数,用于设置每个block除了静态分配的shared Memory(以后会学习到)以外,最多能动态分配的shared memory大小,单位为byte。不需要动态分配时该值为0或省略不写。

  参数S是一个cudaStream_t类型的可选参数,初始值为零,表示该核函数处在哪个流(以后会学习到)之中。

  在这个例子中,由于计算很简单,就选了一个<<<N,1>>>这种搭配。现在我们看一个复杂一点的例子。

  这个例子是说要计算两个任意长的向量的加法,可能会比比65535长,超过了block数的最大范围,甚至于比65535×512(thread上限)还长,应该怎么办呢?下面就用

<<<128,128>>>的计算网络来搞定。

  核函数改为如下:

  1. __global__ void add( int *a, int *b, int *c ) {
  2. int tid = threadIdx.x + blockIdx.x * blockDim.x;
  3. while (tid < N) {
  4. c[tid] = a[tid] + b[tid];
  5. tid += blockDim.x * gridDim.x;
  6. }
  7. }

  这段代码的精髓就在于它是一个循环,当编号为tid = threadIdx.x + blockIdx.x * blockDim.x的线程进行加法运算之后,tid += blockDim.x * gridDim.x;如果tid<N,则这个线程再做一次加法,依次循环下去。因为计算网络只有blockDim.x * gridDim.x这么大(次例为128×128),那么那些大于blockDim.x * gridDim.x并且小于N的数组分量的相加任务就需要继续分配给各个线程,如上就是用循环来分配的。

  任意长度向量相加完整代码:

  1. /*
  2. * Copyright 1993-2010 NVIDIA Corporation. All rights reserved.
  3. *
  4. * NVIDIA Corporation and its licensors retain all intellectual property and
  5. * proprietary rights in and to this software and related documentation.
  6. * Any use, reproduction, disclosure, or distribution of this software
  7. * and related documentation without an express license agreement from
  8. * NVIDIA Corporation is strictly prohibited.
  9. *
  10. * Please refer to the applicable NVIDIA end user license agreement (EULA)
  11. * associated with this source code for terms and conditions that govern
  12. * your use of this NVIDIA software.
  13. *
  14. */
  15.  
  16. #include "../common/book.h"
  17.  
  18. #define N (33 * 1024)
  19.  
  20. __global__ void add( int *a, int *b, int *c ) {
  21. int tid = threadIdx.x + blockIdx.x * blockDim.x;
  22. while (tid < N) {
  23. c[tid] = a[tid] + b[tid];
  24. tid += blockDim.x * gridDim.x;
  25. }
  26. }
  27.  
  28. int main( void ) {
  29. int *a, *b, *c;
  30. int *dev_a, *dev_b, *dev_c;
  31.  
  32. // allocate the memory on the CPU
  33. a = (int*)malloc( N * sizeof(int) );
  34. b = (int*)malloc( N * sizeof(int) );
  35. c = (int*)malloc( N * sizeof(int) );
  36.  
  37. // allocate the memory on the GPU
  38. HANDLE_ERROR( cudaMalloc( (void**)&dev_a, N * sizeof(int) ) );
  39. HANDLE_ERROR( cudaMalloc( (void**)&dev_b, N * sizeof(int) ) );
  40. HANDLE_ERROR( cudaMalloc( (void**)&dev_c, N * sizeof(int) ) );
  41.  
  42. // fill the arrays 'a' and 'b' on the CPU
  43. for (int i=; i<N; i++) {
  44. a[i] = i;
  45. b[i] = * i;
  46. }
  47.  
  48. // copy the arrays 'a' and 'b' to the GPU
  49. HANDLE_ERROR( cudaMemcpy( dev_a, a, N * sizeof(int),
  50. cudaMemcpyHostToDevice ) );
  51. HANDLE_ERROR( cudaMemcpy( dev_b, b, N * sizeof(int),
  52. cudaMemcpyHostToDevice ) );
  53.  
  54. add<<<,>>>( dev_a, dev_b, dev_c );
  55.  
  56. // copy the array 'c' back from the GPU to the CPU
  57. HANDLE_ERROR( cudaMemcpy( c, dev_c, N * sizeof(int),
  58. cudaMemcpyDeviceToHost ) );
  59.  
  60. // verify that the GPU did the work we requested
  61. bool success = true;
  62. for (int i=; i<N; i++) {
  63. if ((a[i] + b[i]) != c[i]) {
  64. printf( "Error: %d + %d != %d\n", a[i], b[i], c[i] );
  65. success = false;
  66. }
  67. }
  68. if (success) printf( "We did it!\n" );
  69.  
  70. // free the memory we allocated on the GPU
  71. HANDLE_ERROR( cudaFree( dev_a ) );
  72. HANDLE_ERROR( cudaFree( dev_b ) );
  73. HANDLE_ERROR( cudaFree( dev_c ) );
  74.  
  75. // free the memory we allocated on the CPU
  76. free( a );
  77. free( b );
  78. free( c );
  79.  
  80. return ;
  81. }

总结:我们通常选取一定数量的线程来解决问题,通常都选2的倍数。是由grid,block,thread,这种三级结构实现的。一般的程序的计算量都会超过线程数量,因此要合理的把计算量尽量平均分配给各个线程来计算。感觉上来说,编写核函数的精髓就是如何利用线程的序号(索引值)来分配计算任务。

cuda学习2-block与thread数量的选取的更多相关文章

  1. CUDA学习笔记-1: CUDA编程概览

    1.GPU编程模型及基本步骤 cuda程序的基本步骤如下: 在cpu中初始化数据 将输入transfer到GPU中 利用分配好的grid和block启动kernel函数 将计算结果transfer到C ...

  2. CUDA学习,第一个kernel函数及代码讲解

    前一篇CUDA学习,我们已经完成了编程环境的配置,现在我们继续深入去了解CUDA编程.本博文分为三个部分,第一部分给出一个代码示例,第二部分对代码进行讲解,第三部分根据这个例子介绍如何部署和发起一个k ...

  3. CUDA学习之二:shared_memory使用,矩阵相乘

    CUDA中使用shared_memory可以加速运算,在矩阵乘法中是一个体现. 矩阵C = A * B,正常运算时我们运用 C[i,j] = A[i,:] * B[:,j] 可以计算出结果.但是在CP ...

  4. 【CUDA学习】GPU硬件结构

    GPU的硬件结构,也不是具体的硬件结构,就是与CUDA相关的几个概念:thread,block,grid,warp,sp,sm. sp: 最基本的处理单元,streaming processor  最 ...

  5. CUDA学习笔记(四)——CUDA性能

    转自:http://blog.sina.com.cn/s/blog_48b9e1f90100fm5h.html 四.CUDA性能 CUDA中的block被划分成一个个的warp,在GeForce880 ...

  6. CUDA学习笔记(一)【转】

    CUDA编程中,习惯称CPU为Host,GPU为Device.编程中最开始接触的东西恐怕是并行架构,诸如Grid.Block的区别会让人一头雾水,我所看的书上所讲述的内容比较抽象,对这些概念的内容没有 ...

  7. cuda学习1-初始庐山真面目

    cuda作为gpu计算中的代表,拥有着超级高的计算效率,其原因是gpu实际相当与一台超级并行机组,使用过MPI做并行计算的人们可能知道,所谓的并行计算,简单讲就是用多个U(计算单元)来完成一个U的计算 ...

  8. 原 iOS深入学习(Block全面分析)http://my.oschina.net/leejan97/blog/268536

    原 iOS深入学习(Block全面分析) 发表于1年前(2014-05-24 16:45)   阅读(26949) | 评论(14) 39人收藏此文章, 我要收藏 赞21 12月12日北京OSC源创会 ...

  9. CUDA学习之一:二维矩阵加法

    今天忙活了3个小时,竟然被一个苦恼的CUDA小例程给困住了,本来是参照Rachal zhang大神的CUDA学习笔记来一个模仿,结果却自己给自己糊里糊涂,最后还是弄明白了一些. RZ大神对CUDA关于 ...

随机推荐

  1. SIM9001GSM模块教程

    博主最近在做一个项目,用到了GSM模块,博主不是什么单片机大神,只是感觉某宝附带的资料太水,所以上传一些自己写的程序和经验,供需要的人参考 1,拨打电话 /********************** ...

  2. ios animation 动画效果实现

    1.过渡动画 CATransition CATransition *animation = [CATransition animation]; [animation setDuration:1.0]; ...

  3. struts2之拦截器

    1. 为什么需要拦截器 早期MVC框架将一些通用操作写死在核心控制器中,致使框架灵活性不足.可扩展性降低, Struts 2将核心功能放到多个拦截器中实现,拦截器可自由选择和组合,增强了灵活性,有利于 ...

  4. ENetwork Basic Configuration PT Practice SBA

    CCNA Exploration: 网络基础知识 (版本 4.0) A few things to keep in mind while completing this activity: 1 Do  ...

  5. JSSDK微信自定义分享

    背景:15年之前的微信分享只需要加入一段js就可以实现.后来微信官方全部禁止了.现在的微信分享全部得使用jssdk. 一.分享功能: 在微信内(必须在微信里)打开网站页面,分享给朋友或者分享到朋友圈时 ...

  6. 面试题 ARC

    什么是ARC ?ARC主要解决什么问题? ARC:自动引用计数. 要点..当对象被创建时 retain count+1, 当对象被release时 retain count-1, 当retain co ...

  7. FreeBSD上构架Nginx服务器

    这篇文章主要记录作者如何在FreeBSD上构架Nginx服务器.作者采用下载该程序的一个源代码包手动编译的方法,而不是使用包管理工具.这样做有两个原因:首先包质量不能保证,或无效或版本旧:其次需要在编 ...

  8. js函数中this的指向

    本文是我个人对this指向的一些理解,如有不足之处,还望大家可以批评指正,在此先谢过了! 首先,我们来回顾一下ES5里函数的几种调用方式: 1⃣️直接调用 foo(); 2⃣️方法调用 obj.foo ...

  9. [效率]Source insight标题栏中路径显示完整路径的方法

    使用Source insight的时候,默认是不显示文件的全路径的,这一点有那么一段时间让我很纠结,因为很多函数都是基于硬件架构的,一个函数有很多时间.查看文件的全路径是非常有必要,可以通过以下实现: ...

  10. [Git]04 如何使用标签

     Git也可以对某一时间点上的版本打上标签.人们在发布某个软件版本(比如 v1.0 等等)的时候,经常这么做. 本节我们一起来学习如何如何新建标签,列出所有可用的标签,以及各种不同类型标签之间的差 ...