覚えたら書く

IT関係のデベロッパとして日々覚えたことを書き残したいです。twitter: @yyoshikaw

JMH - 計測結果のレポートをファイルに出力

JMHを使用した計測を行った場合、通常は計測結果はコンソールに出力されますが、 オプションの指定で計測結果をファイルに出力することができます。
また、出力する形式(CSV, JSON, ...)を指定することも可能です。


ファイル名指定で計測結果のレポートを出力する

OptionsBuilder#result で 計測結果を出力するファイルのファイル名を指定すると、ベンチマーク取得後に結果がそのガファイルに出力されます。
(その他のサンプルでも同様ですが、Eclipseで実行した場合は対象プロジェクトのTOPディレクトリ直下に結果のファイルが出力されます)

■サンプルコード

結果を出力するファイル名に"jmh-report.txt"を指定しています。

import java.util.concurrent.TimeUnit;

import org.openjdk.jmh.annotations.Benchmark;
import org.openjdk.jmh.annotations.BenchmarkMode;
import org.openjdk.jmh.annotations.Fork;
import org.openjdk.jmh.annotations.Measurement;
import org.openjdk.jmh.annotations.Mode;
import org.openjdk.jmh.annotations.OutputTimeUnit;
import org.openjdk.jmh.annotations.Warmup;
import org.openjdk.jmh.runner.Runner;
import org.openjdk.jmh.runner.RunnerException;
import org.openjdk.jmh.runner.options.Options;
import org.openjdk.jmh.runner.options.OptionsBuilder;

@Warmup(iterations=3)
@Measurement(iterations=8)
@OutputTimeUnit(TimeUnit.MILLISECONDS)
@BenchmarkMode(Mode.Throughput)
@Fork(1)
public class ResultToFileBenchmark {

    @Benchmark
    public void date() {
        java.util.Date d = new java.util.Date();
    }

    @Benchmark
    public void calndar() {
        java.util.Calendar c = java.util.Calendar.getInstance();
    }

    public static void main(String[] args) throws RunnerException {
        Options opt = new OptionsBuilder()
                .result("jmh-report.txt")
                .include(ResultToFileBenchmark.class.getName())
                .build();
        new Runner(opt).run();
    }
}

■実行結果(コンソールへの出力内容)

(一部省略)

# Warmup: 3 iterations, 1 s each
# Measurement: 8 iterations, 1 s each
# Timeout: 10 min per iteration
# Threads: 1 thread, will synchronize iterations
# Benchmark mode: Throughput, ops/time
# Benchmark: org.jmh.sample.resultformat.ResultToFileBenchmark.calndar

# Run progress: 0.00% complete, ETA 00:00:22
# Fork: 1 of 1
# Warmup Iteration   1: 860.543 ops/ms
# Warmup Iteration   2: 1750.526 ops/ms
# Warmup Iteration   3: 2037.289 ops/ms
Iteration   1: 2248.850 ops/ms
Iteration   2: 2235.143 ops/ms
Iteration   3: 2254.577 ops/ms
Iteration   4: 2232.210 ops/ms
Iteration   5: 2240.256 ops/ms
Iteration   6: 2215.086 ops/ms
Iteration   7: 2223.034 ops/ms
Iteration   8: 2239.323 ops/ms


Result "calndar":
  2236.060 ±(99.9%) 24.613 ops/ms [Average]
  (min, avg, max) = (2215.086, 2236.060, 2254.577), stdev = 12.873
  CI (99.9%): [2211.447, 2260.673] (assumes normal distribution)


# Warmup: 3 iterations, 1 s each
# Measurement: 8 iterations, 1 s each
# Timeout: 10 min per iteration
# Threads: 1 thread, will synchronize iterations
# Benchmark mode: Throughput, ops/time
# Benchmark: org.jmh.sample.resultformat.ResultToFileBenchmark.date

