相关疑难解决方法(0)

为什么边界检查不会被消除?

我写了一个简单的基准测试,以便找出当通过按位和数组计算数组时是否可以消除边界检查.这几乎就是所有哈希表的作用:它们计算

h & (table.length - 1)
Run Code Online (Sandbox Code Playgroud)

作为索引table,其中hhashCode或派生值.该结果表明,边界检查不被淘汰.

我的基准的想法很简单:计算两个值ij,其中既保证是有效的数组索引.

  • i是循环计数器.当它被用作数组索引时,边界检查被消除.
  • j计算为x & (table.length - 1),x每次迭代时某些值都在变化.当它被用作数组索引时,边界检查不会被消除.

相关部分如下:

for (int i=0; i<=table.length-1; ++i) {
    x += result;
    final int j = x & (table.length-1);
    result ^= i + table[j];
}
Run Code Online (Sandbox Code Playgroud)

另一个实验使用

    result ^= table[i] + j;
Run Code Online (Sandbox Code Playgroud)

代替.时间上的差异可能是15%(在我尝试的不同变体中非常一致).我的问题:

  • 除了绑定检查消除之外还有其他可能的原因吗?
  • 有一些复杂的原因我不明白为什么没有绑定检查消除j

答案摘要

MarkoTopolnik的回答表明它更复杂,并且不能保证取消边界检查是一种胜利,特别是在他的计算机上,"正常"代码比"蒙面"慢.我想这是因为它允许一些额外的优化,在这种情况下显示实际上是有害的(鉴于当前CPU的复杂性,编译器甚至几乎不知道).

leventov的答案清楚地表明,数组边界检查是在"屏蔽"中完成的,并且它的消除使得代码与"正常"一样快.

Donal Fellows指出这样一个事实,即屏蔽不适用于零长度表,x & (0-1)等于x.因此,编译器可以做的最好的事情是用零长度检查替换绑定的检查.但这是恕我直言仍然值得,因为零长度检查可以轻松地移出循环.

建议优化 …

java optimization microbenchmark bounds-check-elimination

20
推荐指数
2
解决办法
964
查看次数

如何编写代码以提示JVM使用向量操作?

一些相关的问题和一年之久:JVM的JIT编译器是否生成使用向量化浮点指令的代码?

前言:我试图在纯java中执行此操作(没有JNI到C++,没有GPGPU工作等等).我已经进行了分析,并且大部分处理时间来自此方法中的数学运算(可能是95%的浮点数学运算和5%的整数运算).我已经将所有Math.xxx()调用减少到足够好的近似值,因此大部分数学运算现在都是浮点数乘以一些加法.

我有一些处理音频处理的代码.我一直在进行调整,并且已经获得了巨大的收益.现在我正在研究手动循环展开以查看是否有任何好处(至少手动展开2,我看到大约25%的改进).在尝试手动展开4时(由于我展开嵌套循环的两个循环,这开始变得非常复杂)我想知道是否有任何我可以做的提示到jvm在运行时它可以使用向量操作(例如SSE2,AVX等......).音频的每个样本都可以完全独立于其他样本计算,这就是为什么我已经能够看到25%的改进(减少浮点计算的依赖性).

例如,我有4个浮点数,循环的4个展开中的每一个都有一个浮点数来保存部分计算的值.我如何声明和使用这些浮子很重要吗?如果我把它变成一个浮点数[4],它会向jvm暗示它们彼此无关,而不是浮动,浮动,浮动,浮动甚至是一类4个公共浮标?有什么我可以做的没有意义,这会杀死我的代码被矢量化的机会?

我在网上看到有关"正常"编写代码的文章,因为编译器/ jvm知道常见模式以及如何优化它们并偏离模式可能意味着更少的优化.至少在不过这种情况下,我也没有想到2展开环之多具有改进的性能,因为它没有,所以我想知道如果有什么我可以做的(或至少这样做),以帮助我机会.我知道编译器/ jvm只会变得更好所以我也要警惕做将来会伤害我的事情.

编辑为好奇:4展开的提高性能的另一个〜25%,比展开了2,所以我真的觉得向量运算会在我的情况下帮助如果JVM支持它(或者是已经使用它们).

谢谢!

java performance jvm-hotspot

18
推荐指数
1
解决办法
1538
查看次数