Chart 8 内核优化

news2024/11/18 20:37:02

文章目录

  • 前言
  • 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.coloradmin.cn/o/1298524.html

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

相关文章

C++ 哈希表实现

目录 前言 一、什么是哈希表 二、直接定值法 三、开放定值法&#xff08;闭散列&#xff09; 1.开放定制法定义 2.开放定制法实现 2.1类的参数 2.2类的构造 2.3查找实现 2.4插入实现 2.5删除实现 2.6string做key 四、哈希桶&#xff08;开散列&#xff09; 1.开散…

让老板成为数据分析师,我用 ChatGpt 链接本地数据源实战测试

本文探究 ChatGpt 等AI机器人能否帮助老板快速的做数据分析&#xff1f;用自然语言同老板进行沟通&#xff0c;满足老板的所有数据分析的诉求&#xff1f; 一、背景 设想这样一个场景&#xff1a;你是某贸易公司的老板&#xff0c;公司所有的日常运转数据都在私域的进销存系统…

tqdm详细教程,实现tqdm进度条完美设计;解决进度条多行一直刷新的问题;如何使得滚动条不上下滚动(保持一行内滚动)

一、tqdm简介 tqdm是一个python进度条库&#xff0c;可以在 Python长循环中添加一个进度提示信息。 二、3种使用方法 1.tqdm(range)-自动更新 import time from tqdm import range# 自动更新 for i in tqdm(range(10)): # 共可以更新10次进度条time. Sleep(0.5) # 每次更新间…

nginx多端口部署

1.配置nginx.conf文件 有几个端口需要部署就写几个server&#xff0c;我这里只部署了两个端口分别为80和81端口&#xff0c;所以有两个server文件。80端口项目入口在根目录的test文件中&#xff0c;81端口项目入口在根目录的test1文件夹中。 2.准备项目文件html文件 在/test1…

2023年终总结-轻舟已过万重山

自我介绍 高考大省的读书人 白&#xff0c;陇西布衣&#xff0c;流落楚、汉。-与韩荆州书 我来自孔孟故里山东济宁&#xff0c;也许是小学时的某一天&#xff0c;我第一次接触到了电脑&#xff0c;从此对它产生了强烈的兴趣&#xff0c;高中我有一个愿望&#xff1a;成为一名计…

【漏洞复现】华脉智联指挥调度平台/xml_edit/fileread.php文件读取漏洞

Nx01 产品简介 深圳市华脉智联科技有限公司&#xff0c;融合通信系统将公网集群系统、专网宽带集群系统、不同制式、不同频段的短波/超短波对讲、模拟/数字集群系统、办公电话系统、广播系统、集群单兵视频、视频监控系统、视频会议系统等融为一体&#xff0c;集成了专业的有线…

【力扣】移除链表元素203

目录 1.前言2. 题目描述3. 题目分析3.1 不带哨兵位3.2 带哨兵位 4. 附代码4.1 不带哨兵位4.2 带哨兵位 1.前言 这里开始介绍从网上一些刷题网站上的题目&#xff0c;在这里做一些分享&#xff0c;和学习记录。 先来介绍一些力扣的OJ题目。 这里的OJ就是我们不需要写主函数&…

SpringBoot的监控(Actuator) 功能

目录 0、官方文档 一、引入依赖 二、application.yml文件中开启监控 三、具体使用 四、具体细节使用 五、端点开启与禁用 六、定制Endpoint 1. 定制 /actuator/health 2. 定制 /actuator/info &#xff08;1&#xff09;直接在配置文件中写死 &#xff08;2&#xff…

【2023传智杯-新增场次】第六届传智杯程序设计挑战赛AB组-ABC题复盘解题分析详解【JavaPythonC++解题笔记】

本文仅为【2023传智杯-第二场】第六届传智杯程序设计挑战赛-题目解题分析详解的解题个人笔记,个人解题分析记录。 本文包含:第六届传智杯程序设计挑战赛题目、解题思路分析、解题代码、解题代码详解 文章目录 一.前言二.赛题题目A题题目-B题题目-C题题目-二.赛题题解A题题解-…

内存学习——堆(heap)

目录 一、概念二、自定义malloc函数三、Debug运行四、heap_4简单分析4.1 heap管理链表结构体4.2 堆初始化4.3 malloc使用4.4 free使用 一、概念 内存分为堆和栈两部分&#xff1a; 栈&#xff08;Stack&#xff09;是一种后进先出&#xff08;LIFO&#xff09;的数据结构&…

STM32-GPIO编程

一、GPIO 1.1 基本概念 GPIO&#xff08;General-purpose input/output&#xff09;通用输入输出接口 --GP 通用 --I input输入 --o output输出 通用输入输出接口GPIO是嵌入式系统、单片机开发过程中最常用的接口&#xff0c;用户可以通过编程灵活的对接口进行控制&#xff0c;…

MATLAB离线附加功能包下载与安装教程

MATLAB离线附加功能包下载与安装教程 本文介绍如何下载与安装MATLAB离线附加功能包,便于大家更加高效的使用MATLAB。 目录 MATLAB离线附加功能包下载与安装教程一、下载1. 获取MATLAB试用版账号2. 使用MATLAB Online搜索所需要的资源包3. 下载所需要的资源包二、安装由于不是…

【QED】井字棋

目录 题目背景题目描述输入格式输出格式测试样例 思路核心代码 题目背景 井字棋&#xff0c;英文名叫Tic-Tac-Toe&#xff0c;是一种在 3 3 3 \times 3 33格子上进行的连珠游戏&#xff0c;和五子棋类似。游戏时&#xff0c;由分别代表O和X的两名玩家轮流在棋盘格子里留下棋子…

uni-app 设置当前page界面进入直接变为横屏模式

首先 我们打开项目的 manifest.json 在左侧导航栏中找到 源码视图 然后找到 app-plus 配置 在下面加上 "orientation": [//竖屏正方向"portrait-primary",//竖屏反方向"portrait-secondary",//横屏正方向"landscape-primary",//横屏…

LIMoE:使用MoE学习多个模态

文章链接&#xff1a;Multimodal Contrastive Learning with LIMoE: the Language-Image Mixture of Experts 发表期刊&#xff08;会议&#xff09;: NeurIPS 2022 目录 1.背景介绍稀疏模型 2.内容摘要Sparse Mixture-of-Experts ModelsContrastive LearningExperiment Analy…

JVM类加载器ClassLoader的源码分析

1、ClassLoader与现有类加载器的关系 ClassLoader与现有类加载器的关系&#xff1a; ClassLoader是一个抽象类。如果我们给定了一个类的二进制名称&#xff0c;类加载器应尝试去定位或生成构成定义类的数据。一种典型的策略是将给定的二进制名称转换为文件名&#xff0c;然后去…

VUEX使用总结

1、Store 使用 文件内容大概就是这三个。通俗来讲actions负责向后端获取数据的&#xff0c;内部执行异步操作分发 Action&#xff0c;调用commit提交一个 mutation。 mutations通过Action提交commit的数据进行提交荷载&#xff0c;使state有数据。 vuex的数据是共享的&#xf…

(三)五种最新算法(SWO、COA、LSO、GRO、LO)求解无人机路径规划MATLAB

一、五种算法&#xff08;SWO、COA、LSO、GRO、LO&#xff09;简介 1、蜘蛛蜂优化算法SWO 蜘蛛蜂优化算法&#xff08;Spider wasp optimizer&#xff0c;SWO&#xff09;由Mohamed Abdel-Basset等人于2023年提出&#xff0c;该算法模型雌性蜘蛛蜂的狩猎、筑巢和交配行为&…

Docker 安装Apache Superset 并实现汉化和快速入门

什么是Apache Superset Apache Superset是一个现代化的企业级商业智能Web应用程序。Apache Superset 支持用户的各种数据类型可视化和数据分析&#xff0c;支持简单图饼图到复杂的地理空间图表。Apache Superset 是一个轻量级、简单化、直观化、可配置的BI 框架。 Docker 安…

Mongodb 添加索引 优化记录

因 每晚12点20分定时任务做数据统计&#xff0c;mongodb 50万条数据开始&#xff0c;每天晚上CPU报警&#xff1a;CPU>95&#xff0c;并耗时3分钟以上. 2023-12-08 00:20:00.023 [Thread-95] INFO c.q.i.q.jobhandler.dataMongoDBXxlJob - 定时生成记录开始 ………… …………