310 words
2 minutes
How to use jmh with spring boot
Introduction
Application performance is a concern of every developer working with software. JMH provides an easy API for developer to benchmark application performance.
In this post, I’ll walk you through to how to use jmh with spring boot. You’ll learn how to set up Spring Boot Test and how to enable jmh benchmark in your test code.
Create a Spring Boot Project
curl https://start.spring.io/starter.tgz -d dependencies=h2,data-jpa,data-rest,lombok \
-d groupId=io.github.bhuwanupadhyay \
-d artifactId=example \
-d packageName=io.github.bhuwanupadhyay.tutorial \
-d baseDir=example \
-d bootVersion=2.2.2.RELEASE | tar -xzvf -
cd example
Add JMH dependencies in pom.xml
<dependency>
<groupId>org.openjdk.jmh</groupId>
<artifactId>jmh-core</artifactId>
<version>1.22</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.openjdk.jmh</groupId>
<artifactId>jmh-generator-annprocess</artifactId>
<version>1.22</version>
<scope>test</scope>
</dependency>
Let’s add some classes for benchmark
OrderLine
entity class
@Entity
@Getter
@Setter
@ToString(exclude = {"itemId", "addressLine", "quantity"})
@EqualsAndHashCode(exclude = {"itemId", "addressLine", "quantity"})
class OrderLine implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private Long itemId;
private String addressLine;
private Integer quantity;
}
OrderLineRepository
repository class for an entityOrderLine
interface OrderLineRepository extends JpaRepository<OrderLine, Long> {
}
- The spring boot configuration
application.properties
spring.application.name=example
spring.jpa.hibernate.ddl-auto=create-drop
JMH Benchmark Code
Let’s benchmark insert operation for OrderLine
entity into database.
@Spring BootTest
@State(Scope.Benchmark)
@BenchmarkMode(Mode.AverageTime)
@OutputTimeUnit(TimeUnit.MILLISECONDS)
public class DemoApplicationTests {
private static OrderLineRepository repository;
@Autowired
public void setRepository(OrderLineRepository repository) {
DemoApplicationTests.repository = repository;
}
@Test
public void runBenchmarks() throws Exception {
Options opts = new OptionsBuilder()
// set the class name regex for benchmarks to search for to the current class
.include("\\." + this.getClass().getSimpleName() + "\\.")
.warmupIterations(3)
.measurementIterations(3)
// do not use forking or the benchmark methods will not see references stored within its class
.forks(0)
// do not use multiple threads
.threads(1)
.shouldDoGC(true)
.shouldFailOnError(true)
.jvmArgs("-server")
.build();
new Runner(opts).run();
}
@Benchmark
public void dbInserts(Parameters parameters) {
int size = Integer.parseInt(parameters.batchSize);
for (int i = 0; i < size; i++) {
OrderLine line = new OrderLine();
line.setAddressLine("Jhamsikhel Ward #3, Arun Thapa Chwok, Lalitpur, Nepal");
line.setItemId(1L);
line.setQuantity(i);
repository.save(line);
}
}
@State(value = Scope.Benchmark)
public static class Parameters {
@Param({"1", "1000"})
String batchSize;
}
}
Benchmark Result for this example
How to use jmh with spring boot
https://semusings.dev/posts/2019/2019-04-20-how-to-use-jmh-with-spring-boot/