torutkのブログ

ソフトウェア・エンジニアのブログ

JMHでマイクロベンチマーク

JavaOne 2014 SFのセッションでJMHを使った性能計測をしていた他、先日日記で紹介したJava Magazineでも記事になっています。
http://d.hatena.ne.jp/torutk/20141006/p1

そこで、実際に試してみました。

まず、JMHツールのホームページを参照します。
http://openjdk.java.net/projects/code-tools/jmh/

推奨する使用法が記載されているので、それに沿って進めます。

まず、インターネット接続環境でJDK 8およびmavenをインストール・セットアップしたマシンを用意します。
JMHはビルドプロジェクトをmavenで作成するので、まずは次を実行します。オプションはJMHホームページのまま実行してみます。理解したらいろいろ変えることとします。

~$ mkdir jmh_excer
~$ cd jmh_excer
jmh_excer$ mvn archetype:generate \
 -DinteractiveMode=false \
 -DarchetypeGroupId=org.openjdk.jmh \
 -DarchetypeArtifactId=jmh-java-benchmark-archetype \
 -DgroupId=org.sample \
 -DartifactId=test \
 -Dversion=1.0
  :
jmh_excer$ ls
test
jmh_excer$

すると、testディレクトリができます。ディレクトリツリーは次のようになりました。

test
  +-- pom.xml
  +-- src
        +-- main
              +-- org
                    +-- sample
                          +-- MyBenchmark.java

どうやら、artifactIdで指定したトップレベディレクトリとgroupIdで指定したパッケージ構造で生成されるようです。生成されたMyBenchmark.javaは次です(ファイル先頭コメント削除しています)。

package org.sample;

import org.openjdk.jmh.annotations.Benchmark;

public class MyBenchmark {

    @Benchmark
    public void testMethod() {
        // place your benchmarked code here
    }

}

ビルドは次です。

~jmh_excer$ cd test
test$ mvn clean install
  :
test$

ビルドすると、targetディレクトリとその中にbenchmarks.jarが生成されます。(他にもいろいろmaven流のディレクトリ・ファイルが生成されています)

実行します。

test$ java -jar target/benchmarks.jar
# VM invoker: C:\java\jdk1.8.0\jre\bin\java.exe
# VM options: <none>
# Warmup: 20 iterations, 1 s each
# Measurement: 20 iterations, 1 s each
# Timeout: 10 min per iteration
# Threads: 1 thread, will synchronize iterations
# Benchmark mode: Throughput, ops/time
# Benchmark: org.sample.MyBenchmark.testMethod

# Run progress: 0.00% complete, ETA 00:06:40
# Fork: 1 of 10
# Warmup Iteration   1: 1516121404.924 ops/s
# Warmup Iteration   2: 1497277602.725 ops/s
  :
Iteration  19: 1483167358.513 ops/s
Iteration  20: 1458119813.650 ops/s


Result: 1461902009.817 ±(99.9%) 8548155.688 ops/s [Average]
  Statistics: (min, avg, max) = (1301371929.415, 1461902009.817, 1516355326.822), stdev = 36193426.438
  Confidence interval (99.9%): [1453353854.129, 1470450165.504]


# Run complete. Total time: 00:08:03

Benchmark                      Mode  Samples           Score         Error  Units
o.s.MyBenchmark.testMethod    thrpt      200  1461902009.817 ± 8548155.688  ops/s

test$

Warmupを20回実施してからメソッド実行を20回実施するサイクルを10回繰り返し実施します。
ここでWarmup、メソッド実行の1回とは、メソッドの呼び出しが1回を意味するのではなく、1秒間メソッドを呼び出し続けることを意味していると思われます。

プログラム実施後、結果を表示します。

結果のScoreは、秒間何回メソッドを実行したかを示していると思われます。
Errorは標準偏差(または分散?)かと思われます。
ベンチマーク対象は@Benchmarkアノテーションを付与したメソッドです。このアノテーションは同じクラスに複数定義することができ、それぞれのメソッド毎に結果が表示されます。

Warmup回数、メソッド実行回数、サイクル回数はコマンドラインオプション、またはクラスへのアノテーションで指定することができます。