Chart 8 内核优化

文章目录

  • 前言
  • 8.1 内核融合和拆分
  • 8.2 编译选项
  • 8.3 Conformant(规范) vs. fast vs. native math functions
  • 8.4 Loop unrolling
  • 8.5 避免分支发散
  • 8.6 Handle image boundaries
  • 8.7 Avoid the use of size_t
  • 8.8 通用 vs. 具名内存地址空间
  • 8.9 Subgroup
  • 8.10 Use of union
  • 8.11 Use of struct
  • 8.12 综合


前言

这一章节提供了有关内核优化的更多细节,这些内容可能与第6章的顶级优化提示和第7章的内存优化有一些重叠。


8.1 内核融合和拆分

一个复杂的应用可能包含许多阶段。对于进行 OpenCL 移植和优化的情况,人们可能会问应该使用多少个内核。这个问题很难回答,因为涉及到许多因素。以下是一些建议:

  • 在内存和计算之间取得良好的平衡。
  • 有足够的波(waves)来隐藏延迟。
  • 避免寄存器溢出。

开发人员可以尝试以下操作:

  • 将一个大内核拆分成多个小内核可能会更好地实现数据并行化。
  • 将多个内核融合成一个内核(内核融合),如果可以通过良好的并行化来减少数据流量(工作组大小相当大)。

8.2 编译选项

APIs clCompileProgram 和 clBuildProgram 提供了许多编译器构建选项,用于性能优化。借助这些选项,开发人员可以根据其目的启用一些功能。例如,使用 -cl-fast-relaxed-math 将使用快速数学运算编译内核,而不是按照 OpenCL 规范提供的更高精度的数学运算:

clBuildProgram( myProgram, numDevices, pDevices, "-cl-fast-relaxed-math ",NULL, NULL );

Adreno GPU 还可以支持一些特定于 Adreno 的选项,以启用特定功能,详见第 9 章的讨论。

8.3 Conformant(规范) vs. fast vs. native math functions

《OpenCL》标准在OpenCL C语言中定义了许多数学函数。默认情况下,所有的数学函数都必须符合IEEE 754单精度浮点数数学要求,这是OpenCL规范要求的。Adreno GPU具有一个内置的硬件模块,即基本函数单元(EFU),用于加速一些原始数学函数。EFU直接不支持的许多数学函数已经通过结合EFU和ALU操作进行了优化,或者通过编译器使用复杂算法进行了模拟。以下表格显示了基于相对性能对OpenCL-GPU数学函数进行分类的列表。使用高性能函数(例如,类别A中的函数)是一个良好的做法。
在这里插入图片描述

或者,如果应用程序对精度不敏感,开发人员可以使用本地或快速数学而不是符合规范的数学函数。表8-2总结了使用数学函数的这三个选项:
本地数学函数(native math function),由底层硬件(如GPU)本地支持的数学函数

  • 对于快速数学,在clBuildProgram调用中启用-cl-fast-relaxed-math。
  • 使用本地数学函数:
    • 具有本地实现的数学函数有 native_cos、native_exp、native_exp2、native_log、native_log2、native_log10、native_powr、native_recip、native_rsqrt、native_sin、native_sqrt、native_tan、native_divide;
    • 以下是使用本地数学的示例:
      • 原始:int c = a / b; // a和b都是整数
      • 使用本地指令:int c = (int)native_divide((float)(a), (float)(b));
        在这里插入图片描述

8.4 Loop unrolling

循环展开通常是一个良好的实践,因为它可以减少指令执行成本并提高性能。Adreno编译器通常可以根据一些启发式方法自动展开循环。然而,也有可能编译器选择不完全展开循环,这取决于诸如寄存器分配预算之类的因素,或者编译器由于缺乏知识而无法展开。在这些情况下,开发人员可以通过以下方式向编译器提供提示或手动强制展开循环:

  • 一个内核可以通过使用 attribute((opencl_unroll_hint)) 或 attribute((opencl_unroll_hint(n))) 来提供提示。
  • 或者,一个内核可以使用指令 #pragma unroll 来展开循环。
  • 最后的选择是手动展开循环。

