热门标签 | HotTags
当前位置:  开发笔记 > 后端 > 正文

BetterPerformanceatLowerOccupancy(一)使用更少线程隐藏计算延迟

这两天看到VasilyVolkov的ppt,对如何更有效的使用GPU做通用计算提出了增加线程级并行以外的另一种方法---增加指令级并行,受益匪浅。刚好也没找到中文版本,就翻译过来与大家交

这两天看到Vasily Volkov的ppt,对如何更有效的使用GPU做通用计算提出了增加线程级并行以外的另一种方法---增加指令级并行,受益匪浅。刚好也没找到中文版本,就翻译过来与大家交流下,有错误请各位指正,所有的实验结果和图片均出自原ppt。请参考《Better Performance at Lower Occupancy》后面两个案例。

  以下为译文:

  为提升GPU的效率,常用的方法是提升设备占用率(occupancy),包括在每个流处理器上运行更多的线程和为每个线程块设定更多的线程。人们常常认为这是隐藏延迟的唯一方法,但我们的实验结果证明最大化占用率反而可能会降低性能:

  大矩阵相乘,单精度浮点(SGEMM)

  

  1024点复数到复数快速傅里叶变换(FFT),单精度浮点:

  

  两个常见谬误:

  1. 多线程是GPU上隐藏延迟的唯一方法。

  2. 共享内存和寄存器一样快。

  整个报告分成五部分:

  1. 使用更少线程隐藏计算延迟。

  2. 使用更少线程隐藏内存访问延迟。

  3. 使用更少线程来加速。

  4. 案例研究:矩阵相乘。

  5. 案例研究:FFT。

  使用更少线程隐藏计算延迟

  计算的延迟

  延迟:执行操作所需时间。一次计算操作需要约20个时钟周期,一次内存访问操作需要400+个时钟周期:

计算的延迟

  以上代码中计算z时,由于z对x的依赖性,在计算x的延迟期内(约20cycle),该操作无法执行。但y的计算由于没有依赖性,因而可以与x的计算重叠(即在20cycle内执行)。


  计算的吞吐量

  延迟的概念常常与吞吐量的概念混淆,比如“计算比内存操作快100倍----每个warp(G80)只需花费4个时钟周期,而内存操作要花费400个时钟周期”这句话就是错误的,因为前者是比率,而后者是时间。

  吞吐量:每个时钟周期完成多少条指令。

  计算:1.3Tflop/s = 480 ops/cycle (指令每周期) (指令为乘加运算)

  访问显存:177GB/s ≈ 32 ops/cycle (指令为32位装载)

  隐藏延迟:在延迟等待时做其他的操作。这样可以运行更快,但上限为峰值。那么怎样达到峰值呢?

  使用里特尔定律(Little’s law),即 所需并行度=延迟*吞吐量

计算的吞吐量

  那么当前设备的并行度怎样呢?

计算的吞吐量 

  (延迟随指令的不同而变化)

  由于指令的延迟固定,如果没有足够的并行度,就不可能达到100%的吞吐量,也就是说没有足够多的运行中指令,那么就存在空闲指令周期。


  怎样得到足够的并行度?

  线程级并行(TLP):通常做法是使用足够的线程来提供需要的并行度,比如:在G80上每个SM执行192个线程。

怎样得到足够的并行度?

  指令级并行(ILP):但你同样可以在单个线程内利用指令间的并行性来达到足够的并行度。

怎样得到足够的并行度?

  你可以在GPU上同时使用ILP和TLP。

  这个规则适用于所有可以运行CUDA的GPU。

  比如在G80上,如果没有ILP,你可以通过25%的GPU占用率达到100%的峰值;或者,在每个线程中有三条指令可以同时进行的情况下,通过8%的GPU占用率达到峰值。

  而在GF104上,如果要达到66%以上的峰值性能,你则必须应用IPL,因为:每个SM中有48个核,单条指令每次广播给16个核。而为了使每个核都有指令执行,单个时钟周期内必须分发3条指令,但事实上每个SM中只有2个warp调度器,无法分发3条指令。所以NV在这里提供了ILP,每个warp在同一指令周期内却可以分发两条以上的指令,这就给我们提供了使每个核都有指令执行的方法。


  我们用实验来证明:

  1.不用ILP来运行大量计算指令

实验证明

  将N_ITERATIONS设定为一个很大的数,选择合适的UNROLL,并保证a,b,c都存储在寄存器中。执行一个block(即只使用一个SM),选择不同的线程块大小,检测所能达到的性能:

实验证明

  GPU为GTX480,理论峰值为1.3Tflop/s,一个SM就是89.6Gflop/s(1.3T/15, GTX480中有15个SM)

  可以看到,如果没有ILP,一个SM上需要576个线程才能达到100%的利用率

  2. 引入指令级并行

  实验ILP=2时,即每个线程执行2条相互独立的指令,

实验证明

  那么如果使用更多线程是在GPU上隐藏延迟的唯一方法,则我们应该得到相同的性能曲线,事实上:

实验证明

  虚线标出的是原本曲线,可以看出:

  当ILP=2时,只需要320个线程就能达到100%的利用率

  加入更多的指令级并行:

  当ILP=3时,每个线程3条独立指令:

实验证明

  得到的结果是:

