直播回顾:SIMD 指令集在 OpenJDK 中的现状与未来 | 龙蜥技术
编者按:SIMD 是 CPU 硬件中一类实现数据并行的扩展指令,它的使用可以大幅提升包括一般应用程序在内的软件性能,但在实际使用中也存在着一些限制。安谋科技(Arm China)资深软件工程师、OpenJDK 社区 Committer 、龙蜥社区 Java 语言与虚拟机 SIG 成员李鹏飞从 Java 应用程序使用 SIMD 指令集的现状、Arm 架构的下一代 SIMD 指令集 SVE 及其特性以及 Arm 在 OpenJDK 社区为支持 SVE 所作的相关工作等方面解读《如何利用硬件 SIMD 指令提升 Java 程序的性能》。
一、SIMD 在 Java 中的应用
学习过计算机体系结构的同学对 SIMD 这个概念应该不陌生,它是指 CPU 指令集中的一类指令,特点是一条指令可以处理多个数据。与一条指令只处理一个数据的标量指令相比,SIMD 指令有点像多车道的高速公路。SIMD 指令通常工作在向量寄存器(vector register)上。我们把向量寄存器上每个待处理数据元素所占的比特位称为一个通道(lane)。如下图所示的两个向量求和的例子。将总长128 比特的向量寄存器按每个数据元素为 int 型来划分,一个向量寄存器就有 4 个通道。因此下图中一条 SIMD 指令就做了 4 个加法运算。按照通俗的理解,在通道位宽(或数据元素宽度)一定的情况下,向量长度越大,Lane 通道数越多,相当于高速公路车道数越多,数据的吞吐量就越大。SIMD 指令集最早只用于科学计算和多媒体处理等专用领域,但随着时间的推移和指令集架构的演进,今天的 SIMD 已经可以用来优化包括一般 C++/Java 应用程序在内的通用计算。应用开发者使用 SIMD 的方法有多种,包括:
- 内嵌SIMD汇编指令代码
- 调用一些优化好的内联(intrinsic)函数
- 交给编译器进行自动向量化
这三种方法各有其优缺点,在具体使用过程中也都存在一些局限性。Arm 在指令集架构层面一直在尝试突破这些局限,其中一个比较大的突破就是基于 Arm AArch64 指令集的 SVE 扩展。
二、Arm SVE 指令集扩展
SVE 的全称是可变长向量扩展(Scalable Vector Extension),它有很多新特性和优势,其中1两个比较重要的是可变长(scalable)和向量掩码(predicate)。第一个特性,“可变长”是指 SVE 有 32 个不规定长度的向量寄存器,其寄存器长度可以是 128 位的任意整数倍,最大可以是 2048 位。我们这里说的“不规定”指的是Arm架构对寄存器长度没有具体限制,CPU 厂商可以根据其硬件设计自主决定。对此 SVE 有一个重要特点,就是包含SVE指令的代码可以直接运行在任意 SVE 寄存器长度的 CPU 上,而不需要重写代码或重新编译。
SVE 的第二个重要特性是向量掩码(predicate),SVE 的 16 个 predicate 寄存器可以用来控制向量操作中通道的活跃性(lane activity)。如上左图所示,predicate 值为 1 标识的活跃通道参与向量加法运算,而不活跃的通道不参与运算。此外,SVE 还提供了一种通过比较操作产生 predicate 值的机制(如上右图所示),从而为循环控制提供了一种新的 predicate 驱动的方法。通过这种新的方法,向量化循环的每一趟可以跑同一套代码,并在循环的最后一趟操作向量的部分通道。
我们用一个通俗的比喻来对比标量指令、传统 SIMD 指令以及 SVE 指令。好比我们要用杯子打一定量的水,标量指令为我们提供了一个小杯子,我们要打很多次;传统 SIMD 指令提供了一个大一点儿的杯子,可以少打几次,但打到最后不够打一满杯的时候还必须换小杯继续打;SVE 不仅为我们提供了一个更大的杯子,这个杯子可以非常大(2048 位),而且它是带刻度的(predicated),在不够打一满杯的情况下可以拿它打半杯。
三、在 OpenJDK 中支持 SVE
为了让 Java 虚拟机用得上 SVE 的这些好特性,我们安谋科技(Arm China)的 JDK 团队在这方面已经投入了近两年时间,主要包括以下三个方面的工作:
- JDK 库函数 SVE 版本 intrinsics 的实现
- Java Vector API 的 SVE 实现
- SVE 自动向量化的支持
除此之外,我们还做了一些基础的通用的支持,包括SVE的寄存器分配,代码生成规则(matching rules)以及运行时SVE特性检查(runtime feature detection)等等。这些工作大部分都实在HotSpot的C2编译器中完成的,对于Vector API,我们还有一些关于 JDK 库函数内部实现的讨论。
这些支持工作有的已经交付社区,且在近期发布的 JDK 版本中已经可以使用了,有的工程量比较大且技术细节很多,还处在紧锣密鼓地开发之中。下图展示了目前我们已经交付的工作和一些未来的计划。