8.5 避免分支发散

通常情况下,当同一组(wave)中的工作项(work items)按照不同的执行路径时,GPU的效率并不高。一些工作项可能需要被屏蔽(masked)以适应不同的分支,导致GPU的占用率降低,如下图所示。此外,条件检查的代码,比如if-else,通常会触发控制流硬件逻辑,这是比较昂贵的操作。
在这里插入图片描述
有一些方法可以避免或减少分歧和条件检查。在算法层面上,可以将进入同一分支的工作项分组为一个非分歧的波(wave)。开发者可以将一些简单的分歧或条件检查操作转换为快速的ALU操作。:

  • 第10.3.6节中的一个示例展示了如何将由昂贵的控制流逻辑执行的三元操作转换为快速的ALU操作。
  • 另一种方法是使用像select这样的函数,它可能使用快速的ALU操作而不是控制流逻辑。

8.6 Handle image boundaries

许多操作可能访问图像边界之外的像素。为了更好地处理边界,应考虑以下选项:

  • 如果可能的话,提前对图像进行填充。
  • 使用具有良好取样器的图像对象(纹理引擎会自动处理)。
  • 编写单独的内核来处理边界,或者让CPU处理边界像素。

8.7 Avoid the use of size_t

在许多情况下,64位内存地址对于OpenCL内核编译可能会带来复杂性,开发者必须谨慎。开发者应避免在内核中将变量定义为size_t类型。对于64位操作系统,内核中定义为size_t的变量可能必须被处理为64位长整型。Adreno GPU必须使用两个32位寄存器来模拟64位。因此,具有size_t变量需要更多的寄存器资源,这通常会导致性能下降,因为激活的波浪较少,工作组大小较小。因此,开发者应该使用32位或更短的数据类型,而不是size_t。

对于在OpenCL中返回size_t的内置函数,编译器可能会尝试根据其知识推导并限制其范围。例如,get_local_id返回结果为size_t,尽管local_id永远不会超过32位。在这种情况下,编译器使用了一个较短的数据类型。然而,通常最好为编译器提供最佳的数据类型,以获得更好的寄存器使用和代码质量。

8.8 通用 vs. 具名内存地址空间

自OpenCL 2.0以来引入了一种称为通用内存地址空间的特性。在OpenCL 2.0之前,指针必须指定其内存地址空间,比如local、private或global。通用内存允许在内核中不设置指针的地址空间,GPU会在内核执行期间确定实际的地址空间。这一特性使开发人员能够重用和减少代码基础,尤其适用于库开发等任务。

使用通用内存地址空间可能会带来性能损失,因为与识别内存空间相关的硬件成本。以下是一些建议关于内存地址空间的使用:

  • 如果事先知道,开发人员应明确指定内存地址空间。这将减少编译器的歧义,避免GPU硬件识别实际内存空间的成本。
  • 尽量避免工作项使用不同的内存地址空间。对于统一(固定)的情况,编译器可能能够提取内存空间并避免硬件识别其内存空间。
  • 准备不同内存地址空间的不同版本代码。

8.9 Subgroup

OpenCL 2.0引入的新子组函数提供了比工作组更精细的对工作项的控制。一个工作组包含一个或多个子组,而在Adreno GPU中,子组与波(wave)概念对应。与1D/2D/3D工作组相比,子组只有一个维度。与工作组类似,一组函数允许工作项在子组内查询其本地ID和其他参数。

子组的强大之处在于OpenCL引入了一套丰富的函数,允许子组中的工作项共享数据并在子组内进行各种操作。没有这个特性,工作项之间的数据共享可能不得不依赖于本地或全局内存,而这通常是昂贵的。

如何实现子组功能取决于硬件供应商。它可以通过硬件加速或通过软件仿真来实现。在Adreno GPU中,许多子组功能都是通过硬件加速的。

