Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does inlining Math.max give over 200x slower code?

I've recently started benchmarking some Java code in order to get the best performance results for my program and noticed some strange thing. Namely, I've benchmarked the following methods:

private static final int n = 10000;

public static void test0(){
    int m = 0;

    for(int i = 0; i < n; ++i){
        m = Math.max(i, m);
    }
}

public static void test1(){
    int m = 0;

    for(int i = 0; i < n; ++i){
        m = ((i >= m) ? i : m);
    }
}

and got those results:

          | Test 0          | Test 1          | 
----------+-----------------+-----------------+-
Average:  | 51,77 ns        | 13956,63 ns     | 
Best:     | 0,00 ns         | 6514,00 ns      | 
Worst:    | 25,45 ms        | 60,50 ms        | 
Tries:    | 16971233        | 16971233        | 

After searching over SO (i.e. Is Math.max(a,b) or (a>b)?a:b faster in Java?) it was certain for me that test1 shouldn't be so much slower.

These methods were tested randomly on 8 threads in 30 seconds and every benchmark I run seems similar. I use jdk1.8.0_45.

So, why is test1 over 200 times slower than test0?

like image 494
Kamil Jarosz Avatar asked Jul 19 '16 19:07

Kamil Jarosz


People also ask

Is Max math slower?

max method is likely to be slower, but it also may return a different result if one of the arguments is NaN.

Is math min slow?

Using Math. Min in a loop is almost 4 times slower than before.


2 Answers

Since Math.max is a static function, the compiler may figure out that the code does nothing at all and simply optimizes the execution by not executing it!

Variable m being local to the function, assigning it does not help as it is never read.

You need to make sure that the execution somehow modifies something so it is not aggressively optimized by the compiler.

For instance, you can can simply print the value of m at the end of the test or make m a class variable that can be accessed later or even sum the result as I originally suggested in the comment.

like image 55
Jean Logeart Avatar answered Nov 14 '22 15:11

Jean Logeart


Math.max(a,b) can be very aggressivly/obviously optimized into a native instruction for the processor.

For the ternary, the simple transformation into processor instruction would be a compare+jump, especially the jump is costly.

To optimize the ternary into the JIT(Just in time compiler) must recognize that the code expresses a max and the native instruction is best.

The JIT might eventually recognize this but until that point it will be slower.

like image 41
k5_ Avatar answered Nov 14 '22 14:11

k5_