【发布时间】:2020-09-07 21:22:15
【问题描述】:
我有一个带有 2 个计数器的循环:i 和 j。如果它们具有相同的值 - 迭代比它们的值不同时更快:
Benchmark Mode Cnt Score Error Units
FloatsArrayBenchmark.times thrpt 20 341805.800 ± 1623.320 ops/s
FloatsArrayBenchmark.times2 thrpt 20 198764.909 ± 1608.387 ops/s
Java 字节码是相同的,这意味着它与一些较低级别的优化有关。有人可以解释为什么会这样吗?这是基准:
import org.openjdk.jmh.annotations.*;
public class FloatsArrayBenchmark {
public static void main(String[] args) throws Exception {
org.openjdk.jmh.Main.main(new String[]{FloatsArrayBenchmark.class.getSimpleName()});
}
@Benchmark @Fork(value = 1, warmups = 0)
public void times(Data data) {
float[] result = new float[10000];;
for (int i = 0, j=0; i < 9_999; i++,j++)
result[j] = data.floats[i] * 10;
}
@Benchmark @Fork(value = 1, warmups = 0)
public void times2(Data data) {
float[] result = new float[10000];
for (int i = 0,j=1; i < 9_999; i++,j++)
result[j] = data.floats[i] * 10;
}
@State(Scope.Benchmark)
public static class Data {
private final float[] floats = new float[10000];
}
}
环境:
- MacOS,试过Java8、Java11、Java14
- 2.4 GHz 四核 Intel Core i5
【问题讨论】:
-
如果 src 和 dst 数组相对于 4k 页面边界具有相同的对齐方式,则可能是 4k 别名(以后加载的错误依赖性)存储在您正在阅读的位置之前的 1 个索引。对于最简单的情况(相同的索引),Java8 可能太旧了,无法使用 SIMD 进行自动矢量化。
-
我认为第一个比较慢,因为双分号
;;...... NOT ...... ???? -
@PeterCordes,Java11 - 结果相同。下载 Java14 试用。不确定别名 - 将不得不阅读。
-
@Andreas,这是我的第一个猜测;)已编辑。
-
此时,您必须进行程序集转储。正如彼得建议的那样,我的猜测可能与缓存边界有关,但如果您真的想知道,请深入挖掘。
标签: java for-loop optimization micro-optimization