除了核心OpenCL中的子组功能之外,OpenCL 3.0还有关于子组的KHR扩展。在使用这些扩展之前,检查扩展的可用性是非常重要的。

子组功能大致可以分为两种类型:规约和洗牌。

  • 规约:Adreno具有硬件支持的规约功能,比通过本地内存进行规约要快得多。
  • 洗牌:洗牌允许数据从一个工作项传递到另一个工作项。通常支持shuffle-up, shuffle-down, and generic shuffle.

除了对标准子组函数的支持,Adreno GPU 还通过供应商扩展支持子组规约和洗牌功能。

8.10 Use of union

虽然联合(union)是 OpenCL 内核语言中的一个标准特性,但在 Adreno GPU 上它是低效的。编译器需要分配额外的寄存器来处理不同大小的成员,因此性能通常较不使用联合的常规内核更差。开发者在 Adreno GPU 上应避免使用联合

8.11 Use of struct

结构体(struct)可以使代码更易于理解和组织,是将一组相关变量组织到一个地方的绝佳方式。尽管有这些优点,但在 Adreno GPU 上使用结构体可能会引起一些效率问题,因此不总是建议使用。以下是一些建议:

  • 尽量避免在结构体内部使用指针。
  • 明确分配单个成员,而不是将整个结构体变量分配给另一个变量。
  • SoA(struct of array,结构体,元素是数组) 或 AoS(array of struct,数组,元素是结构体):
    • 一个关键考虑因素是选择是否能够缓解内核的瓶颈。
    • 例如,如果数组可以安排得使得从内存加载数据具有更好的合并性,那么结构体数组是一个更好的选择。
    • 如果结构体中的成员导致良好的缓存局部性,那么数组结构体可能是一个更好的选择。

8.12 综合

许多其他看似细微的优化技巧都可能提高内核性能。以下是开发人员可以尝试的一些事项:

  • 预先计算在内核中不会改变的值。
    • 使用内核计算可以预先计算的值是不划算的。
    • 可以通过内核参数或 #define 将预先计算的值传递给内核。
    • 使用快速整数内建函数。对于 24 位整数乘法,使用 mul24,对于 24 位整数乘法和累加,使用 mad24。
    • Adreno GPU 在硬件上原生支持 mul24,而 32 位整数乘法则需要多于一条指令。
    • 如果整数在 24 位范围内,使用 mul24 比直接的 32 位乘法更快。
  • 减少 EFU(elementary function unit) 函数的使用。
    • 例如,以下是一段代码:
      r = a / select(c, d, b<T)
      
      其中 a、b 和 T 是 float 变量,c 和 d 是常量,可以重写为:
      r = a * select(1/c, 1/d, b<T)
      
      这样避免了 reciprocal(倒数) EFU 函数,因为 1/c 和 1/d 可以在编译时由编译器推导出。
  • 避免除法运算,尤其是整数除法。
    • 在 Adreno GPU 中,整数除法非常昂贵。
    • 不要使用除法,而是使用 native_recip 进行倒数运算,如第 8.3 节所述。
  • 避免使用整数模运算 (mod,取余),这对 Adreno GPU 来说是昂贵的。
  • 对于常量数组,如查找表、滤波器系数等,将它们声明在内核范围之外
  • 在 OpenCL 内核中使用 mem_fence 函数来分隔或组织代码段。
    • 编译器具有从全局优化角度生成最佳代码的复杂算法。
    • mem_fence 可能会阻止编译器在前后混合代码之前进行重排
    • mem_fence 允许开发人员操作一些代码以进行性能分析和调试。
  • 使用16位ALU计算而不是8位。由于Adreno GPU不支持通用的8位ALU操作,8位可能需要转换为16位或32位ALU操作。
  • 如果可能的话,使用位移操作而不是乘法。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/210341.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

SpringSecurity6 | 自定义认证规则

