本文主要是介绍第3章 HSAIL 虚拟并行ISA,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
3.1 引言
HSAIL是一种低级别的编译器中间语言,旨在表达并行区域的代码,并可在多个供应商平台和硬件世代移植,它可以作为HSA系统应用程序开发的工具。
HSAIL通常由高级编译器生成。开发人员使用高级语言编写程序,并使用语言的自然语法(例如指令或并行循环)来识别并行代码区域。编译生成锁标识的并行区域的CPU和HSAIL的主机代码。HSAIL定义了一种二进制格式BRIG,可以将其嵌入HSA应用程序二进制文件中。一种称为“终止器”的即时JIT编译器提取嵌入的BRIG并将转换为异构设备的目标指令集。根据使用模型,终止器可以在构架时间、安装时间或运行时运行。
HSAIL的好处之一是可以跨多个供应商的产品进行移植。与CPU指令集体系结构不同,GPU和DSP的并行指令集表现出显著的变化。因此,可移植的、多供应商计算机中间语言的标准是一个重要的贡献。生成HSAIL的工具链(编译器、调试器和分析器等)可以确保生成的代码可以在各种目标平台上运行。在多个供应商之间共享这种基础体系结构为开发人员提供了更一致的做法,允许供应商利用通用软件,并将精力集中在工具链的真正产品特定部分。
HSAIL将随着主要由工作负载分析推动的新业务的发展而发展,但大约每隔几年一次,版本的迭代速度被控制成与现代CPU体系结构类似。扩张HSAIL以利用和区分不同类别的域处理器。这样的增加将作为HSAIL的扩展提供,是可选的,并且将依靠核心HSAIL指令来编程许多设备共有的基础并行性。
HSAIL是一种低级的中间语言,运行在机器指令集之上。它专为快速且强大的编译设计的;从HSAIL到机器代码的转换(终止化步骤)不仅仅是一个复杂的编译器优化过程,也是一种翻译。这个终止化步骤的简单些降低了错误蔓延到设计中的机会,并且还降低了由于终止器的变化而导致的性能变化。相反,大多数优化都是在高级编译器中完成的,它具有更大的时间预算和更大的范围来实现复杂的优化。例如,HSAIL提供了一个固定大小的寄存器文件,所以高级编译器执行寄存器分配,这是传统编译过程比较复杂、容易出错且耗时的部分。
3.2 编译流程示例
HSA代理是参与HSA内存模型的设备,可以是GPU、CPU或者其他域处理器。主机CPU代码(即主要功能和数组的数据分配,以白色显式)包含在同一个源文件中,高级编译器将把这个源代码编译成主机CPU指令集中的目标代码。由此产生的可执行图像将包含CPU和BRIG的混合代码。编译器将加载BRIG代码,为目标机器终止,并将结果代码发送到目标机器。在运行时,当CPU指令流遇到HSA代理代码时,将执行此代码。通常,BRIG只终止化一次,并将会生成的代码对象保存在内存中。从终止器输出的HSA代码对象包含目标HSA代理指令集的目标代码。
编译流程是相似的:
1. 同一个源文件包含并行和主机CPU代码;
2. 并行区域有程序员明确表示;
3. 编译器输出的对象包含主机CPU对象代码和BRIG;
4. 执行时,生成的代码调用HSA运行时来终止BRIG并将其分派的目标HSA代理。
3.3 HSAIL执行模型
HSAIL和HSA执行执行是为并行执行而设计的。然而,它们将并行性作为一个单线程的HSAIL程序,与在调度时指定的并行网格相结合,并描述了并行执行的形式。更具体地说,HSAIL程序被称为“内核”,并指定执行的单个“工作项”的指令流程。当调度HSAIL内核时,dispatch命令指定了应该执行的工作项的数量。每个工作项都是都是网格中一点。网格的组织往往受到正在处理的数据形状的影响。
网格由许多工作项组成。因此,每个工作项都有一个唯一的标识符。HSAIL包含指令,以便每个工作项都可以确定它在网格中的位置,从而确定工作项应在那部分数据上运行。
网格划分为一个或多个“工作组”。同一个工作组的工作项可以通过高带宽的“组内存”高效地进行通信和同步。工作组可以通过使用组内存提供从机器获得峰值性能的机会。网格中的每个维度的最后一个工作组可能只是部分填充,这为开发人员提供了网格大小的一些灵活性。
“波前wavefront”是一个硬件概念,表示一起调度并以锁步方式执行的工作项的数量。不同的硬件可能有不同的波前宽度,因此大多数程序员不需要知道波前宽度。HSAIL还提供跨通道操作,结合了来自同一波前的多个工作项的结果。
当网格执行时,工作组被分配到目标HSA代理中的一个或多个计算单元。网格总是按照工作组的大小进行调度。因此,工作组封装了一段并行工作,对于拥有更多计算单元的高端设备,性能自然而然地扩展。
HSA执行模型中的工作项为编程人员提供了熟悉的目标 ,因为每个工作项都代表一个执行线程。HSAIL代码因此类似于一个顺序程序。每个工作项似乎都有自己的程序计数器,控制流可以用条件检查和分支指令表示,而不是显式指定的执行掩码。并行性由网格和工作组(表示要运行多少工作项)表示,而不是在HSAIL代码本身内部。这是一个强大的杠杆,使模型可以在各种不同向量宽度和数量的计算单元的并行硬件上移植。将其与PCU模型对比,CPU模型通常需要不同的不兼容机制来表达线程并行性和SIMD并行性。而且,SIMD并行性通常被硬编码到程序中,并且随着SIMD宽度的增加而难以缩放。宽向量CPU有时会被更容易编程。然而,这通常需要直接在汇编或内置函数中进行开发,并且进一步对汇编进行硬编码以生成特定的向量宽度和指令集。HSAIL代码看起来像是一个熟悉的顺序程序,在可用性和可扩展性,是一个比宽向量汇编编码更显著的改进。
最后,HSA执行模型指定工作项可以并行执行,并且工作项之间的任何通信必须用组内存和屏障、原子或特殊的跨通道指令明确指定。另外,工作组可以并行执行,也可以按任意顺序执行。这两个限制都都允许HSA二进制文件具有出色的可扩展性,因为添加了并行计算的硬件,而不需要昂贵的依赖性检查硬件。
3.4 HSAIL指令集简介
编写HSAIL与编写CPU汇编语言相似:语言使用加载/存储体系结构,支持基本的整数和浮点操作、分支、原子操作、多媒体操作,并使用固定大小的寄存器池。指令集定义了浮点双精度、单精度和半精度。HSAIL还支持函数指针、虚拟函数、共享虚拟内存、系统原子核用于高效跨设备通信的信号。此外,HSAIL还定义了组内存、层次同步原语(例如,工作组、代理和系统范围同步)以及可用于实现峰值的波前。
3.4.1 原子操作
原子操作时HSA内存模型的一部分,它定义了工作项和主机线程如何同步内存访问以控制内存可见性(也称内存一致性)。内存可见性由内存排序和内存范围一起控制。内存排序指定了不同工作项和线程中的原子操作时如何相互同步的,内存范围控制着这个同步可以发生的内存层次级别。
HSA内存模型定义了顺序一致的获取/释放和松弛的原子内存排序。内存范围可以指定为系统、代理、工作组或波前。
原子操作可以指定系统内存范围,以使HSA代理能够以细粒度的方式相互通信。诸如GPU的HSA代理可以将数据生成到工作队列中,然后使用具有顺序一致性的释放内存排序和系统内存范围的原子操作来移动队列上的尾指针。然后,CPU或其他HSA代理可以使用具有顺序一致的获取内存排序和系统内存范围的原子操作来查看队列中的数据。所有这些都可以在不退出HSAIL内核的情况下完成。
HSA通过定义良好的多供应商内存模型支持细粒度的一致性,与现有的仅支持内核调度边界处的重量级粗粒度同步的GPU系统相比,是一个重大改进。
3.4.2 寄存器
HSAIL的一个关键设计就是使用固定大小的寄存器池。这允许寄存器分配被移动到高级编译器,并且允许终止器运行得更快,复杂度更低。HSAIL提供四类寄存器,按其大小定义:
C:1位的谓词寄存器;
S:32位寄存器;
D:64尾寄存器;
Q:包含打包值的128位寄存器;支持几种打包格式。每个打包元素的大小可以从8位到64位;
HSAIL提供最多128个C寄存器。S、D和Q寄存器共享一个资源池,最多支持2048个32位寄存器“插槽”。高级编译器必须确保生成的HSAIL代码中的1 * S + 2 * D + 4 * Q小于2048。该池被设计为足够大以代表各种并行机器目标,但是也具有已知的有限尺寸以简化终止化步骤。如果高级编译器使用所有可用的寄存器,则它将利用HSAIL溢出段来混合进入和退出寄存器的活动值。
3.4.3 分段
HSAIL将地址空间分为7个段:全局、组、私有、只读、溢出、参数和内核参数。
全局段:全局段对所有HSA代理(包括CPU主机)都是可见的。这是HSA代理交换信息(如任务队列、平台原子核共享虚拟内存)的主要分段。
组段:提供工作组中工作项共享的高性能内存。组内可以通过工作组中的任何工作项读取和写入,并且可以通过HSAIL屏障指令和内存栅栏结合使工作组中的其他工作项可见。工作项不能看到其他工作组的组内存。
私有、溢出和参数段:三者可以共享一个连续的内存区域。对这些段的内存引用通常由编译器生成,而不是由程序员明确指定。溢出段用于注册溢出。私有段用于内存工作项的专用的数据,如未分配到寄存器的变量。最后,参数段用于保存传递给HSAIL函数的参数。
只读段:在执行内核期间只读段保持不变,并且可能映射到某些机器上的特殊硬件。
内核参数段:内核参数段用于将参数传递给内核。例如调用内核的HSA代理把参数写入内核参数段,并将指针传递给内核中的内核参数段(在AQL包中指定)。然后,内核将使用内核参数段的信息的加载来访问内核参数。包括所有传递给内核的类型的大小和对齐要求。因此,所有内核参数的布局、大小和对齐可以用过检查内核的签名以设备无关的方式静态绑定。此属性对于实现跨供应商的可移植性至关重要,对于简化终止器实现以及使库开发人员编写可轻松访问内核参数的低级汇编代码也很有用。
平面地址根据虚拟地址映射到全局、组或私有段。这些功能对于编写一个接受平面指针的HSAIL函数是非常有用的,而不是要求函数的多个归一化来覆盖明确指定的全局/组/私有段的所有可能的组合。
3.4.4 波前和通道
波前是一个硬件概念,指示一起安排的工作项的数量。回想一下,一个HSAIL程序代表了单个工作项的程序流程,外观上每个工作项都有自己独立的程序计数器。在许多并行机器上,“幕后”执行波前的实际硬件是SIMD,向量中每个通道代表一个工作项。波前中的所有通道总是执行相同的指令,但有些通道可能是不活动的。这意味着它们会消耗资源,但不会产生任何结果或做任何有用的工作。硬件使用执行掩码来呈现独立程序计数器的外观。每个通道与执行掩码中的一个位相关联;清除不活动通道的位,设置活动通道的位。
许多程序员都可以通过HSAIL内核和大型网络提供出色的可扩展性来指定并行性,而无需担心工作组维度或波前宽度的细节。指定工作组维度提供了优化的机会,特别是当组中的工作项可以从高速通信机制(组内存和工作组屏障)中受益时。
3.5 HSAIL机器模型和配置文件
为了确保HSAIL可以在多个细分市场中高效实施,HSA基金引入机器模型和配置文件的概念。机器模型涉及数据指针的大小;配置文件侧重于功能和精度要求。
拥有太多机器模型和配置文件会破坏生态系统,使基础设施和社区难以发展和成长。因此,目前只有2种机器模型:32位和64位。同样,也只有2种配置文件:基本和完整。
提供HSAIL配置文件,以确保实现支持所需的功能集并满足给定的程序限制。严格定义的一套HSAIL配置文件要求具有一定级别支持的用户提供可移植性保证。基本配置文件表明,实现的目标是较小的系统,提供更好的能源效率,而不牺牲性能。在这个配置文件中精度可能会降低,以提高能源效率。完整配置文件表明,针对大型系统的实现将具有可以保证更高精度的结果而不牺牲性能的硬件。
完整配置文件遵循IEEE-754浮点运算规则。基本配置文件放宽了除法和平方根的精度要求,并且只支持单个浮点舍入模式,可以是舍入到最近邻或舍入为零。
以下规则适用于配置文件:
1. 终止器可以选择支持一个或二个配置文件;
2. 单个配置文件适用于整个HSAIL程序;
3. 应用程序不允许混合配置文件;
4. 每个配置文件都支持大型和小型机器模型;
3.6 HSAIL编译流程
HSA运行时如何从HSAIL生成可以在HSA内核代理上执行的代码,分为两个不同的阶段:
1. 终止化:为特定指令集体系结构创建代码;
2.加载:管理全局和只读变量的分配,以及最终将代码安装到特定HSA内核代理上。
终止化流程和加载流程完全分离,实际上,终止器API是一个可选的扩展,不需要包含在HSA运行时实现中。运行时终止化是可选的,以支持在构建时或安装时执行终止化的系统,因此不需要运行时终止化。编译流程允许离线生成代码对象,也许可以通过离线编译器生成HSAIL,然后调用终止器工具,也可以通过离线编译器直接生成目标ISA(指令集体系结构或机器代码)。支持这两种路径以及一个完整的在线终止化流程,在这个流程中,BRIG被生成,然后在运行时终止化。可选的终止化流程是一个或多个输入模块构建程序开始。所有BRIG代码都包含在模块中。程序可能包含多个共享功能代码和数据的BRIG模块。程序被传递给终止器为目标平台生成ISA,终止器的输出是一个代码对象。代码对象可以直接传递到加载或序列化并保存到磁盘文件。
加载流程从代码对象开始,代码对象可以直接来自终止器的输出(运行时输出)或反序列化磁盘文件(离线终止)。然后加载代码对象,为全局变量分配内存,解析代码中的全局符号的偏移量,并准备要在目标HSA代理上执行的代码。加载步骤的输出是一个“可执行文件”,它可能包含多个内核和相关函数的代码。HSA运行时提供API来从可执行文件中提取“内核对象”句柄,内核对象句柄可以传递到执行期望的内核代码。
HSAIL编译过程涉及多个数据结构和单独步骤,但在编译执行(在线或离线)时提供了极大的灵活性。它还支持终止器输出缓存,并允许BRIG的ISA文件共享全局数据和代码。
3.7 HSAIL编译工具
3.7.1 编译器框架
已将HSAIL作为编译器目标添加到流行的LLVM编译器框架中。这位语言前端提供了一条平滑的路径来生成可以在各种并行计算设备上运行的HSAIL代码。语言前端都为程序员定义了语言特定的语法来标记并行区域。HSAIL回一个独立的、完全指定的编译器中间语言,可以添加到其他编译器框架中
3.7.2 CL离线编译
OpenCL的离线编译器解析了OpenCL内核的语法,通过LLVM编译器运行,并生成HSAIL/BRIG作为输出。离线编译OpenCL本身是有用的,因为它子啊编译时而不是运行时显式错误信息,并且可以促进快速的开发流程。这也提供了一个方便的方法生成直接与HSA运行时一起使用的BRIG序列化文件。这些在生成测试用例、移植代码或开发用于其他语言的库时非常有用。OpenCL定义了丰富的内核语言,它支持许多特性,包括组内存和屏障、广泛的数学和图像库。
3.7.3 HSAIL汇编器和反汇编器
BRIG是HSAIL问价的二进制形式。hsailasm工具将HSAIL文件转换为BRIG,反之亦然。二进制和文本形式时相同信息的两种表示形式,可以相互转换。
3.7.4 ISA和机器码汇编器/反汇编器
HSAIL是一个低级别的编译器目标,并且提供了便于其他供应商以及来自同一供应商的未来硬件移植的优点。在某些情况下,开发人员更愿意直接为目标平台生成ISA。
通过适当的编译器支持。任何语言前端都可以多次运行LLVM编译器。以生成一个包含BRIG和ISA代码的胖二进制文件。此外,LLVM“机器代码”框架可以用作汇编程序,将ISA文件转换为可直接在硬件上运行的目标代码。另一个选择是从LLVM编译器生成BRIG,然后运行离线终止器为选定的目标代理生成ISA。
灵活的HSAIL编译框架和终止器接口为开发人员提供了许多选项,并支持可移植性、稳定性和性能目标。
这篇关于第3章 HSAIL 虚拟并行ISA的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!