“Loop unswitching” optimization is not working

后端 未结 1 819
没有蜡笔的小新
没有蜡笔的小新 2021-01-15 00:56

I heard that Java supports \"Loop Unswitching\", so I simply tested it in JMH.

I thought they would be exactly the same after JIT. Why is this?

priva         


        
1条回答
  •  挽巷
    挽巷 (楼主)
    2021-01-15 01:32

    JMH disables inlining of Blackhole.consume method. A non-inlined method is a black box to the JVM - the compiler does not know whether such method modifies fields, throws exceptions, which registers it trashes etc. JIT compiler cannot apply many optimizations across such method call. (Imagine that a black box method uses Reflection to modify bool field, and thus loop unswitching will become invalid).

    HotSpot JVM still supports loop unswitching when the compilation scope includes the whole loop body, and the condition is known to be constant throughout the loop.

    Consider the modified benchmark:

    @State(Scope.Benchmark)
    public class LoopUnswitching {
        private static final int TIMES = 10_000;
    
        private final Random r = new Random(93);
        private final int[] x = r.ints(TIMES).toArray();
        private final int[] y = r.ints(TIMES).toArray();
    
        private boolean bool;
    
        @Setup(Level.Invocation)
        public void setup() {
            bool = r.nextBoolean();
        }
    
        @Benchmark
        public int test1() {
            int sum = 0;
            for (int i = 0; i < TIMES; i++) {
                if (bool) {
                    sum += x[i];
                } else {
                    sum += y[i];
                }
            }
            return sum;
        }
    
        @Benchmark
        public int test2() {
            int sum = 0;
            if (bool) {
                for (int i = 0; i < TIMES; i++) {
                    sum += x[i];
                }
            } else {
                for (int i = 0; i < TIMES; i++) {
                    sum += y[i];
                }
            }
            return sum;
        }
    }
    

    In this case the performance of test1 and test2 will be similar:

    Benchmark              Mode  Cnt     Score   Error  Units
    LoopUnswitching.test1  avgt   10  2910,432 ± 3,287  ns/op
    LoopUnswitching.test2  avgt   10  2912,922 ± 9,367  ns/op
    

    0 讨论(0)
提交回复
热议问题