Java自动向量化示例

问题描述 投票:5回答:1

我正在尝试找到一个简洁的示例,该示例在x86-64系统上的Java中显示auto vectorization

我已经在for循环中使用y[i] = y[i] + x[i]实现了以下代码。该代码可从自动矢量化中受益,因此我认为Java应该在运行时使用SSE或AVX指令对其进行编译,以加快速度。但是,我在生成的本机代码中找不到矢量化指令。

[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");
        }
    }

为了确定它是否被矢量化,我执行了以下操作:

  1. open eclipse并创建上述文件
  2. 右键单击文件,然后从下拉菜单中选择运行> Java应用程序(暂时忽略输出)
  3. 在Eclipse菜单中,单击运行>运行配置...
  4. 在打开的窗口中,找到VecOpMicroBenchmark,单击它并选择[Arguments选项卡]
  5. 在“参数”选项卡中的“ [[VM参数:]]”下,放置在此位置:-XX:+UnlockDiagnosticVMOptions -XX:CompileCommand=print,VecOpMicroBenchmark.profile
  6. get libhsdis
  7. 并将文件hsdis-amd64.so(对于Windows为.dll)复制(可能重命名)到java / lib目录。就我而言,这是/usr/lib/jvm/java-11-openjdk-amd64/lib
  8. 再次运行VecOpMicroBenchmark
  9. 现在它应该在控制台上打印很多信息,其中一部分是由JIT编译器生成的反汇编本机代码。如果您看到很多消息,但没有诸如movpushadd等组装说明,那么也许您可以在某处找到以下消息:Could not load hsdis-amd64.so; library not loadable; PrintAssembly is disabled这意味着java找不到文件hsdis-amd64.so-它不在正确的目录中,或者没有正确的名称。

hsdis-amd64.so是反汇编程序,用于显示生成的本机代码。在JIT编译器将Java字节码编译为本机代码之后,hsdis-amd64.so用于反汇编本机代码以使其易于阅读。您可以在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表示

添加标量单精度浮点值

,这只会将一个浮点值与另一个浮点值相加(此处,scalar
表示just one,而此处的[[single表示32位,即float而非double)。我在这里期望的是vaddps,这意味着添加打包的单精度浮点值,并且它是真正的SIMD指令(SIMD =单指令,多数据=矢量化指令)。在这里,packed表示将多个浮点数打包到一个寄存器中关于..ss和..ps,请参见http://www.songho.ca/misc/sse/sse.html

SSE定义了两种类型的操作;标量和包装。标量运算仅对最低有效数据元素(位0〜31)进行运算,而打包运算将并行计算所有四个元素。 SSE指令的后缀-ss用于标量操作(单标量),-ps用于打包操作(并行标量)。

Queston:

我的Java示例不正确,还是为什么输出中没有SIMD指令?

我正在尝试寻找一个简洁的示例,该示例在x86-64系统上的Java中显示自动矢量化。我在for循环中使用y [i] = y [i] + x [i]实现了以下代码。此代码可以从自动...

java assembly vectorization x86-64 simd
1个回答
1
投票
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)
© www.soinside.com 2019 - 2024. All rights reserved.