我正在尝试找到一个简洁的示例,该示例在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");
}
}
为了确定它是否被矢量化,我执行了以下操作:
-XX:+UnlockDiagnosticVMOptions -XX:CompileCommand=print,VecOpMicroBenchmark.profile
hsdis-amd64.so
(对于Windows为.dll)复制(可能重命名)到java / lib目录。就我而言,这是/usr/lib/jvm/java-11-openjdk-amd64/lib
。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
用于反汇编本机代码以使其易于阅读。您可以在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指令表示just one,而此处的[[single表示32位,即vaddss
。但是,如果我在这里是正确的,则vaddss
表示添加标量单精度浮点值
,这只会将一个浮点值与另一个浮点值相加(此处,scalar
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]实现了以下代码。此代码可以从自动...
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)