如何编写代码来提示 JVM 使用向量运算?

2022-09-02 04:50:31

有点相关的问题,一年前的问题是:是否有任何JVM的JIT编译器生成使用矢量化浮点指令的代码?

前言:我正在尝试在纯java中执行此操作(没有JNI可以C++,没有GPGPU工作等)。我已经分析了,大部分处理时间来自此方法中的数学运算(可能是95%的浮点数学和5%的整数数学)。我已经将所有 Math.xxx()调用减少到一个足够好的近似值,所以大部分数学现在都是浮点乘法和几个加法。

我有一些处理音频处理的代码。我一直在进行调整,并且已经取得了巨大的进步。现在,我正在研究手动循环展开,看看是否有任何好处(至少手动展开2,我看到大约25%的改进)。在尝试手动展开4(由于我正在展开嵌套循环的两个循环,这开始变得非常复杂)时,我想知道我是否可以做些什么来提示jvm在运行时可以使用矢量运算(例如SSE2,AVX等)。音频的每个样本都可以完全独立于其他样本进行计算,这就是为什么我已经能够看到25%的改进(减少了对浮点计算的依赖性)。

例如,我有 4 个浮点数,每个浮点数对应于循环的 4 个展开,以保存部分计算的值。我如何声明和使用这些浮子是否重要?如果我把它变成一个浮点数[4],这是否暗示jvm它们彼此无关,而不是有浮点数,浮点数,浮点数,浮点数,浮点数甚至一类4个公共浮点数?有没有一些我可以毫无意义的事情会扼杀我代码被矢量化的机会?

我在网上看到过关于“正常”编写代码的文章,因为编译器/ jvm知道常见的模式以及如何优化它们,偏离模式可能意味着更少的优化。然而,至少在这种情况下,我不会期望将循环展开2会像它所做的那样提高性能,所以我想知道我是否还可以做(或者至少做)来帮助我的机会。我知道编译器/ jvm只会变得更好,所以我也想警惕将来会伤害我的事情。

为好奇的人编辑:展开4比展开2将性能提高约25%,所以我真的认为如果jvm支持它(或者可能已经使用它们),矢量操作在我的情况下会有所帮助。

谢谢!


答案 1

我怎么能..音频处理..纯java(没有JNI来C++,没有GPGPU工作,等等)。使用向量运算(例如 SSE2、AVX 等)

Java是高级语言(Java中的一条指令生成许多硬件指令),这是设计上的(例如垃圾回收器内存管理),不适合实时操作高数据量的任务。

通常有针对特定角色(例如图像处理语音识别)优化的特殊硬件,这些硬件多次通过几个简化的处理管道利用并行化。

对于这类任务,也有特殊的编程语言,主要是硬件描述语言汇编语言

即使C++(被认为是快速语言)也不会自动为您使用一些超级优化的硬件操作。它可能只是在某些地方内联几种手工制作的汇编语言方法之一。

所以我的答案是,“可能没有办法”指示JVM对你的代码使用一些硬件优化(例如SSE),即使有一些,Java语言运行时仍然会有太多其他因素会减慢你的代码。

使用为此任务设计的低级语言,并将其链接到 Java 以实现高级逻辑。

编辑:根据评论添加更多信息

如果您确信高级“一次编写一次,随处运行”语言运行时肯定也应该为您进行大量低级优化,并自动将您的高级代码转换为优化的低级代码,那么...JIT 编译器的优化方式取决于 Java 虚拟机的实现。其中有很多。

如果是Oracle JVM(HotSpot),您可以通过下载源代码开始寻找答案,文本出现在以下文件中:SSE2

  • openjdk/hotspot/src/cpu/x86/vm/assembler_x86.cpp
  • openjdk/hotspot/src/cpu/x86/vm/assembler_x86.hpp
  • openjdk/hotspot/src/cpu/x86/vm/c1_LIRGenerator_x86.cpp
  • openjdk/hotspot/src/cpu/x86/vm/c1_Runtime1_x86.cpp
  • openjdk/hotspot/src/cpu/x86/vm/sharedRuntime_x86_32.cpp
  • openjdk/hotspot/src/cpu/x86/vm/vm_version_x86.cpp
  • openjdk/hotspot/src/cpu/x86/vm/vm_version_x86.hpp
  • openjdk/hotspot/src/cpu/x86/vm/x86_32.ad
  • openjdk/hotspot/src/os_cpu/linux_x86/vm/os_linux_x86.cpp
  • openjdk/hotspot/src/share/vm/c1/c1_GraphBuilder.cpp
  • openjdk/hotspot/src/share/vm/c1/c1_LinearScan.cpp
  • openjdk/hotspot/src/share/vm/runtime/globals.hpp

它们使用C++和汇编语言,因此无论如何您都必须学习一些低级语言才能阅读它们。

即使有+500的赏金,我也不会打猎那么深。恕我直言,基于错误的假设,这个问题是错误的


答案 2

Hotspot上的SuperWord优化是有限的,而且非常脆弱。由于它们通常落后于C / C++编译器提供的功能,并且由于它们依赖于特定的循环形状(并且仅支持某些CPU),因此受到限制。

我知道你想写一次运行任何地方。听起来你已经有了一个纯粹的Java解决方案。您可能需要考虑为已知的流行平台提供可选的实现,以补充该实现以“在某些地方快速”,这可能已经是正确的。

很难通过一些代码给你更具体的反馈。我建议你把有问题的循环放在JMH基准测试中。这使得分析和讨论变得容易。


推荐