gpt4 book ai didi

Java 自动矢量化示例

转载 作者:行者123 更新时间:2023-12-01 12:00:58 28 4
gpt4 key购买 nike

我试图找到一个简洁的例子,显示 auto vectorization在 x86-64 系统上的 java 中。

我已经使用 y[i] = y[i] + x[i] 实现了以下代码在 for 循环中。这段代码可以从自动向量化中受益,所以我认为 java 应该在运行时使用 SSE 或 AVX 指令编译它以加快速度。
但是,我在生成的 native 机器代码中找不到矢量化指令。
VecOpMicroBenchmark.java应该受益于自动矢量化:

    /**
* Run with this command to show native assembly:<br/>
* java -XX:+UnlockDiagnosticVMOptions
* -XX:CompileCommand=print,VecOpMicroBenchmark.profile VecOpMicroBenchmark
*/
public class VecOpMicroBenchmark {

private static final int LENGTH = 1024;

private static long profile(float[] x, float[] y) {
long t = System.nanoTime();

for (int i = 0; i < LENGTH; i++) {
y[i] = y[i] + x[i]; // line 14
}

t = System.nanoTime() - t;

return t;
}

public static void main(String[] args) throws Exception {
float[] x = new float[LENGTH];
float[] y = new float[LENGTH];

// to let the JIT compiler do its work, repeatedly invoke
// the method under test and then do a little nap
long minDuration = Long.MAX_VALUE;
for (int i = 0; i < 1000; i++) {
long duration = profile(x, y);
minDuration = Math.min(minDuration, duration);
}
Thread.sleep(10);

System.out.println("\n\nduration: " + minDuration + "ns");
}
}

为了确定它是否被矢量化,我做了以下事情:
  • 打开 eclipse 并创建上述文件
  • 右键单击该文件,然后从下拉菜单中选择 运行 > Java 应用程序 (暂时忽略输出)
  • 在eclipse菜单中,点击运行 > 运行配置...
  • 在打开的窗口中,查找 VecOpMicroBenchmark ,单击它并选择 参数选项卡
  • 在参数选项卡中,在 下虚拟机参数:输入:-XX:+UnlockDiagnosticVMOptions -XX:CompileCommand=print,VecOpMicroBenchmark.profile
  • 获取 libhsdis 并复制(可能重命名)文件 hsdis-amd64.so (.dll for windows) 到 java/lib 目录。就我而言,这是 /usr/lib/jvm/java-11-openjdk-amd64/lib .
  • 运行 VecOpMicroBenchmark 再次

  • 它现在应该向控制台打印大量信息,其中一部分是由 JIT 编译器生成的反汇编的本地机器代码。如果您看到很多消息,但没有像 mov 这样的组装说明, push , add等,那么也许您可以在某处找到以下消息: Could not load hsdis-amd64.so; library not loadable; PrintAssembly is disabled这意味着java找不到文件 hsdis-amd64.so - 它不在正确的目录中或它没有正确的名称。
    hsdis-amd64.so是显示生成的本地机器代码所需的反汇编程序。 JIT编译器将java字节码编译成本地机器码后, hsdis-amd64.so用于反汇编 native 机器代码以使其可读。您可以在 How to see JIT-compiled code in JVM? 找到有关如何获取/安装它的更多信息。 .

    在输出中找到汇编指令后,我浏览了它(太多了,无法在此处发布所有内容)并查找 line 14 .我找到了这个:
    0x00007fac90ee9859: nopl    0x0(%rax)
    0x00007fac90ee9860: cmp 0xc(%rdx),%esi ; implicit exception: dispatches to 0x00007fac90ee997f
    0x00007fac90ee9863: jnb 0x7fac90ee9989
    0x00007fac90ee9869: movsxd %esi,%rbx
    0x00007fac90ee986c: vmovss 0x10(%rdx,%rbx,4),%xmm0 ;*faload {reexecute=0 rethrow=0 return_oop=0}
    ; - VecOpMicroBenchmark::profile@16 (line 14)

    0x00007fac90ee9872: cmp 0xc(%rdi),%esi ; implicit exception: dispatches to 0x00007fac90ee9997
    0x00007fac90ee9875: jnb 0x7fac90ee99a1
    0x00007fac90ee987b: movsxd %esi,%rbx
    0x00007fac90ee987e: vmovss 0x10(%rdi,%rbx,4),%xmm1 ;*faload {reexecute=0 rethrow=0 return_oop=0}
    ; - VecOpMicroBenchmark::profile@20 (line 14)

    0x00007fac90ee9884: vaddss %xmm1,%xmm0,%xmm0
    0x00007fac90ee9888: movsxd %esi,%rbx
    0x00007fac90ee988b: vmovss %xmm0,0x10(%rdx,%rbx,4) ;*fastore {reexecute=0 rethrow=0 return_oop=0}
    ; - VecOpMicroBenchmark::profile@22 (line 14)

    所以它使用了 AVX 指令 vaddss .但是,如果我在这里是正确的, vaddss方法
    添加标量单精度浮点值,这只会将一个浮点值添加到另一个浮点值(此处,标量仅表示 1,而此处单表示 32 位,即 float 而不是 double)。
    我在这里期望的是 vaddps ,这意味着添加打包的单精度浮点值,这是一条真正的 SIMD 指令(SIMD = 单指令,多数据 = 向量化指令)。这里,packed 意味着多个浮点数打包在一个寄存器中。

    关于 ..ss 和 ..ps,见 http://www.songho.ca/misc/sse/sse.html :

    SSE defines two types of operations; scalar and packed. Scalar operation only operates on the least-significant data element (bit 0~31), and packed operation computes all four elements in parallel. SSE instructions have a suffix -ss for scalar operations (Single Scalar) and -ps for packed operations (Parallel Scalar).



    问题:
    我的 java 示例是否不正确,或者为什么输出中没有 SIMD 指令?

    最佳答案

    main()方法,放入 i < 1000000而不仅仅是 i < 1000 .然后 JIT 还生成如下 AVX vector 指令,代码运行速度更快:

    0x00007f20c83da588: vmovdqu 0x10(%rbx,%r11,4),%ymm0
    0x00007f20c83da58f: vaddps 0x10(%r13,%r11,4),%ymm0,%ymm0
    0x00007f20c83da596: vmovdqu %ymm0,0x10(%rbx,%r11,4) ;*fastore {reexecute=0 rethrow=0 return_oop=0}
    ; - VecOpMicroBenchmark::profile@22 (line 14)

    问题中的代码实际上可以由 JIT 编译器使用自动向量化进行优化。但是,正如 Peter Cordes 在评论中指出的那样,JIT 需要相当多的处理,因此不太愿意决定它应该完全优化某些代码。
    解决方法很简单,就是在程序的一次执行过程中更频繁地执行代码,不只是 1000 次,而是 100000 次或一百万次。
    执行 profile() 时多次这样的方法,JIT编译器确信代码非常重要,整体运行时将受益于全面优化,因此再次优化代码,然后它也使用真 vector 指令,如 vaddps .

    更多详情请见 Auto Vectorization in Java

    关于Java 自动矢量化示例,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59725341/

    28 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com