Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Java - Repeated function call reduces execution time

I have this following code

public class BenchMark {
    public static void main(String args[]) {
        doLinear();

        doLinear();

        doLinear();

        doLinear();

    }


    private static void doParallel() {
        IntStream range = IntStream.range(1, 6).parallel();

        long startTime = System.nanoTime();
        int reduce = range
                .reduce((a, item) -> a * item).getAsInt();
        long endTime = System.nanoTime();
        System.out.println("parallel: " +reduce + " -- Time: " + (endTime - startTime));
    }

    private static void doLinear() {
        IntStream range = IntStream.range(1, 6);

        long startTime = System.nanoTime();
        int reduce = range
                .reduce((a, item) -> a * item).getAsInt();
        long endTime = System.nanoTime();
        System.out.println("linear: " +reduce + " -- Time: " + (endTime - startTime));
    }

}

I was trying to benchmark streams but came through this execution time steadily decreasing upon calling the same function again and again

Output:

linear: 120 -- Time: 57008226
linear: 120 -- Time: 23202
linear: 120 -- Time: 17192
linear: 120 -- Time: 17802

Process finished with exit code 0

There is a huge difference between first and second execution time.

I'm sure JVM might be doing some tricks behind the scenes but can anybody help me understand whats really going on there ?

Is there anyway to avoid this optimization so I can benchmark true execution time ?

like image 949
Siva Avatar asked Aug 16 '15 05:08

Siva


1 Answers

I'm sure JVM might be doing some tricks behind the scenes but can anybody help me understand whats really going on there?

  1. The massive latency of the first invocation is due to the initialization of the complete lambda runtime subsystem. You pay this only once for the whole application.

  2. The first time your code reaches any given lambda expression, you pay for the linkage of that lambda (initialization of the invokedynamic call site).

  3. After some iterations you'll see additional speedup due to the JIT compiler optimizing your reduction code.

Is there anyway to avoid this optimization so I can benchmark true execution time?

You are asking for a contradiction here: the "true" execution time is the one you get after warmup, when all optimizations have been applied. This is the runtime an actual application would experience. The latency of the first few runs is not relevant to the wider picture, unless you are interested in single-shot performance.

For the sake of exploration you can see how your code behaves with JIT compilation disabled: pass -Xint to the java command. There are many more flags which disable various aspects of optimization.

like image 54
Marko Topolnik Avatar answered Nov 14 '22 05:11

Marko Topolnik