エンジニア的なネタを毎週書くブログ

東京でWebサービスの開発をしています 【英語版やってみました】http://taichiw-e.hatenablog.com/

SpringBootのアプリで、JMHを使ってみた

メソッドのちょっとした書き方の違いによる速度の計測をしたくて(Micro Benchmarkというらしい。対義語はMacro Benchmark)、JMHで計測をしてみました。

JMHのオフィシャルページを見ると、mvn archetype:generate なるものが出てきて「なんじゃこりゃ?」だったり
適当にググったページでは、そもそも古くて今は動かないサンプルだったりと、どうにもわかりにくかったのですが、こちらのページのとおりに試してみたところ、うまくいきました。
Microbenchmarking with Java | Baeldung

それでもハマったところ
1. SpringBootのmain methodがあるクラスに、Benchmark用のmain methodも書いたところ、以下のようなエラーが出て何故か起動できず。

# JMH version: 1.21
# VM version: JDK 1.8.0_121, Java HotSpot(TM) 64-Bit Server VM, 25.121-b13
# VM invoker: C:\Program Files\Java\jdk1.8.0_121\jre\bin\java.exe
# VM options: -Xmx3000m -Ddebug -XX:TieredStopAtLevel=1 -Xverify:none -Dspring.output.ansi.enabled=always -Dzookeeper.address=b -Dcom.sun.management.jmxremote -Dcom.sun.management.jmxremote.port=51723 -Dcom.sun.management.jmxremote.authenticate=false -Dcom.sun.management.jmxremote.ssl=false -Djava.rmi.server.hostname=localhost -Dspring.liveBeansView.mbeanDomain -Dspring.application.admin.enabled=true -javaagent:C:\Program Files\JetBrains\IntelliJ IDEA 2018.1\lib\idea_rt.jar=51724:C:\Program Files\JetBrains\IntelliJ IDEA 2018.1\bin -Dfile.encoding=UTF-8
# Warmup: 5 iterations, 10 s each
# Measurement: 5 iterations, 10 s each
# Timeout: 10 min per iteration
# Threads: 1 thread, will synchronize iterations
# Benchmark mode: Throughput, ops/time
# Benchmark: rakuten.travel.availability.calculation.api.BenchmarkRunner.benchMarkKick3

# Run progress: 0.00% complete, ETA 00:10:00
# Warmup Fork: 1 of 1
Error: Exception thrown by the agent : java.rmi.server.ExportException: Port already in use: 51723; nested exception is: 
	java.net.BindException: Address already in use: JVM_Bind
<forked VM failed with exit code 1>
<stdout last='20 lines'>
</stdout>
<stderr last='20 lines'>
Error: Exception thrown by the agent : java.rmi.server.ExportException: Port already in use: 51723; nested exception is: 
	java.net.BindException: Address already in use: JVM_Bind
</stderr>

→ 上記ページのように、mainメソッドを書くための専用のクラスを別に作ったところ、問題なく動作。

2. テスト対象のメソッドにパラメータを渡す方法がわからなかった
→ これも上記ページに書いてある


おまけ
とあるメソッドのリファクタ結果

Benchmark                        Mode  Cnt       Score        Error  Units
BenchmarkRunner.benchMarkKick1  thrpt    5   29271.881 ±   1088.831  ops/s
BenchmarkRunner.benchMarkKick2  thrpt    5   74336.732 ±   4597.243  ops/s
BenchmarkRunner.benchMarkKick3  thrpt    5  280990.396 ± 185017.629  ops/s

1はもとのまま。2はちょっとリファクタリング。3はもっとリファクタリング
もとより桁一つ速くなった。うひょー!