http://blog.csdn.net/canhui_wang/article/details/51730264

摘要

本文主要讲述CUDA的threadIdx。

1. Grid,Block和Thread三者的关系

其中,一个grid包含多个blocks,这些blocks的组织方式可以是一维,二维或者三维。任何一个block包含有多个Threads,这些Threads的组织方式也可以是一维,二维或者三维。举例来讲:比如上图中,任何一个block中有10个Thread,那么,Block(0,0)的第一个Thread的ThreadIdx是0,Block(1,0)的第一个Thread的ThreadIdx是11;Block(2,0)的第一个Thread的ThreadIdx是21,......,依此类推,不难整理出其中的映射公式(表达式已在代码中给出)。

2. GridID,BlockID,ThreadID三者的关系

ThreadID是线性增长的,其目的是用于在硬件和软件上唯一标识每一个线程。CUDA程序中任何一个时刻,每一个线程的ThreadIdx都是特定唯一标识的!grid,block的划分方式不同,比如一维划分,二维划分,或者三维划分。显然,Threads的唯一标识ThreadIdx的表达方式随着grid,block的划分方式(或者说是维度)而不同。下面通过程序给出ThreadIdx的完整的表达式。其中,由于使用的时候会考虑到GPU内存优化等原因,代码可能也会有所不同,但是threadId的计算的表达式是相对固定的。

  1. /**************************************************************/
  2. // !!!!!!!!!!!!!!注意!!!!!!!!!!!!!!!!
  3. /**************************************************************/
  4. // grid划分成a维,block划分成b维,
  5. // 等价于
  6. // blocks是a维的,Threads是b维的。
  7. // 这里,本人用的是第一中说法。
  8. /**************************************************************/
  9. // 情况1:grid划分成1维,block划分为1维。
  10. __device__ int getGlobalIdx_1D_1D() {
  11. int threadId = blockIdx.x *blockDim.x + threadIdx.x;
  12. return threadId;
  13. }
  14. // 情况2:grid划分成1维,block划分为2维。
  15. __device__ int getGlobalIdx_1D_2D() {
  16. int threadId = blockIdx.x * blockDim.x * blockDim.y
  17. + threadIdx.y * blockDim.x + threadIdx.x;
  18. return threadId;
  19. }
  20. // 情况3:grid划分成1维,block划分为3维。
  21. __device__ int getGlobalIdx_1D_3D() {
  22. int threadId = blockIdx.x * blockDim.x * blockDim.y * blockDim.z
  23. + threadIdx.z * blockDim.y * blockDim.x
  24. + threadIdx.y * blockDim.x + threadIdx.x;
  25. return threadId;
  26. }
  27. // 情况4:grid划分成2维,block划分为1维。
  28. __device__ int getGlobalIdx_2D_1D() {
  29. int blockId = blockIdx.y * gridDim.x + blockIdx.x;
  30. int threadId = blockId * blockDim.x + threadIdx.x;
  31. return threadId;
  32. }
  33. // 情况5:grid划分成2维,block划分为2维。
  34. __device__ int getGlobalIdx_2D_2D() {
  35. int blockId = blockIdx.x + blockIdx.y * gridDim.x;
  36. int threadId = blockId * (blockDim.x * blockDim.y)
  37. + (threadIdx.y * blockDim.x) + threadIdx.x;
  38. return threadId;
  39. }
  40. // 情况6:grid划分成2维,block划分为3维。
  41. __device__ int getGlobalIdx_2D_3D() {
  42. int blockId = blockIdx.x + blockIdx.y * gridDim.x;
  43. int threadId = blockId * (blockDim.x * blockDim.y * blockDim.z)
  44. + (threadIdx.z * (blockDim.x * blockDim.y))
  45. + (threadIdx.y * blockDim.x) + threadIdx.x;
  46. return threadId;
  47. }
  48. // 情况7:grid划分成3维,block划分为1维。
  49. __device__ int getGlobalIdx_3D_1D() {
  50. int blockId = blockIdx.x + blockIdx.y * gridDim.x
  51. + gridDim.x * gridDim.y * blockIdx.z;
  52. int threadId = blockId * blockDim.x + threadIdx.x;
  53. return threadId;
  54. }
  55. // 情况8:grid划分成3维,block划分为2维。
  56. __device__ int getGlobalIdx_3D_2D() {
  57. int blockId = blockIdx.x + blockIdx.y * gridDim.x
  58. + gridDim.x * gridDim.y * blockIdx.z;
  59. int threadId = blockId * (blockDim.x * blockDim.y)
  60. + (threadIdx.y * blockDim.x) + threadIdx.x;
  61. return threadId;
  62. }
  63. // 情况9:grid划分成3维,block划分为3维。
  64. __device__ int getGlobalIdx_3D_3D() {
  65. int blockId = blockIdx.x + blockIdx.y * gridDim.x
  66. + gridDim.x * gridDim.y * blockIdx.z;
  67. int threadId = blockId * (blockDim.x * blockDim.y * blockDim.z)
  68. + (threadIdx.z * (blockDim.x * blockDim.y))
  69. + (threadIdx.y * blockDim.x) + threadIdx.x;
  70. return threadId;
  71. }

