Previously we had an example on using JMH with Gradle for our benchmarks.
Since maven is the most popular build tool for Java it is worth to setup an example.
Let’s add the dependency to our project
<dependencies> <dependency> <groupId>org.openjdk.jmh</groupId> <artifactId>jmh-core</artifactId> <version>1.36</version> </dependency> <dependency> <groupId>org.openjdk.jmh</groupId> <artifactId>jmh-generator-annprocess</artifactId> <version>1.36</version> </dependency> </dependencies>
Let’s add a simple benchmark for Array initialization:
import java.util.concurrent.TimeUnit; import org.openjdk.jmh.annotations.Benchmark; import org.openjdk.jmh.annotations.BenchmarkMode; import org.openjdk.jmh.annotations.Mode; import org.openjdk.jmh.annotations.OutputTimeUnit; import org.openjdk.jmh.annotations.Scope; import org.openjdk.jmh.annotations.State; @State(Scope.Benchmark) @OutputTimeUnit(TimeUnit.MICROSECONDS) @BenchmarkMode(Mode.All) public class ArrayInitializationBenchmark { @Benchmark public Integer[] initialize() { return new Integer[256]; } }
We can run the benchmark in various ways. A main class org.openjdk.jmh.Main is provided. This class can be used to pass arguments and execute the benchmarks of interest. So what we can do is to use the maven shade plugin and generate a binary just for the benchmarks.
<build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-shade-plugin</artifactId> <version>3.2.0</version> <executions> <execution> <phase>package</phase> <goals> <goal>shade</goal> </goals> <configuration> <finalName>jmh-benchmarks</finalName> <transformers> <transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer"> <mainClass>org.openjdk.jmh.Main</mainClass> </transformer> </transformers> </configuration> </execution> </executions> </plugin> </plugins> </build>
By running
mvn clean install
We shall have two jars generated. The jar jmh-benchmarks.jar is the one of interest since it will come configured with the org.openjdk.jmh.Main class.
Running the benchmark is simple
java -jar target/jmh-benchmarks.jar ArrayInitializationBenchmark
It we need more customisations we can also create our own main method and define our benchmarks that we shall pass to the JMH Runner.
package com.gkatzioura.concurrency.benchmark; import org.openjdk.jmh.runner.Runner; import org.openjdk.jmh.runner.RunnerException; import org.openjdk.jmh.runner.options.Options; import org.openjdk.jmh.runner.options.OptionsBuilder; public class BenchmarkMain { public static void main(String[] args) throws RunnerException { Options opt = new OptionsBuilder().include(ArrayInitializationBenchmark.class.getSimpleName()).build(); new Runner(opt).run(); } }
The results will be printed on console
Benchmark Mode Cnt Score Error Units ArrayInitializationBenchmark.initialize thrpt 25 10.050 ± 1.045 ops/us ArrayInitializationBenchmark.initialize avgt 25 0.116 ± 0.011 us/op ArrayInitializationBenchmark.initialize sample 8122862 0.147 ± 0.003 us/op ArrayInitializationBenchmark.initialize:initialize·p0.00 sample ≈ 0 us/op ArrayInitializationBenchmark.initialize:initialize·p0.50 sample 0.125 us/op ArrayInitializationBenchmark.initialize:initialize·p0.90 sample 0.208 us/op ArrayInitializationBenchmark.initialize:initialize·p0.95 sample 0.250 us/op ArrayInitializationBenchmark.initialize:initialize·p0.99 sample 0.417 us/op ArrayInitializationBenchmark.initialize:initialize·p0.999 sample 1.374 us/op ArrayInitializationBenchmark.initialize:initialize·p0.9999 sample 16.608 us/op ArrayInitializationBenchmark.initialize:initialize·p1.00 sample 2179.072 us/op ArrayInitializationBenchmark.initialize ss 5 2.992 ± 0.593 us/op
We have all the benchmark modes enabled thus each one of them is listed: Throughput, Average, Single Shot and Sample.
For a more detailed view on the benchmark and the options we have you can check the previous blog on JMH.
That’s it! Happy benchmarking