《Better Performance at Lower Occupancy》解读

背景

  • CUDA的通常建议在SM或者Block中使用更多的线程来隐藏访存时延。
    但是作者提出 这 种 方 式 可 能 不 是 完 全 正 确 的 这种方式可能不是完全正确的
    有关occupancy的含义:The multiprocessor occupancy is the ratio of active warps to the
    maximum number of warps supported on a multiprocessor of the GPU
  • 作者列举了两个实验数据来说明这件事情,结果一目了然:
    在这里插入图片描述
    作者提出使用CUDA编程时的两点谬论:
  1. 多线程是隐藏时延仅有的一种方式。这里的时延包括两种:一种是算数延时;一种是访存延时
  2. shared memroy 和 register 的访存速度一样快

优化点1:使用更少的线程来隐藏计算延时

首先将计算延迟与访存延迟做一个对比,计算延迟要比访存延迟要快将近100倍,一次计算大概花费4cycles,而一次访存需要花费400cycles。
当操作之间有依赖的时候计算延迟就会影响程序的性能,比如下面的例子:
在这里插入图片描述
由于1、2两条语句没有依赖关系因此可以并行执行;而1、3语句有依赖关系,因此3语句必须要等待1语句运行完毕才能执行,因此这种串行时延带来的计算时延影响了此程序的效率。
那么如何隐藏计算时延呢?常规的方式就是在一个计算单元或block中放置多个不同任务的线程。

线程并行度(TLP)与指令集并行度(ILP)对GPU的影响

如下图所示,图1中在指令集并行度等于1的时候在一定范围内使用越多的线程GPU利用率就越高;图2中当在一定线程并行度的情况下,在一定范围内使用越多的指令并行度GPU利用率就越高
在这里插入图片描述
从这两个图中作者提出针对CUDA的一些编程优化的谬误,并对其做出了完善。
**谬误1:**只有提高occupancy(也就是提高线程数量)才能改善计算延迟。
从图中也可以看出,通过提高指令集并行度也可以改善计算延迟
谬误2: occupancy(线程数量)是唯一决定GPU利用率的因素。从图中显而易见,指令并行度也会影响GPU的利用率。
通过一句话来总结的话就是,之前的使用忽略了指令并行度。也就是通过增加线程之外的指令并行也可以提高资源利用率。

优化点2:隐藏内存延时

需要使用的并行度的量化公式为:

Need parallelism = Latency * Throughput

为了达到一定的吞吐,计算与访存所对应的需要并行度为:
在这里插入图片描述
那么为了达到100KB需要多少的线程数量呢?通常有以下几种方法:

  • 使用多线程
  • 使用指令并行,一个线程做更多的工作

相关的实验结果为:
在这里插入图片描述
谬误3: 在使用较少线程的时候不能隐藏内存延时,因此会降低性能。
从图2中可以看出仅仅使用4%的occupancy可以到达的最大 背景

  • CUDA的通常建议在SM或者Block中使用更多的线程来隐藏访存时延。但是作者提出 这 种 方 式 可 能 不 是 完 全 正 确 的 这种方式可能不是完全正确的 - 作者列举了两个实验数据来说明这件事情,结果一目了然:在这里插入图片描述作者提出使用CUDA编程时的两点谬论:1. 多线程是隐藏时延仅有的一种方式。这里的时延包括两种:一种是算数延时;一种是访存延时2. shared memroy 和 register 的访存速度一样快### 优化点1:使用更少的线程来隐藏计算延时首先将计算延迟与访存延迟做一个对比,计算延迟要比访存延迟要快将近100倍,一次计算大概花费4cycles,而一次访存需要花费400cycles。当操作之间有依赖的时候计算延迟就会影响程序的性能,比如下面的例子:在这里插入图片描述由于1、2两条语句没有依赖关系因此可以并行执行;而1、3语句有依赖关系,因此3语句必须要等待1语句运行完毕才能执行,因此这种串行时延带来的计算时延影响了此程序的效率。那么如何隐藏计算时延呢?常规的方式就是在一个计算单元或block中放置多个不同任务的线程。#### 线程并行度(TLP)与指令集并行度(ILP)对GPU的影响如下图所示,图1中在指令集并行度等于1的时候在一定范围内使用越多的线程GPU利用率就越高;图2中当在一定线程并行度的情况下,在一定范围内使用越多的指令并行度GPU利用率就越高在这里插入图片描述从这两个图中作者提出针对CUDA的一些编程优化的谬误,并对其做出了完善。谬误1:只有提高occupancy(也就是提高线程数量)才能改善计算延迟。从图中也可以看出,通过提高指令集并行度也可以改善计算延迟谬误2: occupancy(线程数量)是唯一决定GPU利用率的因素。从图中显而易见,指令并行度也会影响GPU的利用率。通过一句话来总结的话就是,之前的使用忽略了指令并行度。也就是通过增加线程之外的指令并行也可以提高资源利用率。### 优化点2:隐藏内存延时需要使用的并行度的量化公式为:cppNeed parallelism = Latency * Throughput为了达到一定的吞吐,计算与访存所对应的需要并行度为:在这里插入图片描述那么为了达到100KB需要多少的线程数量呢?通常有以下几种方法:- 使用多线程- 使用指令并行,一个线程做更多的工作相关的实验结果为:在这里插入图片描述谬误3: 在使用较少线程的时候不能隐藏内存延时,因此会降低性能。从图2中可以看出仅仅使用4%的occupancy可以到达的最大的Utilization能达到84%。
    通过这一点可以看出来提高指令并行度可以实现在低线程下的高使用率。

使用更少的线程跑得更快

更少的线程意味着一个线程可以使用更多的寄存器

因为此ppt做的比较早,所以对比了两种很早的GPU类型,从图中的数据看出,使用更少的occupancy可以使用到更多的寄存器。
在这里插入图片描述
通过寄存器可以达到峰值吞吐,不同层次存储之间带宽见下图:
在这里插入图片描述
谬误4: 一个warp中的线程访问shared mem和访问寄存器一样快当没有bank冲突的时候。从上图看到并非如此,shared mem的带宽要比寄存器低6倍。因此通过更多的寄存器访问来代替共享内存访问可以提高程序的性能。

矩阵乘法为例:验证通过更小的occupancy与使用更多的寄存器来优化性能。

  • baseline代码:
    在这里插入图片描述

  • 每个线程4 输出代码:
    在这里插入图片描述

  • 4输出的吞吐可以达到1.76倍的加速

  • 使用更少的occupancy可以达到更好的性能

  • 通过此方式可以达到的最大吞吐为838 Gflop/s,平均每个线程有36个输出、33% occupancy、平均每个SM有2个线程块。

outputs per thread 对吞吐和occupancy的影响

下图显而易见,提高outputs per thread可以提高Gflops同时会减少occupancy。
在这里插入图片描述

总结

  • 每个线程做更多的工作(提高计算并行度)可以隐藏计算时延
  • 使用更少的线程可以使用更多的寄存器,减少shared mem的访问
  • 实现以上两种优化的方式是可以提高每个线程的多输出。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值