✅作者简介&#xff1a;大家好&#xff0c;我是Leo&#xff0c;热爱Java后端开发者&#xff0c;一个想要与大家共同进步的男人&#x1f609;&#x1f609; &#x1f34e;个人主页&#xff1a;Leo的博客 &#x1f49e;当前专栏&#xff1a; Java从入门到精通 ✨特色专栏&#xf…

移相干涉技术1-多种干涉条纹仿真模拟生成(原理转载+代码实现 包括模拟生成干涉条纹图)

过去的干涉测量技术是通过人的肉眼或者相机拍摄&#xff0c;来直观判断干涉图中条纹特征进而完成测量&#xff0c;该方法的不稳定因素&#xff08;比如人的主观意志&#xff09;很多&#xff0c;其精度误差在/10左右38]&#xff1b;现代干涉测量技术通过将电子技术、计算机技术…

智能优化算法应用:基于厨师算法无线传感器网络(WSN)覆盖优化 - 附代码

智能优化算法应用&#xff1a;基于厨师算法无线传感器网络(WSN)覆盖优化 - 附代码 文章目录 智能优化算法应用&#xff1a;基于厨师算法无线传感器网络(WSN)覆盖优化 - 附代码1.无线传感网络节点模型2.覆盖数学模型及分析3.厨师算法4.实验参数设定5.算法结果6.参考文献7.MATLAB…

一加 12 Pop-up快闪活动来袭,十城联动火爆开启

12 月 9 日&#xff0c;一加 12 Pop-up 快闪活动在北京、深圳、上海、广州等十城联动开启&#xff0c;各地加油欢聚快闪现场&#xff0c;抢先体验与购买一加 12。作为一加十年超越之作&#xff0c;一加 12 全球首发拥有医疗级护眼方案和行业第一 4500nit 峰值亮度的 2K 东方屏、…

C++新经典模板与泛型编程:策略类模板

策略类模板 在前面的博文中&#xff0c;策略类SumPolicy和MinPolicy都是普通的类&#xff0c;其中包含的是一个静态成员函数模板algorithm()&#xff0c;该函数模板包含两个类型模板参数。其实&#xff0c;也可以把SumPolicy和MinPolicy类写成类模板—直接把algorithm()中的两…

【Linux】无法使用 ifconfig 查看系统网络接口信息,报错 command not found: ifconfig

问题描述 ifconfig是一个用于配置和显示系统网络接口信息的命令行工具。它通常用于Unix、Linux和其他类Unix系统中。 通过ifconfig命令&#xff0c;你可以查看和修改系统中网络接口的配置信息&#xff0c;包括IP地址、子网掩码、MAC地址、MTU&#xff08;最大传输单元&#x…

javacv踩坑记录

前一阵学习opencv&#xff0c;发现在做人脸识别的时候遇到一些类库不存在的情况&#xff0c;查找后发现是由于拓展包没有安装完全&#xff08;仅安装了基础版&#xff09;。由于网络的问题&#xff08;初步猜测&#xff09;&#xff0c;始终无法安装好拓展包。 于是另辟蹊径&am…

[文档级关系抽取|ACL论文]文档级关系抽取中语言理解的基础模型

Did the Models Understand Documents? Benchmarking Models for Language Understanding in Document-Level Relation Extraction School of Computer Science, Fudan University | ACL 2023.06 | 原文链接 Background 过去的工作大多数都是从单个句子中收获更多的关系&am…

MongoDB中的$type操作符和limit与skip方法

本文主要介绍MongoDB中的$type操作符和limit与skip方法。 目录 MongoDB的$type操作符MongoDB的limit方法MongoDB的skip方法 MongoDB的$type操作符 MongoDB中的$type操作符用于检查一个字段的类型是否与指定的类型相匹配。它可以用于查询和投影操作。 $type操作符可以与以下数…

JVS低代码表单引擎:数据校验与处理的先锋

随着信息技术的迅速发展&#xff0c;数据校验与处理已经成为了各类应用中不可或缺的一环。尤其是在涉及敏感信息&#xff0c;如密码处理时&#xff0c;其安全性和准确性显得尤为重要。JVS低代码表单引擎提供了强大的文本组件触发逻辑校验功能&#xff0c;它能够在用户填写数据的…