3. GPU Threads与CPU Threads的比较

GPU Threads的生成代价小,是轻量级的线程;CPU Threads的生成代价大,是重量级的线程。CPU Threads虽然生成的代价高于GPU Threads,但其执行效率高于GPU Threads,所以GPU Threads无法在个体的比较上取胜,只有在数量上取胜。在这个意义上来讲,CPU Threads好比是一头强壮的公牛在耕地,GPU Threads好比是1000头弱小的小牛在耕地。因此,为了保证体现GPU并行计算的优点,线程的数目必须足够多,通常至少得用上1000个GPU线程或者更多才够本,才能很好地体现GPU并行计算的优点!

4. GPU Threads的线程同步

线程同步是针对同一个block中的所有线程而言的,因为只有同一个block中的线程才能在有效的机制中共同访问shared memory。要知道,由于每一个Thread的生命周期长度是不相同的,Thread对Shared Memory的操作可能会导致读写的不一致,因此需要线程的同步,从而保证该block中所有线程同时结束。

GPU CUDA之——深入理解threadIdx的更多相关文章

  1. GPU,CUDA,cuDNN的理解

    最近用到这方面的知识,感觉这篇文章写的很好,为了方便自己查阅,就搬运了过来,如果牵涉到侵权,请联系我,我会删除该博文!!! 我们知道做深度学习离不开GPU,不过一直以来对GPU和CPU的差别,CUDA ...

  2. 真实机下 ubuntu 18.04 安装GPU +CUDA+cuDNN 以及其版本选择(亲测非常实用)【转】

    本文转载自:https://blog.csdn.net/u010801439/article/details/80483036 ubuntu 18.04 安装GPU +CUDA+cuDNN : 目前, ...

  3. GPU CUDA编程中threadIdx, blockIdx, blockDim, gridDim之间的区别与联系

    前期写代码的时候都会困惑这个实际的threadIdx(tid,实际的线程id)到底是多少,自己写出来的对不对,今天经过自己一些小例子的推敲,以及找到官网的相关介绍,总算自己弄清楚了. 在启动kerne ...

  4. [GPU] CUDA for Deep Learning, why?

    又是一枚祖国的骚年,阅览做做笔记:http://www.cnblogs.com/neopenx/p/4643705.html 这里只是一些基础知识.帮助理解DL tool的实现. 最新补充:我需要一台 ...

  5. OpenCV GPU CUDA OpenCL 配置

    首先,正确安装OpenCV,并且通过测试. 我理解GPU的环境配置由3个主要步骤构成. 1. 生成关联文件,即makefile或工程文件 2. 编译生成与使用硬件相关的库文件,包括动态.静态库文件. ...

  6. GPU CUDA 经典入门指南

    转自:http://luofl1992.is-programmer.com/posts/38830.html CUDA编程中,习惯称CPU为Host,GPU为Device.编程中最开始接触的东西恐怕是 ...

  7. GPU/CUDA程序初体验 向量加法

    现在主要的并行计算设备有两种发展趋势: (1)多核CPU. 双核,四核,八核,...,72核,...,可以使用OpenMP编译处理方案,就是指导编译器编译为多核并行执行. (2)多线程设备(GP)GP ...

  8. ubuntu16.04+caffe+GPU+cuda+cudnn安装教程

    步骤简述: 1.安装GPU驱动(系统适配,不采取手动安装的方式) 2.安装依赖(cuda依赖库,caffe依赖) 3.安装cuda 4.安装cudnn(只是复制文件加链接,不需要编译安装的过程) 5. ...

  9. GPU && CUDA:主机和设备间数据传输测试

    数据传输测试,先从主机传输到设备,再在设备内传输,再从设备传输到主机. H-->D D-->D D-->H // moveArrays.cu // // demonstrates C ...