# Run progress: 50.00% complete, ETA 00:00:12
# Fork: 1 of 1
# Warmup Iteration   1: 36258.596 ops/ms
# Warmup Iteration   2: 39107.596 ops/ms
# Warmup Iteration   3: 43195.965 ops/ms
Iteration   1: 43738.107 ops/ms
Iteration   2: 43637.666 ops/ms
Iteration   3: 43731.485 ops/ms
Iteration   4: 43573.084 ops/ms
Iteration   5: 42717.360 ops/ms
Iteration   6: 43211.566 ops/ms
Iteration   7: 42826.822 ops/ms
Iteration   8: 42844.488 ops/ms


Result "date":
  43285.072 ±(99.9%) 837.663 ops/ms [Average]
  (min, avg, max) = (42717.360, 43285.072, 43738.107), stdev = 438.114
  CI (99.9%): [42447.409, 44122.735] (assumes normal distribution)


# Run complete. Total time: 00:00:24

Benchmark                       Mode  Cnt      Score     Error   Units
ResultToFileBenchmark.calndar  thrpt    8   2236.060 ±  24.613  ops/ms
ResultToFileBenchmark.date     thrpt    8  43285.072 ± 837.663  ops/ms

Benchmark result is saved to jmh-report.txt

■ファイルへの出力内容

ファイル(jmh-report.txt)には以下の内容が出力されます

"Benchmark","Mode","Threads","Samples","Score","Score Error (99.9%)","Unit"
"org.jmh.sample.resultformat.ResultToFileBenchmark.calndar","thrpt",1,8,2236.060013,24.612811,"ops/ms"
"org.jmh.sample.resultformat.ResultToFileBenchmark.date","thrpt",1,8,43285.072457,837.663008,"ops/ms"


ResultFormatType.CSV - CSV形式で結果を出力する

OptionsBuilder#resultFormatを使用することで計測結果の出力形式を指定するとが可能です。
また、形式を指定するとOptionsBuilder#resultFormatを実行しなくても拡張子まで含めてファイル名を自動的に決定してくれます。
CSV形式の場合ファイル名は、"jmh-result.csv" になります。

■サンプルコード

CSV形式で出力するためにOptionsBuilder#resultFormatResultFormatType.CSVを指定しています。

import java.util.concurrent.TimeUnit;

import org.openjdk.jmh.annotations.Benchmark;
import org.openjdk.jmh.annotations.BenchmarkMode;
import org.openjdk.jmh.annotations.Fork;
import org.openjdk.jmh.annotations.Measurement;
import org.openjdk.jmh.annotations.Mode;
import org.openjdk.jmh.annotations.OutputTimeUnit;
import org.openjdk.jmh.annotations.Warmup;
import org.openjdk.jmh.results.format.ResultFormatType;
import org.openjdk.jmh.runner.Runner;
import org.openjdk.jmh.runner.RunnerException;
import org.openjdk.jmh.runner.options.Options;
import org.openjdk.jmh.runner.options.OptionsBuilder;

@Warmup(iterations=3)
@Measurement(iterations=8)
@OutputTimeUnit(TimeUnit.MILLISECONDS)
@BenchmarkMode(Mode.Throughput)
@Fork(1)
public class CSVFormatBenchmark {

    @Benchmark
    public void date() {
        java.util.Date d = new java.util.Date();
    }

    @Benchmark
    public void calndar() {
        java.util.Calendar c = java.util.Calendar.getInstance();
    }

    public static void main(String[] args) throws RunnerException {
        Options opt = new OptionsBuilder()
                 .resultFormat(ResultFormatType.CSV)
                 .include(CSVFormatBenchmark.class.getName())
                .build();
        new Runner(opt).run();
    }
}

■実行結果(コンソールへの出力内容)

(一部省略)

# Warmup: 3 iterations, 1 s each
# Measurement: 8 iterations, 1 s each
# Timeout: 10 min per iteration
# Threads: 1 thread, will synchronize iterations
# Benchmark mode: Throughput, ops/time
# Benchmark: org.jmh.sample.resultformat.CSVFormatBenchmark.calndar