实验证明

  即当ILP=3时,只需要256个线程就可以达到100%利用率。

  不幸的是,当ILP超过4时,就不会再扩展了(lz:猜想每个warp在一个时钟周期内最多就只能分发4条指令了)

实验证明

  当ILP=4时,需要192个线程就能达到100%的利用率。


  总结

  可以通过两种方法隐藏计算延迟

  实验证明

  这条同样适用于其他GPU,比如G80架构

  实验证明

  谬误:提升占用率是隐藏延迟的唯一方法?错误,提升ILP是另一种方法。

  谬误:占用率是衡量GPU利用率的标准?错误,它只是一个影响因素。

  谬误:“为完全隐藏计算延迟,流处理器必须在计算能力为1.x的设备上运行至少192个线程,或者在计算能力为2.0的设备上运行384个线程”(出自CUDA Best Practices Guide)。错误,在G80-GT200上通过64个线程,在GF100上通过192个线程同样可以达到目的。


推荐阅读
  • Java和JavaScript是什么关系?java跟javaScript都是编程语言,只是java跟javaScript没有什么太大关系,一个是脚本语言(前端语言),一个是面向对象 ... [详细]
  • 本文介绍了Python爬虫技术基础篇面向对象高级编程(中)中的多重继承概念。通过继承,子类可以扩展父类的功能。文章以动物类层次的设计为例,讨论了按照不同分类方式设计类层次的复杂性和多重继承的优势。最后给出了哺乳动物和鸟类的设计示例,以及能跑、能飞、宠物类和非宠物类的增加对类数量的影响。 ... [详细]
  • 篇首语:本文由编程笔记#小编为大家整理,主要介绍了软件测试知识点之数据库压力测试方法小结相关的知识,希望对你有一定的参考价值。 ... [详细]
  • ejava,刘聪dejava
    本文目录一览:1、什么是Java?2、java ... [详细]
  • 【Windows】实现微信双开或多开的方法及步骤详解
    本文介绍了在Windows系统下实现微信双开或多开的方法,通过安装微信电脑版、复制微信程序启动路径、修改文本文件为bat文件等步骤,实现同时登录两个或多个微信的效果。相比于使用虚拟机的方法,本方法更简单易行,适用于任何电脑,并且不会消耗过多系统资源。详细步骤和原理解释请参考本文内容。 ... [详细]
  • 知识图谱——机器大脑中的知识库
    本文介绍了知识图谱在机器大脑中的应用,以及搜索引擎在知识图谱方面的发展。以谷歌知识图谱为例,说明了知识图谱的智能化特点。通过搜索引擎用户可以获取更加智能化的答案,如搜索关键词"Marie Curie",会得到居里夫人的详细信息以及与之相关的历史人物。知识图谱的出现引起了搜索引擎行业的变革,不仅美国的微软必应,中国的百度、搜狗等搜索引擎公司也纷纷推出了自己的知识图谱。 ... [详细]
  • 如何用UE4制作2D游戏文档——计算篇
    篇首语:本文由编程笔记#小编为大家整理,主要介绍了如何用UE4制作2D游戏文档——计算篇相关的知识,希望对你有一定的参考价值。 ... [详细]
  • JavaScript设计模式之策略模式(Strategy Pattern)的优势及应用
    本文介绍了JavaScript设计模式之策略模式(Strategy Pattern)的定义和优势,策略模式可以避免代码中的多重判断条件,体现了开放-封闭原则。同时,策略模式的应用可以使系统的算法重复利用,避免复制粘贴。然而,策略模式也会增加策略类的数量,违反最少知识原则,需要了解各种策略类才能更好地应用于业务中。本文还以员工年终奖的计算为例,说明了策略模式的应用场景和实现方式。 ... [详细]
  • 使用Ubuntu中的Python获取浏览器历史记录原文: ... [详细]
  • 本文介绍了Hyperledger Fabric外部链码构建与运行的相关知识,包括在Hyperledger Fabric 2.0版本之前链码构建和运行的困难性,外部构建模式的实现原理以及外部构建和运行API的使用方法。通过本文的介绍,读者可以了解到如何利用外部构建和运行的方式来实现链码的构建和运行,并且不再受限于特定的语言和部署环境。 ... [详细]
  • 本文介绍了Perl的测试框架Test::Base,它是一个数据驱动的测试框架,可以自动进行单元测试,省去手工编写测试程序的麻烦。与Test::More完全兼容,使用方法简单。以plural函数为例,展示了Test::Base的使用方法。 ... [详细]
  • 我所理解的JMM 2 new原子性
    概述文本探讨构造函数是否为原子性问题。案例我们首先如下代码:publicclassPerson{publicintage;publicPerson(){age ... [详细]
  • 第七课主要内容:多进程多线程FIFO,LIFO,优先队列线程局部变量进程与线程的选择线程池异步IO概念及twisted案例股票数据抓取 ... [详细]
  • POCOCLibraies属于功能广泛、轻量级别的开源框架库,它拥有媲美Boost库的功能以及较小的体积广泛应用在物联网平台、工业自动化等领域。POCOCLibrai ... [详细]
  • Java编程思想一书中第21章并发中关于线程间协作的一节中有个关于汽车打蜡与抛光的小例子(原书的704页)。这个例子主要展示的是两个线程如何通过wait ... [详细]
author-avatar
手机用户2502870863
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有