随机推荐

  1. jQuery 整体架构

    不同于 jQuery 代码各个模块细节实现的晦涩难懂,jQuery 整体框架的结构十分清晰,按代码行文大致分为如上图所示的模块. 初看 jQuery 源码可能很容易一头雾水,因为 9000 行的代码感 ...

  2. Java - 如何进行安全发布

    首先让我简单解释一下所谓"发布". 发布(publish),使对象可以在当前作用域之外的代码中可见,如果该对象被发布,则该对象的非私有域中引用的所有实例同样也会被发布. 不仅仅是作 ...

  3. 数据结构(四)--- 红黑树(RedBlock-Tree)

      文章图片来自邓俊辉老师课件 先提几个问题去思考学习本文 : 红黑树和2-4树(B-Tree)很像,那么它存在的动机又是什么呢 插入和删除操作的逻辑又是怎么样的,时间和空间复杂度可以达到怎么样 和 ...

  4. 在 Azure 上创建和链接 Azure SQL 数据库

    本快速入门介绍了如何在 Azure 门户中创建并连接 Azure SQL 数据库.在本教程中完成的所有操作均符合 1 元试用条件. 开始之前 如果您还没有 Azure 账户,可以申请 1 元试用账户. ...

  5. 通过winmm.dll控制声音播放

    介绍如何通过winmm.dll播放声音 首先导入两个函数 /// <summary> /// 向媒体控制接口发送控制命令 /// </summary> /// <para ...

  6. 【原创】MapReduce程序如何在集群上执行

    首先了解下资源调度管理框架Yarn. Yarn的结构(如图): Resource Manager (rm)负责调度管理整个集群上的资源,而每一个计算节点上都会有一个Node Manager(nm)来负 ...

  7. String.replace使用技巧

    relace replace() 方法返回一个由替换值替换一些或所有匹配的模式后的新字符串.模式可以是一个字符串或者一个正则表达式, 替换值可以是一个字符串或者一个每次匹配都要调用的函数. 使用字符串 ...

  8. Hibernate 脏检查和刷新缓存机制

    刷新缓存: Session是Hibernate向应用程序提供的操作数据库的主要接口,它提供了基本的保存,更新,删除和加载java对象的方法,Session具有一个缓存,可以管理和追踪所有持久化对象,对 ...

  9. js实现字体和容器宽高随窗口改变

    用于字体大小和容器的宽高字体和宽高设为rem就可以了 var html = document.documentElement; function fonts(){ var hW = html.offs ...

  10. Javascript 多物体淡入淡出(透明度变化)

    <!DOCTYPE html><html> <head> <meta charset="UTF-8"> <title>& ...