跳到主要内容

JEP 315:改进 Aarch64 内部函数

QWen Max 中英对照 JEP 315 Improve Aarch64 Intrinsics

概述

改进现有的字符串和数组内部函数,并在 AArch64 处理器上为 java.lang.Math 的 sin、cos 和 log 函数实现新的内部函数。

非目标

  • 对比并匹配其他架构的性能
  • 仅为单一 ARM64 架构实现调整通用 AArch64 端口内在函数,以达到最佳性能
  • 将内在函数移植到 ARM CPU 端口

动机

特定于专用 CPU 架构的代码模式提高了用户应用程序和基准测试的性能。

描述

Intrinsics 用于利用特定 CPU 架构的汇编代码,这些代码会在给定方法中替代通用的 Java 代码执行,以提升性能。尽管大多数 Intrinsics 已经在 AArch64 移植中实现,但以下 java.lang.Math 方法的优化 Intrinsics 仍然缺失:

  • sin (正弦三角函数)
  • cos (余弦三角函数)
  • log (数字的对数)

本 JEP 旨在通过为这些方法实现优化的内在函数来弥补这一差距。

同时,虽然大部分内联函数已经在 AArch64 移植中实现,但某些内联函数的当前实现可能不是最优的。具体来说,AArch64 架构的一些内联函数可能会受益于软件预取指令、内存地址对齐、针对多流水线 CPU 的指令布局,以及用更快的指令模式或 SIMD 指令替换某些指令模式。

这包括(但不限于)一些典型的操作,如 String::compareToString::indexOfStringCoding::hasNegativesArrays::equalsStringUTF16::compressStringLatin1::inflate 以及各种校验和计算。

根据内在算法、最常见的内在用例以及 CPU 的具体特性,可以考虑以下更改:

  • 使用 ARM NEON 指令集。此类代码(如果有的话会被创建)将被放置在一个标志下(例如 UseSIMDForMemoryOps),以防现有算法存在非 NEON 版本。
  • 使用预取提示指令 (PRFM)。该指令的效果取决于各种因素,例如是否存在 CPU 硬件预取器及其能力、CPU/内存时钟比率、内存控制器的具体情况以及特定算法的需求。
  • 重新排序指令并减少数据依赖性,以便尽可能允许乱序执行。
  • 如有必要,避免未对齐的内存访问。某些 CPU 实现会在跨越 16 字节边界、dcache 行边界发出加载/存储指令时施加惩罚,或者针对不同的加载/存储指令有不同的最佳对齐方式(例如,请参阅 Cortex A53 指南)。如果在与对齐无关的 CPU 上,使用对齐版本的内联函数不会减慢代码执行速度,那么改进地址对齐以帮助那些确实存在一些惩罚的 CPU 可能是有益的,前提是这不会显著增加代码复杂性。

测试

  • 使用 JMH 基准测试将在 Cavium ThunderX、ThunderX2 和 Cortex A53 硬件上测试 Intrinsics 性能。
  • 功能正确性将使用 jtreg 测试套件进行测试。如果现有的测试基础不能提供足够的覆盖范围,可能会创建额外的测试。

风险与假设

  • 将努力实现性能最佳的 AArch64 内联函数的通用版本。在无法实现的情况下,可能需要为特定硬件供应商编写专用版本的内联函数。
  • 无法对所有 AArch64 硬件变体进行测试和性能测量。如果在提交补丁进行审查时社区认为有必要,我们将依靠 OpenJDK 社区对我们目前没有的硬件进行测试。
  • 此 JEP 范围内的内联函数是特定于 CPU 架构的,因此更改它们不会影响共享的 HotSpot 代码。