模电·放大电路的分析方法——等效电路法

放大电路的分析方法——等效电路法 晶体管的直流模型及静态工作点的估算法晶体管共射h参数等效模型 h h h参数等效模型的由来参数的物理意义简化的h参数等效模型 r b e {r\tiny be} rbe的近似表达式 共射放大电路动态参数的分析电压放大倍数 A ˙ u \.{A}\tiny u A˙u输入电阻 …

【小米电脑管家】安装使用教程--非小米电脑

安装说明功能体验下载资源 Xiaomi HyperOS发布后&#xff0c;小米妙享电脑端独立版本也走向终点&#xff0c;最新的【小米电脑管家】将会内置妙享实现万物互联。那么本篇文章将分享非小米电脑用户如何绕过设备识别验证安装使用【小米电脑管家】实现万物互联 安装说明 1.解压文…

如何用Python编写俄罗斯方块Tetris游戏?

在本文中&#xff0c;我们将用Python代码构建一个令人惊叹的项目&#xff1a;俄罗斯方块游戏。在这个项目中&#xff0c;我们将使用pygame库来构建游戏。要创建此项目&#xff0c;请确保您的系统中安装了最新版本的Python。让我们开始吧&#xff01; Pygame是一组跨平台的Pyth…

wireshark过滤包小技巧

1、过滤包含某个字符串的数据包&#xff1a; 或者&#xff1a; 2、过滤包含某一连续十六进制的数据包&#xff1a; 或者&#xff1a; 3、过滤精确到位数位置 或者&#xff1a;

关于使用EB tresos出现无法激活的情况解决

EB安装完成时需要激活才能使用的&#xff0c;不然都无法建立工程。 我在安装eb studio时就是在激活方面有问题导致无法使用&#xff0c;下面讲解出现了什么问题以及我如何去解除的。 1.出现的错误提示&#xff1f; ERROR&#xff1a;flexActAPPActivationSend按照在官网中&…

低代码:轻松构建应用程序的新时代

在当今数字化时代&#xff0c;应用程序对于日常企业业务的开展&#xff0c;已经成为一种刚需。然而&#xff0c;应用程序开发的过程往往耗时耗力&#xff0c;对于企业来讲&#xff0c;是一笔不小的成本开支。低代码问世以来&#xff0c;一直在尝试为业务人员赋能&#xff0c;让…

扁平按钮样式

上图 代码&#xff1a; <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><title>扁平按钮</title><style>body {margin: 0;padding: 0;height: 100vh;display: flex;justify-content: center;ali…

Web漏洞-XSS绕过和pikachu靶场4个场景(三)

★★实战前置声明★★ 文章中涉及的程序(方法)可能带有攻击性&#xff0c;仅供安全研究与学习之用&#xff0c;读者将其信息做其他用途&#xff0c;由用户承担全部法律及连带责任&#xff0c;文章作者不承担任何法律及连带责任。 1、XSS漏洞挖掘与绕过 1.1、XSS漏洞挖掘 数据…

排序算法---冒泡排序

1. 原理 对数组进行遍历&#xff0c;每次对相邻的两个元素进行比较&#xff0c;如果大的在前面&#xff0c;则交换两个元素的位置&#xff0c;完成一趟遍历后&#xff0c;数组中最大的数值到了数组的末尾。再对前面n-1个数值进行相同的遍历。一共完成n-1趟遍历就实现了排序。 1…

104. 二叉树的最大深度(Java)

目录 解法&#xff1a; 官方解答&#xff1a; 方法一&#xff1a;深度优先搜索 方法二&#xff1a;广度优先搜索 思路与算法 复杂度分析 时间复杂度&#xff1a; 空间复杂度&#xff1a; 给定一个二叉树 root &#xff0c;返回其最大深度。 二叉树的 最大深度 是指从根…