# Run progress: 0.00% complete, ETA 00:00:22
# Fork: 1 of 1
# Warmup Iteration   1: 801.988 ops/ms
# Warmup Iteration   2: 1717.748 ops/ms
# Warmup Iteration   3: 2063.707 ops/ms
Iteration   1: 2228.389 ops/ms
Iteration   2: 2220.809 ops/ms
Iteration   3: 2153.975 ops/ms
Iteration   4: 2127.324 ops/ms
Iteration   5: 2140.863 ops/ms
Iteration   6: 2149.958 ops/ms
Iteration   7: 2199.567 ops/ms
Iteration   8: 1941.240 ops/ms


Result "calndar":
  2145.266 ±(99.9%) 173.484 ops/ms [Average]
  (min, avg, max) = (1941.240, 2145.266, 2228.389), stdev = 90.736
  CI (99.9%): [1971.782, 2318.750] (assumes normal distribution)


# Warmup: 3 iterations, 1 s each
# Measurement: 8 iterations, 1 s each
# Timeout: 10 min per iteration
# Threads: 1 thread, will synchronize iterations
# Benchmark mode: Throughput, ops/time
# Benchmark: org.jmh.sample.resultformat.CSVFormatBenchmark.date

# Run progress: 50.00% complete, ETA 00:00:12
# Fork: 1 of 1
# Warmup Iteration   1: 37353.221 ops/ms
# Warmup Iteration   2: 37525.984 ops/ms
# Warmup Iteration   3: 41822.555 ops/ms
Iteration   1: 42684.230 ops/ms
Iteration   2: 43107.547 ops/ms
Iteration   3: 43209.845 ops/ms
Iteration   4: 42733.811 ops/ms
Iteration   5: 43333.149 ops/ms
Iteration   6: 40338.558 ops/ms
Iteration   7: 38625.473 ops/ms
Iteration   8: 39366.701 ops/ms


Result "date":
  41674.914 ±(99.9%) 3664.312 ops/ms [Average]
  (min, avg, max) = (38625.473, 41674.914, 43333.149), stdev = 1916.506
  CI (99.9%): [38010.603, 45339.226] (assumes normal distribution)


# Run complete. Total time: 00:00:24

Benchmark                    Mode  Cnt      Score      Error   Units
CSVFormatBenchmark.calndar  thrpt    8   2145.266 ±  173.484  ops/ms
CSVFormatBenchmark.date     thrpt    8  41674.914 ± 3664.312  ops/ms

Benchmark result is saved to jmh-result.csv

■ファイルへの出力内容

ファイル(jmh-result.csv)には以下の通りCSV形式で出力されます。
(ただ、デフォルトの場合もカンマ区切りのCSV形式で出力されていたので違いが無いですが・・・)

"Benchmark","Mode","Threads","Samples","Score","Score Error (99.9%)","Unit"
"org.jmh.sample.resultformat.CSVFormatBenchmark.calndar","thrpt",1,8,2145.265649,173.484068,"ops/ms"
"org.jmh.sample.resultformat.CSVFormatBenchmark.date","thrpt",1,8,41674.914382,3664.311779,"ops/ms"


ResultFormatType.TEXT - スペース区切りで結果を出力する

以下、OptionsBuilder#resultFormatResultFormatType.TEXTを指定した場合のサンプルです。
ファイル名は、"jmh-result.text" になります。

■サンプルコード

OptionsBuilder#resultFormatResultFormatType.TEXTを指定しています。

import java.util.concurrent.TimeUnit;

import org.openjdk.jmh.annotations.Benchmark;
import org.openjdk.jmh.annotations.BenchmarkMode;
import org.openjdk.jmh.annotations.Fork;
import org.openjdk.jmh.annotations.Measurement;
import org.openjdk.jmh.annotations.Mode;
import org.openjdk.jmh.annotations.OutputTimeUnit;
import org.openjdk.jmh.annotations.Warmup;
import org.openjdk.jmh.results.format.ResultFormatType;
import org.openjdk.jmh.runner.Runner;
import org.openjdk.jmh.runner.RunnerException;
import org.openjdk.jmh.runner.options.Options;
import org.openjdk.jmh.runner.options.OptionsBuilder;

