zl程序教程

您现在的位置是:首页 >  其它

当前栏目

CUDA优化冷知识22|测量Occupancy的三种方式

优化 方式 知识 三种 22 测量 CUDA
2023-06-13 09:11:37 时间

这一系列文章面向CUDA开发者来解读《CUDA C Best Practices Guide》 (CUDA C最佳实践指南)

CUDA优化冷知识21|occupancy越高越好么?

CUDA优化冷知识20|不改变代码本身如何提升性能?

一般的来说, occupancy往往有个折中点, 过高了或者过低了性能都不好. (就如同你干得过少, 或者干得过累都不好一样). 好了, 我们有了occupancy的概念, 知道了无需一味的去追逐occupancy, 就已经是一个很大的胜利了. 我们下面将具体看一下, 如何测量, 调节occupancy, 并从理论的角度看下它们可能带来的性能变化。

手册里先说了计算/测量occupancy的三个方式, 然后再说了调节一些资源的使用, 会occupancy造成怎样的变化可以反映出来。

我们先看看手册说的occupancy的测量/计算方式. 这个其实以前在编程指南手册上也有涉及, 只是可能没有今天的这样的系统一点。

一种是纯手工计算, 纯手工计算是指的人为的设定或者找到某kernel的, 寄存器使用量, shared memory使用量, block里的线程数量这三种因素/资源的使用后,通过和手册中的特定计算能力下的这三种资源的情况(该表在编程指南手册的后面有)对比, 从而手工的计算出来一个理论的occupancy.

这种方式不需要任何工具, 而且可以在你敲代码的时候, 自然的在大脑中提前形成大致的轮廓. 坏处是比较枯燥, 而且你需要比较熟悉特定计算能力的情况, 才能大致的对比出来你的kernel, 将来在该计算能力的卡上运行, 会得到一个怎样的理论occupancy。

第二种计算/测量occupancy的方式, 则是使用工具. 具体的可以分成静态的一个Excel文件(即本章节的图中的occupancy calculator的那个.xlsx文件),在里面选好了寄存器资源, shared memory资源, block中的线程数量, 和对应的计算能力后, 该.xlsx文件中的宏, 会自动为你计算一下.

该静态的计算工具文件好处是可以免除记忆特定计算能力的参数, 而且还提供了一些高级参数(手册所没有提供的), 例如特定计算能力的某些资源是按照什么方式/粒度分配的信息. 同时不需要安装复杂的开发环境, 例如你可以将此excel文件复制到手机上打开, 或者上传到OFFICE365, 一样可以随时随地使用。坏处是你依然需要手工去测量/计算这3个基本资源, 在你的kernel下的具体使用量, 才能进行后续计算。

而同时也存在另外一种工具, 动态的分析工具, 指的是nsight或者nvprof类似这种的profiler, 它们会在你的kernel运行起来后, 自动为你抓取到这个信息, 从而免除了3个基本数据的手工取得, 也免除了后续的计算过程, 全自动。坏处则是你只能取得你所拥有的计算能力的卡(例如, 一张8.6的30HX显卡(尚未问世, 我们假定的30HX是最近的8.6计算能力)), 在此卡上实际运行时候的数据,你无法取得你所没有拥有的一张计算能力的卡上的情况. 但是手工计算和用Excel计算都是可以算出来一张不存在的卡上的情况的。

对于公司开发的情况, 例如拥有所有的要出售的产品所针对的, 市场上的所有代的计算能力的卡或者Jetson产品, 都购买回来的情况的时候(每种至少一个), 则无需担忧这种。这是第二种用工具的方式.

而第三种则比较主动一点了, 可以编程的通过相应的occupancy api (见cuda runtime api的手册, 或者我们之前的编程指南的稍微提到的部分内容), 在运行的时候, 动态的获取到我的某kernel, 在现在的某卡(例如3号卡上), 用XXX的资源配置或者线程形状, 能取得百分之多少的occupancy。

这种方式坏处是需要用户编程, 增加了额外的编码负担(和出错的可能). 好处则是, 你的代码可以在将来的卡上, 在开发的时候无论纸面或者实际的资料都没有的情况下, 在未来的某一天实际运行的时候, 代码自我分析和发现得到occupancy. 例如将来在一张30HX上, 此卡尚未问世, 我们也不知道计算能力的情况, 但是用第三种API的方式, 将来可以动态的得到, 从而潜在的能动态的(用代码)微调occupancy。

好了. 这是关于取得/测量Occupancy的三种方式, 今天我们简单的说了, 寄存器资源的限制, Occupancy的意义和高低对性能的可能影响, 以及, Occupancy的具体测量/计算方式。这三个因素其实还挺重要的,很多时候我们写代码, 当算法固定了, 实现也基本固定的情况下, 想调节性能, 只能从这3种基本不太影响现有不的代码格局的方面入手。所以关于这3方面的优化调节, 也往往排在算法-->实现--->(今天的执行/配置方面的调节)这么的一个重要顺序.

因为例如有更好的排在前面的情况, 例如一个快10倍的算法, 你应当先去考虑选择它, 而不是今天的这些"优化方面",你很难简单的通过"优化"去将一个GPU上的应用性能继续提升10X, 但是更换算法, 你有可能。所以大家在实际使用中, 不要舍本逐末, 应当至少什么是最先考虑的. 只有当最先考虑的因素都完成后, 再进行这些介绍的经验和手册告诉你的实践操作. 就如同刚才说的某妹子, 她如果直接嫁一个100倍有钱的老公, 还管这些一天怎么干活, 怎么做事? 后面的这些将毫无意义.

我们在下次的内容中, 将会具体结合寄存器, shared memory, block形状这三种因素, 综合occupancy分析, 3因素 vs occupancy vs 性能的情况.

最新活动: