【论文阅读】Retargeting and Respecializing GPU Workloads for Performance Portability

摘要

  为了接近峰值性能,像gpu这样的加速设备需要大量的特定于架构的调优,以了解共享内存、并行性、tensor core等的可用性。不幸的是,对更高性能和更低成本的追求导致了架构设计的显著多样化,甚至是产自同一供应商的产品也是如此。这就产生了跨不同gpu的性能可移植性需求,这对于具有特定体系结构的特定编程模型中的程序尤其重要。即使程序可以在不同的体系结构上无缝地执行,但它也可能遭受性能损失,因为它没有根据可用的硬件资源(如快速内存和寄存器)适当地调整大小,更不用说没有使用体系结构的新高级特性了。
  我们提出了一种新的方法,通过自动调整每个并行线程所做的工作量,以及它所需的内存和寄存器资源的数量,来提高现代机器上(遗留)CUDA程序的性能。通过在MLIR编译器基础架构内操作,我们还能够通过执行CUDA的自动转换来将AMD gpu作为转换目标,并同时调整程序粒度以适应目标gpu的大小
  结合平台特定编译器辅助的自动调优,我们的方法在Rodinia基准套件上比baseline CUDA实现提高了27%的geomean速度,并且在其他相似的NVIDIA平台上和AMD gpu上执行相同CUDA程序,其两个平台的性能相当.

本文为了解决两问题:

  1. 同一编程模型(同一平台),不同硬件架构或硬件参数,实现性能可移植。
  2. 不同编程模型(不同平台),实现代码翻译,性能可移植。

介绍

GPU 硬件的演变
CUDA 编程模型和语法随时间相对稳定,但底层 GPU 硬件已经显著发展,增加了许多新特性和指令。
性能可移植性问题
即使 CUDA 编写的 GPU 内核能够在更新的 NVIDIA GPU 上运行,它们也可能因为kernel尺寸与目标架构不匹配而无法达到类似的利用率。
编译器机制的提出
作者提出了一种基于编译器的机制,通过自动调整每个 GPU 线程的工作量以及内存和寄存器资源的使用量,来“调整”GPU 程序以适应特定架构。
MLIR 编译器基础设施
该工作基于 MLIR 编译器基础设施,利用 Polygeist 编译器将 CUDA 代码翻译成目标无关的表示,并进行自动调整。
性能提升和目标 GPU 的适配
结合编译器后端的自动调优,所提出的方法在 Rodinia 基准测试套件上有显著的性能提升,并在类似的 NVIDIA 和 AMD GPU 上执行相同的 CUDA 程序时实现了性能一致性。

利用现有的CUDA代码,编译器自动调节程序粒度、每个线程的工作量、以及内存和寄存器的数量,而无需更改编程模型。

  1. 将CUDA代码转成基于mlir的与目标无关的IR表示
  2. 使用thread 或者block的coarsening来控制每个线程的工作量和内存资源
  3. 能够自动地将原本为 NVIDIA GPU 编写的 CUDA 程序重新定位(retarget)或适配(adapt),使其能够在 AMD GPU 上运行。
  4. 最后对接到后端编译器,获取较低级别的信息(寄存器数量和溢出量),这使得在编译时自动调整过滤掉性能低下的程序,根据这个运行时间也可得到最优的粒度。

背景

  GPU编程模型和架构,主要讲解GPU的执行结构、合并访存、Occupancy、性能可移植;

合并访存:当warp中的线程执行load时,可以进行coalesced,如果满足某些要求(load size,strided,global offset),这将load到menory中执行更少的内存事务,从而减小最小的带宽。
Occupancy:SM上活动的线程 / SM所能驻留的最大线程数,其达到最大时未必是性能最高时,因为

  Polygeist/MLIR 中的 GPU 编译,主要讲解MLIR,Polygetist,thread coarsening

Polygetist:是一个 C++ 编译器和使用 MLIR 构建的扩展。引入了一种基于 MLIR 的 GPU barrier同步原语编译器抽象,可实现 GPU 到 CPU 的转译和barrier优化。

在这里插入图片描述

thread coarsening:增加每个线程处理数据的量,通过隐藏访存操作的延迟来提高GPU性能,有时会因为引入strided memory阻碍coalesced load或增加寄存器压力,从而降低 GPU occupancy。

Polygetist-GPU pipeline 概述

  Polygeist 以提供接受 CUDA 代码、执行优化和kernel粒度选择并针对 NVIDIA 和 AMDGPU 的端到端 GPU 编译器。我们将CPU端与GPU端代码的编译结合在一起,从而允许同时更新kernel配置和启动以及kernel代码本身。具体就是将 GPU 代码的 MLIR 表示内联到 CPU 代码中,且使用显式的并行循环表示(scf.parallel,不同于gpu.launch),可直接进行循环分析和优化。kernel将由特定于目标的程序进行概述和处理。通过 MLIR 中可用的pipeline来生成作为全局数据嵌入到 IR 中的特定于目标的二进制文件。最后,剩余的主机代码由特定于目标的pipeline进行处理,用各自GPU的runtime调用,替换掉gup_warppers,并且使用LLVM进一步降低为自包含的优化二进制。
在这里插入图片描述
在这里插入图片描述

嵌套并行循环的UNROLL-AND-INTERLEAVE

  研究嵌套并行循环的经典循环展开变换,同时处理 GPU 式的barrier synchronization。fig6为循环因子为2的for循环展开;for循环进行展开后,有语句运行的绝对先后顺序的限制,而并行循环只需要满足语句的相对先后顺序即可。
在这里插入图片描述
在这里插入图片描述

A.嵌套控制流:Unroll、Jam 和 Interleave

在这里插入图片描述

B.Synchronization

  现在考虑 Interleave 情况下的嵌套循环的主体,fig10所示。barrier 的变化需要进行转换,以保留 barrier 所保护语句的相对顺序。这个条件可以通过将来自不同迭代的语句副本分组在一起来满足,fig10 左侧所示。此外,最终变得连续的几个 barrier 可以轻松地用一个 barrier 替换。相反,如果 barrier 重复,例如,当不同的block运行不同次数的内循环迭代时,外循环的展开和交错可能会变得非法,fig10 右。因此,如果 GPU 块具有嵌套控制流,并且条件在编译时未知,则我们不会将转换应用于与 GPU 块相对应的并行循环。
在这里插入图片描述

C.多维循环

  CUDA 编程模型使程序员能够将指定block和grid可以划分为三个维度:x、y 和 z。因此,kernel中的并行循环是具有 3 个(或更少)维度的多并行。 同时也提出了应该在哪些维度执行thread and block coarsening的问题。其提供了两种方法来实现这一点。第一,可以指定多并行的总coarsening factor,并且 Polygeist-GPU 将尝试在不具有恒定大小1的维度上平衡因子(例如,对于总因子 16,我们将用 4、2 和 2 粗化 3 个维 度分别,而对于 6,我们将使用 3、2 和 1 进行粗化。). 另一种选择是显式指定 x、y 和 z 因子。

Coarsening 作为粒度变化

A.Thread Coarsening(线程粗化)

  定义:线程粗化是一种优化技术,通过增加每个线程处理的工作量来减少线程的数量。这意味着每个线程将执行更多的工作单元,从而减少总的线程数,但保持块(block)的大小不变
  目的:通过隐藏内存访问延迟和提高线程的占用率(occupancy),从而提高GPU内核的性能。

B.Block Coarsening(块粗化)

  定义:块粗化是另一种优化技术,通过增加每个块处理的工作量来减少块的数量。这通常涉及到减少网格(grid)的尺寸,但保持每个块中的线程数不变
  目的:通过减少同步操作和提高内存访问效率,以及更有效地利用GPU的执行资源,来提升性能。

C.Block and Thread Coarsening之间的权衡

  与线程粗化不同,块粗化结合了来自不同块的共享内存分配,增加了共享内存的使用。 这可能会提高那些未充分利用共享内存或带宽的kernel的性能,但在那些使用大量共享内存的kernel可能会降低性能,因为共享内存成为了主要的occupancy限制因素。请注意,这两种粗化都会增加每个线程的寄存器使用量,这是另一个occupancy限制因素,但无法在特定于平台的编译器之外直接控制。
  根据实现的不同,线程粗化可能会通过引入跨步访问模式(strided)而干扰kernel中最初存在的coalescing-friendly访问模式。块粗化保留了独立block中存在的内存访问模式。
  当粗化因子不是并行循环上限(loop upper)的除数时,会出现如何执行剩余迭代的额外问题。 当执行线程粗化时,剩余的迭代必须在同一块内执行,以保持块内同步。然而,执行剩余工作的额外线程会干扰在线程之间平衡工作负载,从而确保以完整的warp进行运行,并引入收敛分支执行的复杂性。由于这些原因,我们将线程粗化因子限制为仅上限的约数
  相反,在进行块粗化时, 我们生成一个完成块其余部分的工作的 epilogue kernel。因此,块粗化可以扩展到任何粗化因子,而不仅仅是上限的除数。由于线程粗化减少了每个块的线程数量,因此大的粗化因子或最初具有很少线程的block可能最终运行的线程数量少于warp的线程数。这将导致并行线程利用率不足和性能下降。类似地,块粗化减少了网格中块的数量,这可能会导致kernel的block数小于 SM,并导致相应的性能下降。
  我们的初步观察表明,kernel通常被设计为尽可能利用block级别的并行性,因此更多的并行性,从而可以在该级别找到粗化机会。 最后,可以将块粗化和线程粗化结合起来,以结合优点或减轻缺点。

在这里插入图片描述

这里主要分析了两种粗化的利弊,以及之间的权衡,包括了粗化对内存和寄存器的影响,以及粗化因子的选取

Alternative Code Path

  由于 Unroll 和 Interleave 转换是在相对较高的抽象级别上执行的,因此我们在中间表示中引入了替代区域(alternative regions)的概念, 以提供对编译时多版本控制的支持。然后,我们可以将具有不同因子的块和线程粗化应用于不同的区域,以便每个区域以不同的粒度进行相同的计算。这使我们能够推迟选择最佳替代方案,直到编译pipeline中较低级别的抽象提供足够详细的信息(例如,有关寄存器使用的信息)为止。否则,我们将不得不开发一个高抽象级别的性能模型,并致力于很大程度上不精确的启发式方法来选择最佳粗化因子。
  实际上,替代方案以新的 multi-region MLIR 操作表示(fig12)。它们是在我们的流程中通过简单地多次复制kernel body region,并对不同region应用不同因子的粗化而产生的。然后,编译pipeline可以正常进行,每个region分别进行optimized和lowered,直到达到以下决策点之一。
在这里插入图片描述

共享内存使用的早期剪枝:

  鉴于静态共享内存必须预先分配,大小在编译时已知,我们可以在生成替代方案后立即对其进行分析,以计算所使用的共享内存总量。此时可以丢弃所需要共享内存超过目标硬件上可用内存的替代方案

kernel统计:

  在并行循环表示中,我们可以使用闭式表达式收集循环中的算术和内存操作数量的信息,如果编译时循环边界未知,则使用符号表示。在LLVM表示中,我们还可以额外收集GPU控制流中的分支操作数量信息,众所周知,分支操作会负面影响性能,因为控制流发散可能表现为依次执行分支,同时将不相关的线程屏蔽掉。

这段话描述了编译过程中如何收集和分析GPU kernel代码的性能和相关信息,这里涉及到两个阶段的代码表示:

  1. 并行循环表示:在这个阶段,编译器分析并行循环并计算其中的算术和内存操作数量。如果循环的边界在编译时不能确定(即循环次数可能依赖于运行时的数据),则使用符号表达式来表示这些未知的边界。
  2. LLVM表示:在LLVM的中间表示阶段,除了继续分析算术和内存操作外,编译器还会关注控制流中的分支操作。分支操作可能会引起性能问题,因为它们可能导致线程执行路径的分歧。在GPU编程中,理想的状况是所有线程尽可能执行相同的指令路径,以避免资源浪费。如果分支操作导致某些线程执行了其他线程不需要执行的代码路径(即“不相关线程被屏蔽”),这可能会导致GPU执行单元的利用率下降,从而降低整体性能。

  最后,使用特定于平台的后端(例如 ptxas)将表示形式编译为二进制,为我们提供有关寄存器使用和溢出、估占用率等的信息。我们丢弃在此阶段产生新溢出的替代方案,因为 GPU 上的溢出会将数据放入本地内存(loaction memory)比寄存器慢几个数量级。

Timing-Driven Optimization (TDO) or 自动调优

  最后,通过初步过滤的替代方案将作为独立kernels包含在最终的二进制文件中。我们的编译器提供了一种"性能分析(profiling)"模式,在该模式下,编译器会生成额外的逻辑代码,这些代码能够允许在编译时或运行时选择不同的实现版本(alternative implementations)。每个替代方案都可以在不同的数据上执行一次或多次,以测量平均执行时间,然后选择性能最佳的一个。然后可以再次调用编译器以删除所有其他替代方案并提供单一版本,而无需额外调度。

实验

  Combining Block and Thread Coarsening:将两种coarsening结合使用,并与单独只进行一种coarsening进行比较。
在这里插入图片描述
在这里插入图片描述

  Comparison against a Mainstream CUDA Compiler:将Polygeist编译器生成的代码与主流CUDA编译器(clang)生成的代码进行性能比较。
在这里插入图片描述

  Translation to AMD: hipify+clang vs. Polygeist-GPU:使用编译器表示的CUDA代码在AMD gpu上运行的自动翻译,并将其与baseline的source-to-source方法进行比较。
在这里插入图片描述

实验结果

  1. 结合使用线程粗化和块粗化在多个内核上系统地优于仅使用其中一种粗化技术。
  2. Polygeist编译器在优化后相比于clang编译器在不同NVIDIA GPU上实现了17%至27%的性能提升。 在AMD
  3. GPU上,Polygeist编译器自动翻译的CUDA代码相比于hipify工具翻译的代码在性能上取得了16%至17%的提升。

实验结论

  1. 粗化技术能够根据目标硬件的特性调整程序的执行粒度,从而提高性能。
  2. Polygeist编译器证明了其在跨不同GPU架构(包括NVIDIA和AMD)的性能可移植性方面的优势。

最后附上链接

论文连接:https://domke.gitlab.io/paper/ivan-retargeting-2024.pdf
Polygeist项目源码:https://github.com/llvm/Polygeist

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

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

相关文章

Apache CloudStack Official Document 翻译节选(七)

关于 Apache CloudStack 的 最佳实践 (一) Best Practices 部署Apache CloudStack是极具挑战性的,在整个部署过程中需要你做出形形色色的技术性选择。Apache CloudStack的配置条目是相当灵活的,这是因为在组合和配置具体条目时有…

【深入浅出Docker】【三】Docker容器详解

文章目录 一. Docker容器简介二. Docker容器详解1. 容器vs虚拟机1.1. 虚拟机模型1.2. 容器模型1.3. 虚拟机的额外开销 2. 容器启动过程描述3. 容器进程4. 容器生命周期与文件保存5. 优雅地停止容器:两阶段方式停止并删除容器6. 利用重启策略进行容器的自我修复6.1. …

SpringBoot依赖之Spring Data Redis实现位图Bitmap

Spring Boot 项目中使用 Spring Data Redis 实现位图Bitmap 暂未发表,记录于20240820 概念 Spring Data Redis (AccessDriver) 依赖名称: Spring Data Redis (AccessDriver)功能描述: Advanced and thread-safe Java Redis client for synchronous, asynchronous,…

学习 node.js 六 Markdown 转为 html,zlib

目录 Markdown 转为 html 安装 ejs语法 标签含义 1. 纯文本标签 2. 输出经过 HTML 转义的内容 3. 输出非转义的内容(原始内容) marked browserSync zlib gzip deflate gzip 和 deflate 区别 http请求压缩 Markdown 转为 html 什么是markdown? Markdo…

分享思源笔记的几个骚操作

文章目录 思维导图复习法效果视频制作过程使用方法 大纲复习方法制作过程 人工智能简易使用效果制作过程 思维导图复习法 效果视频 bandicam20240817222246034.mp4 制作过程 首先下载【写味】主题或者是[自定义块样式]插件 他两个的区别是 思维导图以列表形式写出来 选择转…

【2025校招】4399 NLP算法工程师笔试题

目录 1. 第一题2. 第二题3. 第三题 ⏰ 时间:2024/08/19 🔄 输入输出:ACM格式 ⏳ 时长:2h 本试卷分为单选,自我评价题,编程题 单选和自我评价这里不再介绍,4399的编程题一如既往地抽象&#xff…

redis AOF机制

在redis运行期间,不断将redis执行的写命令写到文件中,redis重启之后,只要将这些命令重复执行一遍就可以恢复数据。因为AOF只是将少量的写命令写入AOF文件中,因此其执行效率高于RDB,开启AOF即使Redis发生故障&#xff0…

前端使用miniO上传文件

项目背景:vue2&#xff0c;前提是请先安装miniO,若安装引入时报错&#xff0c;那就是版本不对&#xff0c;通常指定版本安装即可。 页面样式&#xff1a; 前端vue页面代码&#xff1a; //<el-form>表单中:<el-form-item label"文件" prop"fileIds&q…

TY6802 同步整流PCB设计注意事项

TY6802 系列是一款用于反激式电源次级同步整流芯片&#xff0c;TY6802能可靠支持包括 DCM、CCM和准谐振模式。TY6802 集成了一个 100V 功率 MOSFET&#xff08;TY6802A&#xff1a;100V15mR; TY6802B&#xff1a;100V10mR; TY6802C&#xff1a;100V7.5mR;) &#xff0c;可以取代…

API容易被攻击,如何做好API安全

随着互联网技术的飞速发展和普及&#xff0c;网络安全问题日益严峻&#xff0c;API&#xff08;应用程序接口&#xff09;已成为网络攻击的常见载体之一。API作为不同系统之间数据传输的桥梁&#xff0c;其安全性直接影响到整个系统的稳定性和数据的安全性。 根据Imperva发布的…

JavaScript(25)——BOM、延迟函数、JS执行机制

BOM BOM是浏览器对象模型 window对象是一个全局对象&#xff0c;也就是JavaScript中的顶级对象所有通过var定义的全局作用域中的变量&#xff0c;函数都会变成window对象的属性和方法window对象下的属性和方法调用的时候可以省略window 延时函数 let a setTimeout(回调函数…

OLED整体刷新到结合switch刷新方式演变

OLED整体刷新到结合switch刷新方式演变 引言 OLED刷新模式, 其实很简单, 就和prinf输出一样, 只是我们这里利用OLED来输出我们所需要的东西了。 至于OLED单独整体刷新, 还是利用switch刷新, 都是形而上学, 形的东西, 至于底层, 江协科技大佬已经帮我整理好了, 我们是站在巨人的…

【Python零基础学习】字典

文章目录 前言一、简单字典示例二、使用字典三、字典遍历四、嵌套总结 前言 Python 字典 是一种非常强大且灵活的数据结构&#xff0c;它允许你通过键&#xff08;key&#xff09;来存储和检索值&#xff08;value&#xff09;。想象一下&#xff0c;字典就像一个巨大的电话簿…

8月21日微语报,星期三,农历七月

8月21日微语报&#xff0c;星期三&#xff0c;农历七月十八&#xff0c;工作愉快&#xff0c;生活喜乐&#xff01; 一份微语报&#xff0c;众览天下事&#xff01; 1、今日出发&#xff01;中国体育代表团将分两批出征巴黎残奥会。 2、股价再创新高&#xff01;工商银行市值…

suricata编译安装和运行

目录 编译安装 运行 调试 编译安装 apt -y install autoconf automake build-essential cargo \ libjansson-dev libpcap-dev libpcre2-dev libtool \ libyaml-dev make pkg-config rustc zlib1g-dev apt-get install libpcre3-dev wget https://www.openin…

项目实战--SpringBoot整合EasyExcel实现数据导入导出

SpringBoot整合EasyExcel实现数据导入导出 一、前言二、实践2.1 实体类注解方式2.2 动态参数化导出导入 一、前言 在公司业务系统开发过程中&#xff0c;操作 Excel 实现数据的导入导出是个非常常见的需求。 最近公司的项目采用EasyPoi来实现的&#xff0c;但是在数据量大的情…

GPT-SoVITS

文章目录 model archS1 ModelS2 model model arch S1 model: AR model–ssl tokensS2 model: VITS&#xff0c;ssl 已经是mel 长度线性相关&#xff0c;MRTE(ssl_codes_embs, text, global_mel_emb)模块&#xff0c;将文本加强相关&#xff0c;学到一个参考结果 S1 Model cla…

Linux进程间通信——SystemV消息队列与信号量

文章目录 消息队列信号量同步互斥原语、原子性信号量多线程并发访问锁 消息队列 SystemV除了共享内存之外&#xff0c;还有一个进程间通信的方式&#xff0c;是消息队列 我们说一切进程间通信的方式本质其实就是让不同进程看到同一份资源 这个消息队列的本质其实就是让两个进…

十二步:像玩游戏一样搞量化,量化交易不是“黑神话”

十二步&#xff1a;像玩游戏一样搞量化&#xff0c;量化交易不是“黑神话” 1、定义您的目标2、数据收集和清理3、构思4、模型开发5、回测6、风险管理7、交易成本分析 (TCA)8、模拟交易9、优化10、执行11、监控和维护12、记录和审查结论 《黑神话&#xff1a;悟空》今日上线了&…

OSPF-基础多区域实验

1.ENSP下载 阿里云盘分享 ⭐/*无需密钥 免费下载 安装不成功&#xff0c;可关注并私信博主*/ 2.OSPF的基础需求和规则 实验规则&#xff1a; 1.接口地址→XY.XY.XY.R /24 X:两者之间最小的 Y:两者之间最大的 R:谁的接口就是谁的编号 以R1和R2之间的连接为例&#xff0…