@Warmup(iterations=3)
@Measurement(iterations=8)
@OutputTimeUnit(TimeUnit.MILLISECONDS)
@BenchmarkMode(Mode.Throughput)
@Fork(1)
public class TextFormatBenchmark {

    @Benchmark
    public void date() {
        java.util.Date d = new java.util.Date();
    }

    @Benchmark
    public void calndar() {
        java.util.Calendar c = java.util.Calendar.getInstance();
    }

    public static void main(String[] args) throws RunnerException {
        Options opt = new OptionsBuilder()
                .resultFormat(ResultFormatType.TEXT)
                 .include(TextFormatBenchmark.class.getName())
                .build();
        new Runner(opt).run();
    }
}

■実行結果(コンソールへの出力内容)

(一部省略)

# Warmup: 3 iterations, 1 s each
# Measurement: 8 iterations, 1 s each
# Timeout: 10 min per iteration
# Threads: 1 thread, will synchronize iterations
# Benchmark mode: Throughput, ops/time
# Benchmark: org.jmh.sample.resultformat.TextFormatBenchmark.calndar

# Run progress: 0.00% complete, ETA 00:00:22
# Fork: 1 of 1
# Warmup Iteration   1: 840.722 ops/ms
# Warmup Iteration   2: 1811.098 ops/ms
# Warmup Iteration   3: 1994.031 ops/ms
Iteration   1: 2163.944 ops/ms
Iteration   2: 2059.981 ops/ms
Iteration   3: 2175.931 ops/ms
Iteration   4: 2139.949 ops/ms
Iteration   5: 2257.767 ops/ms
Iteration   6: 2193.703 ops/ms
Iteration   7: 2190.150 ops/ms
Iteration   8: 2009.930 ops/ms


Result "calndar":
  2148.919 ±(99.9%) 151.271 ops/ms [Average]
  (min, avg, max) = (2009.930, 2148.919, 2257.767), stdev = 79.118
  CI (99.9%): [1997.649, 2300.190] (assumes normal distribution)


# Warmup: 3 iterations, 1 s each
# Measurement: 8 iterations, 1 s each
# Timeout: 10 min per iteration
# Threads: 1 thread, will synchronize iterations
# Benchmark mode: Throughput, ops/time
# Benchmark: org.jmh.sample.resultformat.TextFormatBenchmark.date

# Run progress: 50.00% complete, ETA 00:00:12
# Fork: 1 of 1
# Warmup Iteration   1: 30056.156 ops/ms
# Warmup Iteration   2: 30540.027 ops/ms
# Warmup Iteration   3: 43359.686 ops/ms
Iteration   1: 43069.238 ops/ms
Iteration   2: 42919.146 ops/ms
Iteration   3: 34731.576 ops/ms
Iteration   4: 38545.223 ops/ms
Iteration   5: 42328.447 ops/ms
Iteration   6: 37412.075 ops/ms
Iteration   7: 37396.214 ops/ms
Iteration   8: 38859.252 ops/ms


Result "date":
  39407.646 ±(99.9%) 5835.543 ops/ms [Average]
  (min, avg, max) = (34731.576, 39407.646, 43069.238), stdev = 3052.102
  CI (99.9%): [33572.104, 45243.189] (assumes normal distribution)


# Run complete. Total time: 00:00:24

Benchmark                     Mode  Cnt      Score      Error   Units
TextFormatBenchmark.calndar  thrpt    8   2148.919 ±  151.271  ops/ms
TextFormatBenchmark.date     thrpt    8  39407.646 ± 5835.543  ops/ms

Benchmark result is saved to jmh-result.text

■ファイルへの出力内容

ファイル(jmh-result.text)には以下の通りスペース区切りで各項目が出力されます。

Benchmark                     Mode  Cnt      Score      Error   Units
TextFormatBenchmark.calndar  thrpt    8   2148.919 ±  151.271  ops/ms
TextFormatBenchmark.date     thrpt    8  39407.646 ± 5835.543  ops/ms


