JMH stands for Java Microbenchmark Harness. JMH is a tool that makes benchmarking more accurate and straightforward.
Benchmarking is extremely useful for high-performance applications, helping you choose the algorithm or library that delivers the best speed.
Alright! Enough with the theory, let’s get into practice. What we need to do is build a project comparing the speed of different string concatenation approaches in Java. Make sure you have Java and Gradle installed first!
Step 1: Create a Gradle project
Open Terminal and run the following command:gradle init
Then select the following options:
Select type of project to generate:
1: basic
2: groovy-application
3: groovy-library
4: java-application
5: java-library
6: kotlin-application
7: kotlin-library
8: scala-library
Enter selection (default: basic) [1..8] 4
Select build script DSL:
1: groovy
2: kotlin
Enter selection (default: groovy) [1..2] 1
Select test framework:
1: junit
2: testng
3: spock
Enter selection (default: junit) [1..3] 1
Project name (default: jmh-gradle-example):
Source package (default: jmh.gradle.example): tri.le.jmh
Step 2: Copy the main directory to jmh
cp -r src/main src/jmh
The purpose of this is to separate the 3 parts: main code, test code, and benchmark code.
Step 3: Update build.gradle
Add id "me.champeau.gradle.jmh" version "0.4.8" to the plugins block.
Step 4: Setup is done, now let’s write code ;))
To make it quick, you can grab this file, and I will explain right away:
| |
Performs “warmup” 5 times, 1 second each. Why do we need warmup? Java automatically optimizes code, so warming up helps us achieve accurate benchmark results.
| |
Executes the benchmark over 5 iterations, 1 second each.
| |
JMH will create 1 child process for each benchmark case. Creating a child process ensures the optimizer is reset and the benchmark results are more accurate.
Step 5: Run the benchmark!
./gradlew --no-daemon clean jmh
The results will be displayed in the console or can be viewed with:cat build/reports/jmh/results.txt
Benchmark Mode Cnt Score Error Units
StringAppend.bmStringBuffer thrpt 5 13566863.267 ± 427443.554 ops/s
StringAppend.bmStringBufferx1000 thrpt 5 36998.492 ± 2895.325 ops/s
StringAppend.bmStringBufferx5 thrpt 5 5529261.499 ± 277625.096 ops/s
StringAppend.bmStringBuilder thrpt 5 13462457.325 ± 978240.749 ops/s
StringAppend.bmStringBuilderx1000 thrpt 5 36989.126 ± 1716.705 ops/s
StringAppend.bmStringBuilderx5 thrpt 5 5466705.447 ± 176616.966 ops/s
StringAppend.bmStringConcat thrpt 5 27930719.298 ± 581249.324 ops/s
StringAppend.bmStringConcatx1000 thrpt 5 47104.039 ± 2358.121 ops/s
StringAppend.bmStringConcatx5 thrpt 5 7170529.805 ± 383608.303 ops/s
StringAppend.bmStringJoin thrpt 5 10204201.921 ± 463528.750 ops/s
StringAppend.bmStringJoinx1000 thrpt 5 30493.885 ± 1708.261 ops/s
StringAppend.bmStringJoinx5 thrpt 5 4322622.068 ± 49032.328 ops/s
StringAppend.bmStringPlus thrpt 5 13689364.101 ± 509784.615 ops/s
StringAppend.bmStringPlusx1000 thrpt 5 288.086 ± 15.175 ops/s
StringAppend.bmStringPlusx5 thrpt 5 5590364.456 ± 277476.212 ops/s
You can also check out the git repo here. :))