java benchmarks examples

In this post two examples of java benchmark:

  • simple time example
  • JMH

Simple time benchmark

If you need a rough idea for the elapsed time in seconds or milliseconds than you can use:

  • System.nanoTime();
  • System.currentTimeMillis()

In the program below we are getting 43th Fibonacci number by recursion. We are measuring the start and the end time. After that we are outputting time in several different formats: nanoseconds, milliseconds, seconds, minutes. Depending on your need you can get decimal precision for the seconds by division instead of using TimeUnit method. In this example you can see also how to convert nanoseconds to other units by method:

double seconds = TimeUnit.SECONDS.convert(elapsedTime, TimeUnit.NANOSECONDS);

The simple code execution measurement in seconds:

package benchmark;

import java.util.concurrent.TimeUnit;

public class Simple {

    public static void main(String[] args) {

        int n = 43;
        
        System.out.println("Fibonacci iteration:");
        
        //
        // Start , action and end
        //
        long start = System.nanoTime();
        
        int fibN = fib(n);
        System.out.printf("result = %d is: %d \n", n, fibN);
        
        long elapsedTime = System.nanoTime() - start;

        //
        // Output in different formats: ms, ns, seconds, minutes
        //
        
        double seconds = TimeUnit.SECONDS.convert(elapsedTime, TimeUnit.NANOSECONDS);
        double secondDecimalPrecision = (double)elapsedTime / 1000000000.0;
        double ms = TimeUnit.MILLISECONDS.convert(elapsedTime, TimeUnit.NANOSECONDS);
        double minutes = TimeUnit.MINUTES.convert(elapsedTime, TimeUnit.NANOSECONDS);

        System.out.printf("Nanoseconds: %d ms\n", elapsedTime );
        System.out.printf("Miliseconds: %f ms\n", ms );
        System.out.printf("Seconds: %f ms\n", seconds);
        System.out.printf("Seconds2: %f ms\n", secondDecimalPrecision);
        System.out.printf("MInutes: %f ms\n", minutes);

    }

    static int fib(int n) {
        if (n<2) return 1;
        else return fib(n-1) + fib(n-2);
    }
}

result:

result = 43 is: 701408733 
Nanoseconds: 2697330235 ms
Miliseconds: 2697.000000 ms
Seconds: 2.000000 ms
Seconds2: 2.697330 ms
MInutes: 0.000000 ms

Java Microbenchmark Harness example

For better, more precise and complete examples you can use JMH (Java Microbenchmark Harness). This one is more accurate but also more complicated to be done. You will need additional maven libraries to be added to your project.

Import required dependencies

Open your pom.xml file and add this dependencies inside (version 1.20 is the last one available at the time of writing the article. For more recent you can check: JMH Core )

<!-- https://mvnrepository.com/artifact/org.openjdk.jmh/jmh-core -->
<dependency>
    <groupId>org.openjdk.jmh</groupId>
    <artifactId>jmh-core</artifactId>
    <version>1.20</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.openjdk.jmh/jmh-generator-annprocess -->
<dependency>
    <groupId>org.openjdk.jmh</groupId>
    <artifactId>jmh-generator-annprocess</artifactId>
    <version>1.20</version>
    <scope>provided</scope>
</dependency>

Java classes and methods

Now adding the Java code - the code is searching for 52-th number from the Fibonacci sequence by recursion. Two classes are needed one to run the benchmark and the one that will be test. The Fibonacci code is in the second one:

  • class BenchmarkRunner - used to run the benchmark
package benchmark;

public class BenchmarkRunner {
    public static void main(String[] args) throws Exception {
        org.openjdk.jmh.Main.main(args);
    }
}
  • class TestBM - the class that will be benchmarked. So here as you can see we have the code and the benchmark option.
package benchmark;

import org.openjdk.jmh.annotations.*;

public class TestBM {

    @Benchmark
    @BenchmarkMode(Mode.AverageTime)
    @Fork(value = 1)
    @Warmup(iterations = 2)
    @Measurement(iterations = 1)
    public void init() {

        fib(52);
        //fibbonaci(300);
    }
    
    static int fib(int n) {
        if (n<2) return 1;
        else return fib(n-1) + fib(n-2);
    }

    double fibbonaci(int n){
        double prev=0d, next=1d, result=0d;
        for (int i = 0; i < n; i++) {
            result=prev+next;
            prev=next;
            next=result;
        }
        return result;
    }
}

result:

# Run progress: 0.00% complete, ETA 00:00:03
# Fork: 1 of 1
# Warmup Iteration   1: 185.060 s/op
# Warmup Iteration   2: 184.308 s/op
Iteration   1: 185.068 s/op


Result "benchmark.TestBM.init":
  185.068 s/op


# Run complete. Total time: 00:09:15

Benchmark    Mode  Cnt    Score   Error  Units
TestBM.init  avgt       185.068           s/op

You can play with the Fibonacci number - for 52 we get 185 seconds for recursive execution.

Settings

You can customize JMH in many ways. Here we are using simple configuration to measure the average time. The number of iterations for warm-up and measurement are set to 2 and 1. By default they are higher - 10 and 20.

Configuration:

    @Benchmark
    @BenchmarkMode(Mode.AverageTime)
    @Fork(value = 1)
    @Warmup(iterations = 2)
    @Measurement(iterations = 1)

More information

Note: if you use JMH with intellij you can have a look on this plugin:
idea-jmh-plugin

If you use it without plugin in maven project you may need to clean your project - maven clean. Otherwise you can have unexpected results based on old executions.

Related Article