310 words
2 minutes
How to use jmh with spring boot
2019-04-20

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 entity OrderLine
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#

Image

How to use jmh with spring boot
https://semusings.dev/posts/2019/2019-04-20-how-to-use-jmh-with-spring-boot/
Author
Bhuwan Prasad Upadhyay
Published at
2019-04-20