ResultFormatType.JSON - JSON形式で結果を出力する

JSON形式で出力する場合は、OptionsBuilder#resultFormatの引数にResultFormatType.JSONを指定します。
JSON形式の場合ファイル名は、"jmh-result.json" になります。

■サンプルコード

JSON形式で出力するためにOptionsBuilder#resultFormatResultFormatType.JSONを指定しています。

import java.util.concurrent.TimeUnit;

import org.openjdk.jmh.annotations.Benchmark;
import org.openjdk.jmh.annotations.BenchmarkMode;
import org.openjdk.jmh.annotations.Fork;
import org.openjdk.jmh.annotations.Measurement;
import org.openjdk.jmh.annotations.Mode;
import org.openjdk.jmh.annotations.OutputTimeUnit;
import org.openjdk.jmh.annotations.Warmup;
import org.openjdk.jmh.results.format.ResultFormatType;
import org.openjdk.jmh.runner.Runner;
import org.openjdk.jmh.runner.RunnerException;
import org.openjdk.jmh.runner.options.Options;
import org.openjdk.jmh.runner.options.OptionsBuilder;

@Warmup(iterations=3)
@Measurement(iterations=8)
@OutputTimeUnit(TimeUnit.MILLISECONDS)
@BenchmarkMode(Mode.Throughput)
@Fork(1)
public class JSONFormatBenchmark {

    @Benchmark
    public void date() {
        java.util.Date d = new java.util.Date();
    }

    @Benchmark
    public void calndar() {
        java.util.Calendar c = java.util.Calendar.getInstance();
    }

    public static void main(String[] args) throws RunnerException {
        Options opt = new OptionsBuilder()
                .resultFormat(ResultFormatType.JSON)
                 .include(JSONFormatBenchmark.class.getName())
                .build();
        new Runner(opt).run();
    }
}

■実行結果(コンソールへの出力内容)

(一部省略)

# Warmup: 3 iterations, 1 s each
# Measurement: 8 iterations, 1 s each
# Timeout: 10 min per iteration
# Threads: 1 thread, will synchronize iterations
# Benchmark mode: Throughput, ops/time
# Benchmark: org.jmh.sample.resultformat.JSONFormatBenchmark.calndar

# Run progress: 0.00% complete, ETA 00:00:22
# Fork: 1 of 1
# Warmup Iteration   1: 723.338 ops/ms
# Warmup Iteration   2: 1588.531 ops/ms
# Warmup Iteration   3: 1813.152 ops/ms
Iteration   1: 1975.679 ops/ms
Iteration   2: 1823.954 ops/ms
Iteration   3: 2127.294 ops/ms
Iteration   4: 2140.784 ops/ms
Iteration   5: 2198.476 ops/ms
Iteration   6: 2152.402 ops/ms
Iteration   7: 1756.058 ops/ms
Iteration   8: 2075.053 ops/ms


Result "calndar":
  2031.213 ±(99.9%) 312.982 ops/ms [Average]
  (min, avg, max) = (1756.058, 2031.213, 2198.476), stdev = 163.695
  CI (99.9%): [1718.231, 2344.194] (assumes normal distribution)


# Warmup: 3 iterations, 1 s each
# Measurement: 8 iterations, 1 s each
# Timeout: 10 min per iteration
# Threads: 1 thread, will synchronize iterations
# Benchmark mode: Throughput, ops/time
# Benchmark: org.jmh.sample.resultformat.JSONFormatBenchmark.date

# Run progress: 50.00% complete, ETA 00:00:12
# Fork: 1 of 1
# Warmup Iteration   1: 35741.999 ops/ms
# Warmup Iteration   2: 35740.262 ops/ms
# Warmup Iteration   3: 42828.846 ops/ms
Iteration   1: 41715.681 ops/ms
Iteration   2: 38704.681 ops/ms
Iteration   3: 40630.365 ops/ms
Iteration   4: 42170.008 ops/ms
Iteration   5: 43113.156 ops/ms
Iteration   6: 42888.040 ops/ms
Iteration   7: 42712.572 ops/ms
Iteration   8: 43553.429 ops/ms


