{{announcement.body}}
{{announcement.title}}

Measuring Performance of Your Methods Using JMH in Java

DZone 's Guide to

Measuring Performance of Your Methods Using JMH in Java

In this article, I will be referring method as a component in isolation and show you how to test your methods using JMH as per their performances.

· Performance Zone ·
Free Resource

rulers

Measure Java performance!

From JDK-12 onwards, the JDK comes with JMH (Java Microbenchmark Harness), It is a toolkit that helps you implement Java microbenchmarks correctly. JMH is developed by the same people who implement the Java virtual machine (JVM) so they know the internals and how Java makes optimizations at run time.

You may also like: JMH: Benchmark REST APIs

Why JMH?

There are many optimizations that the JVM or underlying hardware may apply to your component when the benchmark executes that component in isolation. These optimizations may not be possible to apply when the component is running as part of a larger application. Badly implemented microbenchmarks may thus make you believe that your component’s performance is better than it will be in reality.

Whenever we come across a problem, we tend to solve it recursively, iteratively or by using inbuilt methods provided in our language. After coding we tend to confuse that for a given set of data(large, small, Fixed) will I have a better edge to use inbuilt methods or method 1 or method 2 or...method 3.

In this article, I will be referring method as a component in isolation, As my whole agenda is to show you how to test your methods using JMH as per their performances.

Before starting there are few prerequisites, If you don’t have JDK 12 then you need to import the dependencies in your project for that you can either download the JARs of making a maven project and adding below dependencies:

Java
x
15
 
1
  <dependencies>
2
<dependency>
3
<artifactId>jmh-core</artifactId>
4
<groupId>org.openjdk.jmh</groupId>
5
<version>${jmh.version}</version>
6
</dependency>
7
<dependency>
8
<artifactId>jmh-generator-annprocess</artifactId>
9
<groupId>org.openjdk.jmh</groupId>
10
<version>${jmh.version}</version>
11
</dependency>
12
</dependencies>
13
<p>
14
<jmh.version>1.21</jmh.version>
15
  </properties>


For the sake of simplicity, let's take an example to generate N natural numbers and store them in a List.

  • A simple or traditional approach will be to use a loop which will execute from 1 to N and store each number to List<Integer> list by list.add() .
  • A more functional approach will be to use stream to generate a Intstream from 1 to N and then store than to list.
  • Java
    xxxxxxxxxx
    1
    49
     
    1
    import java.util.ArrayList;
    2
    import java.util.List;
    3
    import java.util.stream.Collectors;
    4
    import java.util.stream.IntStream;
    5
    import org.openjdk.jmh.annotations.Benchmark;
    6
    import org.openjdk.jmh.annotations.BenchmarkMode;
    7
    import org.openjdk.jmh.annotations.Mode;
    8
    import org.openjdk.jmh.annotations.Param;
    9
    import org.openjdk.jmh.annotations.Scope;
    10
    import org.openjdk.jmh.annotations.State;
    11
    import org.openjdk.jmh.runner.Runner;
    12
    import org.openjdk.jmh.runner.RunnerException;
    13
    import org.openjdk.jmh.runner.options.Options;
    14
    import org.openjdk.jmh.runner.options.OptionsBuilder;
    15
     
               
    16
    @State(Scope.Thread)
    17
    public class Testing {
    18
     
               
    19
      @Param({"10"})
    20
      private int number;
    21
     
               
    22
      @Benchmark
    23
      @BenchmarkMode({Mode.All})
    24
      //traditional method to generate N numbers and store it in List
    25
      public List<Integer> traditionalMethod(Testing T) {
    26
        List<Integer> list = new ArrayList<>();
    27
        for (int i = 1; i <= number; i++) {
    28
          list.add(i);
    29
        }
    30
        return list;
    31
      }
    32
     
               
    33
      @Benchmark
    34
      @BenchmarkMode({Mode.All})
    35
      //using #stream to generate N numbers and store it in List
    36
      public List<Integer> streamMethod(Testing T) {
    37
        return IntStream.rangeClosed(1, number).boxed().collect(Collectors.toList());
    38
      }
    39
     
               
    40
      public static void main(String[] args) throws RunnerException {
    41
        Options opt = new OptionsBuilder()
    42
            .include(Testing.class.getSimpleName())
    43
            .forks(1)
    44
            .build();
    45
     
               
    46
        new Runner(opt).run();
    47
      }
    48
    }
    49
     
               


    After running the program the results are as follows:

    The throughput of the stream method is better for the small range of 10, it might or might not be the same for the larger data set.

    The detailed project has been uploaded to GitHub, you can fork it and run in your own local environment and can do modify or add your own methods and check how they are working in terms of performance.

    The following article used @BenchmarkMode({Mode.All}) which will benchmark all the following:

    Throughput("thrpt", "Throughput, ops/time"),
    AverageTime("avgt", "Average time, time/op"),
    SampleTime("sample", "Sampling time"),
    SingleShotTime("ss", "Single shot invocation time"),
    All("all", "All benchmark modes");

    In case you need the only Throughput to be measured then use Mode.Throughput.

    GitHub Link


    Further Reading

    JMH Performance Testing InfinityDB

    How to Improve the Performance of a Java Application

    Addressing Application Performances in Java Applications

    Topics:
    perforamnce ,java 1.8 ,jmh ,jdk ,jvm

    Opinions expressed by DZone contributors are their own.

    {{ parent.title || parent.header.title}}

    {{ parent.tldr }}

    {{ parent.urlSource.name }}