zoukankan      html  css  js  c++  java
  • 【并行计算-CUDA开发】CUDA软件架构与Nvidia硬件对应关系

    前面扯了很多,不过大多都是在讲CUDA 在软体层面的东西;接下来,虽然Heresy 自己也不熟,不过还是来研究一下硬体的部分吧~毕竟要最佳化的时候,好像还是要大概知道一下相关的东西的。这部分主要参考资料是:

    在研究硬体架构前,可能须要先回去看《nVidia CUDA简介》,稍微回顾一下在CUDA中thread、thread block、block grid的意义:一个CUDA的平行化的程式会被以许多个thread来执行,数个thread会被群组成一个block,而多个thread block则会再构成grid。也就是一个kernel程式会有一个grid,grid底下有数个block,每个block都是一群thread的群组。而在同一个block中的thread可以透过shared memory来沟通,也可以同步。

    硬体基本架构

    实际上在nVidia的GPU里,最基本的处理单元是所谓的SP(Streaming Processor),而一颗nVidia的GPU里,会有非常多的SP可以同时做计算;而数个SP会在附加一些其他单元,一起组成一个SM(Streaming Multiprocessor)。几个SM则会在组成所谓的TPC(Texture Processing Clusters)。 
    在G80/G92的架构下,总共会有128个SP,以8个SP为一组,组成16个SM,再以两个SM为一个TPC,共分成8个TPC来运作。而在新一代的GT200里,SP则是增加到240个,还是以8个SP组成一个SM,但是改成以3个SM组成一个TPC,共10组TPC。下面则是提供了两种不同表示方式的示意图。(可参考《NVIDIA G92终极状态!!》、《NVIDIA D10U绘图核心》)

    对应到CUDA

    而在CUDA 中,应该是没有TPC 的那一层架构,而是只要根据GPU 的SM、SP 的数量和资源来调整就可以了。

    如果把CUDA 的Grid – Block – Thread 架构对应到实际的硬体上的话,会类似对应成GPU – Streaming Multiprocessor ??– Streaming Processor;一整个Grid 会直接丢给GPU 来执行,而Block 大致就是对应到SM, thread 则大致对应到SP。当然,这个讲法并不是很精确,只是一个简单的比喻而已。

    SM 中的Warp 和Block

    CUDA的device实际在执行的时候,会以Block为单位,把一个个的block分配给SM进行运算;而block中的thread,又会以「warp」为单位,把thread来做分组计算。目前CUDA的warp大小都是32,也就是32个thread会被群组成一个warp来一起执行;同一个warp里的thread,会以不同的资料,执行同样的指令。此外,在Compute Capability 1.2的硬体中,还加入了warp vote的功能,可以快速的进行warp内的简单统计。

    基本上warp 分组的动作是由SM 自动进行的,会以连续的方式来做分组。比如说如果有一个block 里有128 个thread 的话,就会被分成四组warp,第0-31 个thread 会是warp 1、32-63 是warp 2、64-95 是warp 3、96-127 是warp 4。

    而如果block 里面的thread 数量不是32 的倍数,那他会把剩下的thread 独立成一个warp;比如说thread 数目是66 的话,就会有三个warp:0-31、32-63、64-65 。由于最后一个warp 里只剩下两个thread,所以其实在计算时,就相当于浪费了30 个thread 的计算能力;这点是在设定block 中thread 数量一定要注意的事!

    一个SM 一次只会执行一个block 里的一个warp,但是SM 不见得会一次就把这个warp 的所有指令都执行完;当遇到正在执行的warp 需要等待的时候(例如存取global memory 就会要等好一段时间),就切换到别的warp 来继续做运算,借此避免为了等待而浪费时间。所以理论上效率最好的状况,就是在SM 中有够多的warp 可以切换,让在执行的时候,不会有「所有warp 都要等待」的情形发生;因为当所有的warp 都要等待时,就会变成SM 无事可做的状况了~

    下图就是一个warp 排程的例子。一开始是先执行thread block 1 的warp1,而当他执行到第六行指令的时候,因为需要等待,所以就会先切到thread block 的warp2 来执行;一直等到存取结束,且刚好有一个warp 结束时,才继续执行TB1 warp1 的第七行指令。

    实际上,warp 也是CUDA 中,每一个SM 执行的最小单位;如果GPU 有16 组SM 的话,也就代表他真正在执行的thread 数目会是32*16 个。不过由于CUDA 是要透过warp 的切换来隐藏thread 的延迟、等待,来达到大量平行化的目的,所以会用所谓的active thread 这个名词来代表一个SM 里同时可以处理的thread 数目。

    而在block 的方面,一个SM 可以同时处理多个thread block,当其中有block 的所有thread 都处理完后,他就会再去找其他还没处理的block 来处理。假设有16 个SM、64 个block、每个SM 可以同时处理三个block 的话,那一开始执行时,device 就会同时处理48 个block;而剩下的16 个block 则会等SM 有处理完block 后,再进到SM 中处理,直到所有block 都处理结束。

    建议的数值?

    在Compute Capability 1.0/1.1中,每个SM最多可以同时管理768个thread(768 active threads)或8个block(8 active blocks);而每一个warp的大小,则是32个thread,也就是一个SM最多可以有768 / 32 = 24个warp(24 active warps)。到了Compute Capability 1.2的话,则是active warp则是变为32,所以active thread也增加到1024。

    在这里,先以Compute Capability 1.0/1.1 的数字来做计算。根据上面的数据,如果一个block 里有128 个thread 的话,那一个SM 可以容纳6 个block;如果一个block 有256 个thread 的话,那SM 就只能容纳3 个block。不过如果一个block 只有64 个thread 的话,SM 可以容纳的block 不会是12 个,而是他本身的数量限制的8 个。

    因此在Compute Capability 1.0/1.1的硬体上,决定block大小的时候,最好让里面的thread数目是warp数量(32)的倍数(可以的话,是64的倍数会更好);而在一个SM里,最好也要同时存在复数个block。如果再希望能满足最多24个warp的情形下,block里的thread数目似乎会是96(一个SM中有8个block)、128(一个SM中有6个block)、192(一个SM中有4个block)、256(一个SM中有3个block)这些数字了~ 
    而官方的建议则是一个block里至少要有64个thread,192或256个也是通常比较合适的数字(请参考Programming Guide) 。

    但是是否这些数字就是最合适的呢?其实也不尽然。因为实际上,一个SM 可以允许的block 数量,还要另外考虑到他所用到SM 的资源:shared memory、registers 等。在G80 中,每个SM 有16KB 的shared memory 和8192 个register。而在同一个SM 里的block 和thread,则要共用这些资源;如果资源不够多个block 使用的话,那CUDA 就会减少Block 的量,来让资源够用。在这种情形下,也会因此让SM 的thread 数量变少,而不到最多的768 个。

    比如说如果一个thread 要用到16 个register 的话(在kernel 中宣告的变数),那一个SM 的8192 个register 实际上只能让512 个thread 来使用;而如果一个thread 要用32 个register,那一个SM 就只能有256 个thread 了~而shared memory 由于是thread block 共用的,因此变成是要看一个block 要用多少的shread memory、一个SM 的16KB 能分给多少个block 了。

    所以虽然说当一个SM里的thread越多时,越能隐藏latency,但是也会让每个thread能使用的资源更少因此,这点也就是在最佳化时要做取舍的了。

    转自:

    http://kheresy.wordpress.com/2008/07/09/cuda-%E7%9A%84-threading%EF%BC%9Ablock-%E5%92%8C-grid-%E7%9A%84%E8%A8%AD%E5%AE%9A%E8%88%87-warp/

  • 相关阅读:
    out/host/linuxx86/obj/EXECUTABLES/aapt_intermediates/aapt 64 32 操作系统
    linux 查看路由器 电脑主机 端口号 占用
    linux proc进程 pid stat statm status id 目录 解析 内存使用
    linux vim 设置大全详解
    ubuntu subclipse svn no libsvnjavahl1 in java.library.path no svnjavahl1 in java.library.path no s
    win7 安装 ubuntu 双系统 详解 easybcd 工具 不能进入 ubuntu 界面
    Atitit.json xml 序列化循环引用解决方案json
    Atitit.编程语言and 自然语言的比较and 编程语言未来的发展
    Atitit.跨语言  文件夹与文件的io操作集合  草案
    Atitit.atijson 类库的新特性设计与实现 v3 q31
  • 原文地址:https://www.cnblogs.com/huty/p/8517846.html
Copyright © 2011-2022 走看看