前面扯了很多,不过大多都是在讲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/


【并行计算-CUDA开发】CUDA软件架构与Nvidia硬件对应关系的更多相关文章

  1. CUDA开发 - CUDA 版本

    "CUDA runtime is insufficient with CUDA driver"CUDA 9.2: 396.xx CUDA 9.1: 387.xx CUDA 9.0: ...

  2. 【并行计算与CUDA开发】英伟达硬件加速编解码

    硬件加速 并行计算 OpenCL OpenCL API VS SDK 英伟达硬件编解码方案 基于 OpenCL 的 API 自己写一个编解码器 使用 SDK 中的编解码接口 使用编码器对于 OpenC ...

  3. 【并行计算-CUDA开发】英伟达硬件解码器分析

    这篇文章主要分析 NVCUVID 提供的解码器,里面提到的所有的源文件都可以在英伟达的 nvenc_sdk 中找到. 解码器的代码分析 SDK 中的 sample 文件夹下的 NvTranscoder ...

  4. 【并行计算与CUDA开发】英伟达硬件加速解码器在 FFMPEG 中的使用

    目录(?)[-] 私有驱动 编译 FFMPEG 使用 nvenc 这篇文档介绍如何在 ffmpeg 中使用 nvenc 硬件编码器. 私有驱动 nvenc 本身是依赖于 nvidia 底层的私有驱动的 ...

  5. 【视频开发】【CUDA开发】FFMPEG硬件加速-nvidia方案

    1.目标 <1>显卡性能参数: <2>方案可行性: 2.平台信息 2.1.查看当前显卡信息 命令:  lspci |grep VGA  信息:  01:00.0 VGA com ...

  6. 【视频开发】【CUDA开发】ffmpeg Nvidia硬件加速总结

    原文链接:https://developer.nvidia.com/ffmpeg GPU-accelerated video processing integrated into the most p ...

  7. 【并行计算-CUDA开发】有关CUDA当中global memory如何实现合并访问跟内存对齐相关的问题

    ps:这是英伟达二面面的一道相关CUDA的题目.<NVIDIA CUDA编程指南>第57页开始          在合并访问这里,不要跟shared memory的bank conflic ...

  8. 【CUDA开发】CUDA的安装、Nvidia显卡型号及测试

    说明:想要让Theano在Windows8.1下能利用GPU并行运算,必须有支持GPU并行运算的Nvidia显卡,且要安装CUDA,千万不要电脑上是Intel或AMD的显卡,却要编写CUDA. 文中用 ...

  9. Windows平台CUDA开发之前的准备工作

    CUDA是NVIDIA的GPU开发工具,眼下在大规模并行计算领域有着广泛应用. windows平台上面的CUDA开发之前.最好去NVIDIA官网查看说明,然后下载对应的driver. ToolKits ...

随机推荐

  1. NodeList对象的特点

    nodeList对象的特点1,nodeList是一种类数组对象,用于保存一组有序的节点.2,通过方括号来访问nodeList的值,有item方法与length属性.3,它并不是Array的实例,没有数 ...

  2. Nginx 转发特点URL到指定服务

    location ^~ /fs/ {#如https://xx.com/fs/upload 转发到文件服务器 proxy_pass http://127.0.0.1:8080/fs/; }

  3. Java学习 1.5——静态Static的作用与用法

    在网上查阅资料,静态大约分为这几部分:修饰成员变量:修饰成员方法:静态代码块:静态导包,下面会用代码一一展示: 修饰成员变量: 一个类中,使用static修饰成员变量后,该变量变为全局变量,当再次ne ...

  4. Break 和 Continue 语句

    break 语句用于跳出循环. continue 用于跳过循环中的一个迭代. 1.break关键字可以用来退出switch或循环语句   不能在IF语句中使用break和continue 示例:在if ...

  5. Python基础--01小项目体现的基础知识

    part1:猜拳游戏 #coding=utf-8 #当有汉语时可能编译器不认识,需要定义代码 ''' 多行注释 写这个程序是为了熟悉python的基本语法 这是第一个小例子包含简单的if判断,循环和输 ...

  6. B/S上传大文件的解决方案

    第一点:Java代码实现文件上传 FormFile file = manform.getFile(); String newfileName = null; String newpathname =  ...

  7. IntelliJ IDEA 运行项目的时候提示 Command line is too long 错误

    在 IntelliJ IDEA 项目运行的时候收到了下面的错误提示: Error running 'Application': Command line is too long. Shorten co ...

  8. jquery-常用事件

  9. @ConfigurationProperties实现配置注入到实体类

    spring boot 使用@ConfigurationProperties 有时候有这样子的情景,我们想把配置文件的信息,读取并自动封装成实体类,这样子,我们在代码里面使用就轻松方便多了,这时候,我 ...

  10. iTerm2使用Profiles自动登录

    http://blog.csdn.net/wandershi/article/details/75088310 1.创建Profiles文件 cd ~/.ssh/iTerm2SSH/ vi 172.1 ...