Java可以识别CPU的SIMD优势;或者只是循环展开的优化效果

Java可以识别CPU的SIMD优势;或者只是循环展开的优化效果,java,performance,optimization,simd,loop-unrolling,Java,Performance,Optimization,Simd,Loop Unrolling,这部分代码来自我的一个向量类的点积方法。该方法对目标向量数组(1000个向量)进行内积计算 当向量长度为奇数(262145)时,计算时间为4.37秒。当向量长度(N)为262144(8的倍数)时,计算时间为1.93秒 time1=System.nanotime(); int count=0; for(int j=0;j<1000;i++) { b=vektors[i]; // selects next vector(b)

这部分代码来自我的一个向量类的点积方法。该方法对目标向量数组(1000个向量)进行内积计算

当向量长度为奇数(262145)时,计算时间为4.37秒。当向量长度(N)为262144(8的倍数)时,计算时间为1.93秒

     time1=System.nanotime();
     int count=0;
     for(int j=0;j<1000;i++)
     {

             b=vektors[i]; // selects next vector(b) to multiply as inner product.
                           // each vector has an array of float elements.

             if(((N/2)*2)!=N)
             {
                 for(int i=0;i<N;i++)
                 {
                     t1+=elements[i]*b.elements[i];
                 }
             }
             else if(((N/8)*8)==N)
             {
                 float []vek=new float[8];
                 for(int i=0;i<(N/8);i++)
                 {
                     vek[0]=elements[i]*b.elements[i];
                     vek[1]=elements[i+1]*b.elements[i+1];
                     vek[2]=elements[i+2]*b.elements[i+2];
                     vek[3]=elements[i+3]*b.elements[i+3];
                     vek[4]=elements[i+4]*b.elements[i+4];
                     vek[5]=elements[i+5]*b.elements[i+5];
                     vek[6]=elements[i+6]*b.elements[i+6];
                     vek[7]=elements[i+7]*b.elements[i+7];


                     t1+=vek[0]+vek[1]+vek[2]+vek[3]+vek[4]+vek[5]+vek[6]+vek[7];
                     //t1 is total sum of all dot products.
                 }
             }
     }
     time2=System.nanotime();
     time3=(time2-time1)/1000000000.0; //seconds
time1=System.nanotime();
整数计数=0;

对于(int j=0;j我对此做了一些研究(我从一个类似于我在C中做的矩阵乘法的项目中汲取了一些知识),但对我的答案持怀疑态度,因为我决不是这方面的专家

至于你的第一个问题,我认为加速来自循环的展开;你在for循环中进行的条件检查大约减少了87%。据我所知,JVM从1.4开始就支持SSE,但要真正控制代码是否使用矢量化(当然要知道),你需要使用JNI

请参见此处的JNI示例:

当您将向量的大小从262144减少到64时,缓存无疑是一个因素。当我在C中执行此项目时,我们必须为更大的矩阵实现缓存块以利用缓存。您可能需要做的一件事是检查缓存大小


作为一个旁注:最好是以触发器而不是秒来衡量性能,因为程序的运行时间(以秒为单位)可能会根据许多不同的因素而变化,例如当时的CPU使用情况。

您的代码有一系列问题。您确定您在衡量您认为衡量的是什么吗

您的第一个循环执行此操作,按更常规的方式缩进:

 for(int j=0;j<1000;i++) {
     b=vektors[i]; // selects next vector(b) to multiply as inner product.
                   // each vector has an array of float elements.
 }

for(int j=0;jAlso向量(size=13)的计算时间等于向量(size=13*16),这不是很奇怪吗?将问题大小乘以16就得到了相同的时间(两者都将近1秒)我认为CPU在分支方面很强大。13很小,13*16允许你使用循环展开。但两者都是非常小的向量,所以我怀疑你会看到很多时间变化。该程序的开销可能会使两个计算时间相形见绌。如果他的第二个循环没有中断,两个循环将以完全相同的方式使用缓存。speedup并不是因为减少了条件检查。这是因为计算的组织方式不同。如果你将向量的大小减少到64,那么所有东西都适合L1,以什么顺序遍历都不重要。在现代处理器上,触发器并不是一个很好的速度度量标准,因为它们是高度流水线和算术的etic通常不是瓶颈。我只是删除了上面的“}”。我在调试时忘了删除。对不起。你的意思是不同大小的向量意味着不同级别的缓存。根本没有SIMD?要使用JNI,我需要该.h文件来真正使用CPU吗?我试过了,但没有成功(下载了javacpp的jar并显示了路径)但我会更加努力。很抱歉,我本来打算删除“}”,但忘了删除。(调试)嗯。是的,让它工作起来有点烦人。你需要类似于
hsdis-amd64的东西。所以JVM需要找到
-XX:+UnlockDiagnosticVMOptions
才能
-XX:+printsassembly
。而且你必须正确地利用一切。无法加载hsdis-amd64.dll;库无法加载;printsassembly是dis启用-->搜索下载位置,然后将其显示为外部jar文件(或库)?构建您自己的openjdk。或者构建
hsdis base
包或其他任何东西。无论如何,当我尝试使用类似代码时,我仍然看到它发出了一系列标量指令。底线:在速度很重要的任何事情上都不要使用java。我使用的是opencl,但读到直接使用avx至少可以使速度提高10倍现在。