Result "date":
  41935.992 ±(99.9%) 3045.526 ops/ms [Average]
  (min, avg, max) = (38704.681, 41935.992, 43553.429), stdev = 1592.869
  CI (99.9%): [38890.466, 44981.517] (assumes normal distribution)


# Run complete. Total time: 00:00:25

Benchmark                     Mode  Cnt      Score      Error   Units
JSONFormatBenchmark.calndar  thrpt    8   2031.213 ±  312.982  ops/ms
JSONFormatBenchmark.date     thrpt    8  41935.992 ± 3045.526  ops/ms

Benchmark result is saved to jmh-result.json

■ファイルへの出力内容

ファイル(jmh-result.json)には以下の通りJSON形式で出力されます。
(JSON形式の場合CSVやTEXTに比べると細かな情報が出力されます)

[
    {
        "benchmark" : "org.jmh.sample.resultformat.JSONFormatBenchmark.calndar",
        "mode" : "thrpt",
        "threads" : 1,
        "forks" : 1,
        "warmupIterations" : 3,
        "warmupTime" : "1 s",
        "warmupBatchSize" : 1,
        "measurementIterations" : 8,
        "measurementTime" : "1 s",
        "measurementBatchSize" : 1,
        "primaryMetric" : {
            "score" : 2031.2125350456186,
            "scoreError" : 312.98161845723837,
            "scoreConfidence" : [
                1718.2309165883803,
                2344.194153502857
            ],
            "scorePercentiles" : {
                "0.0" : 1756.0580968714692,
                "50.0" : 2101.173201603441,
                "90.0" : 2198.475678280988,
                "95.0" : 2198.475678280988,
                "99.0" : 2198.475678280988,
                "99.9" : 2198.475678280988,
                "99.99" : 2198.475678280988,
                "99.999" : 2198.475678280988,
                "99.9999" : 2198.475678280988,
                "100.0" : 2198.475678280988
            },
            "scoreUnit" : "ops/ms",
            "rawData" : [
                [
                    1975.6794167720557,
                    1823.9541417969915,
                    2127.293876619056,
                    2140.7844450137263,
                    2198.475678280988,
                    2152.4020984228355,
                    1756.0580968714692,
                    2075.052526587826
                ]
            ]
        },
        "secondaryMetrics" : {
        }
    },
    {
        "benchmark" : "org.jmh.sample.resultformat.JSONFormatBenchmark.date",
        "mode" : "thrpt",
        "threads" : 1,
        "forks" : 1,
        "warmupIterations" : 3,
        "warmupTime" : "1 s",
        "warmupBatchSize" : 1,
        "measurementIterations" : 8,
        "measurementTime" : "1 s",
        "measurementBatchSize" : 1,
        "primaryMetric" : {
            "score" : 41935.99154431828,
            "scoreError" : 3045.5258433819627,
            "scoreConfidence" : [
                38890.46570093632,
                44981.517387700245
            ],
            "scorePercentiles" : {
                "0.0" : 38704.68115216356,
                "50.0" : 42441.289768770104,
                "90.0" : 43553.42888340613,
                "95.0" : 43553.42888340613,
                "99.0" : 43553.42888340613,
                "99.9" : 43553.42888340613,
                "99.99" : 43553.42888340613,
                "99.999" : 43553.42888340613,
                "99.9999" : 43553.42888340613,
                "100.0" : 43553.42888340613
            },
            "scoreUnit" : "ops/ms",
            "rawData" : [
                [
                    41715.68149483313,
                    38704.68115216356,
                    40630.365288648034,
                    42170.00803633526,
                    43113.156056319305,
                    42888.03994163592,
                    42712.57150120494,
                    43553.42888340613
                ]
            ]
        },
        "secondaryMetrics" : {
        }
    }
]



関連エントリ