Java中的矢量距离计算 - 优化

时间:2012-09-28 19:28:42

标签: java optimization

作为图像处理功能的一部分,我需要计算它们之间的平方和 图像中有两行。

这部分代码占用了96%的运行时间:

for(int dx=0;dx<size;dx++) {
    int left = a[pa+dx];
    int right = b[pb+dx];
    int diff = (left & 0xFF) - (right & 0xFF);
    sum += diff*diff;
}

其中:

  • ab属于byte[]
  • 类型
  • sumlong
  • sizeint,通常值较大(约为400)

运行Java 7 64位。我尝试用a[pa+dx]之类的内容替换a[pa++] 表现并不好。

与C ++编写的完全相同的代码完全执行保存运行 整体快两倍(!)和 据我所知,不应该有这个Java的重要原因 代码是快速的,特别是当边界检查可以移出循环时 编译器。

如何优化这些内容以执行与C ++代码一样的操作 - 最终它是如此 整数算术它不应该在Java中慢得多

编辑:C ++示例如下:

unsigned char const *srcptr=&a[pa];
unsigned char const *tgtptr=&b[pb];
for(int dx=0;dx < size;dx++) {
    int p1=*srcptr++;
    int p2=*tgtptr++;
    int diff = p1 - p2;
    sum += diff * diff;
}

我想了解如何使HotSpot优化器创建代码 与上面显示的C ++代码一样快,最后它非常简单容易 优化生产线。

4 个答案:

答案 0 :(得分:2)

它只是很小,但您不需要& 0xFF来计算差异:差异将是相同的有符号或无符号。

100 - -1 = 101  // signed
228 - 127 = 101 // unsigned

然后它会更紧密的循环体:

for (int dx = 0; dx < size; dx++) {
    int diff = a[pa+dx] - b[pb+dx];
    sum += diff*diff;
}

编辑:

关于有符号和无符号字节算术似乎存在一些混淆。如果您怀疑它们是相同的,请执行以下命令:

byte a = -128;
byte b = 127;
int diff = a - b;
System.out.println(diff); // -255

a = 127;
b = -128;
diff = a - b;
System.out.println(diff); // 255

原因 diff值的范围大于byte(-128..127),是java自动将byte扩展为int < em>在计算之前,因为目标变量是int

答案 1 :(得分:1)

在我使用不同的C ++编译器和不同的Java版本测试相同的算法后,我得出结论,GCC是非常良好的编译器,它比intel和clang更好地优化代码!

这些是在C ++和Java中实现的相同算法的运行时(当上面的行是运行时的96%时:

Intel 12.1  1:58
GCC 4.6     0:43
GCC 4.4     0:43
Clang       1:20
Java 7      1:20
Java 6      1:23

这表明Java运行速度和clang一样快,英特尔编译器出于某种原因做得非常糟糕,但是gcc给出了最好的结果,所以我不能指望Java运行得比 大多数C ++编译器都可以。

注意这是由gcc:

生成的程序集
.L225:
    movzbl  (%rcx), %r8d
    movzbl  (%rsi), %r10d
    addl    $1, %edx
    addq    $1, %rcx
    addq    $1, %rsi
    subl    %r10d, %r8d
    imull   %r8d, %r8d
    movslq  %r8d, %r8
    addq    %r8, %rax
    cmpl    %edx, %ebp
    ja      .L225

这是由clang生成的:

.LBB0_26:
    movzbl  (%r11), %r13d
    movzbl  (%r14), %esi
    subl    %r13d, %esi
    imull   %esi, %esi
    movslq  %esi, %rsi
    addq    %rsi, %rcx
    incq    %r11
    incq    %r14
    decq    %r12
    jne     .LBB0_26

有什么区别?海湾合作委员会重新安排指示,以便他们可以 在管道中并行运行,例如:

    movzbl  (%rcx), %r8d
    movzbl  (%rsi), %r10d
    addl    $1, %edx
    addq    $1, %rcx
    addq    $1, %rsi

总的来说,Java运行时间很好。

在向英特尔编译器提供-xHost选项(优化当前CPU)后,

编辑,运行时间提高到56秒(使用mmx指令),但仍然没有gcc快,但是比Java好一点

答案 2 :(得分:1)

& 0xFF移到循环外部。

通过计算int[] - ab的版本并使用这些来重写您的循环来执行此操作。

答案 3 :(得分:-1)

如果“size”,如果数组a或b的大小可以避免条件:

try{
    for (int dx = 0; ; dx++) {
        ...
        ...
    }
}catch(ArrayIndexOutOfBoundException e){}

这两条直线还是弯曲的?您可以发布问题的格式表示,或数组的数字示例吗?也许有更好的几何解决方案?