mike-neckのブログ

Java or Groovy or Swift or Golang

JMH の細かい実行制御

JMH で何かしらの処理のパフォーマンスを計測する時に、すべての計測対象が必ずしもステートレスにできないケースがある。

例えば、 List<String> にデータが 1万レコードほどある時に、 add(int, String) の呼び出しのパフォーマンスを計測する場合など。

この例の場合だと、 JMH の実行設定をイテレーション10秒に設定していると、 3 億回ほどメソッドが呼び出されたりする。すると、最後の方には List<String> にデータが 3億1 万レコードある状態でのベンチマークとなり、もともと計測したかった 1万レコードの時点での速度計測にならなかったりする。

このようなケースでは、 @Setup@TearDown アノテーションに与える、 Level をうまく設定してやることで、レコード件数を維持できる。

@State(Scope.Group)
public class Sample {

  private List<String> list;

  @Group("sample")
  @Setup(Level.Iteration)
  public void setup() {
    this.list = new ArrayList<>();
    for (int i = 0; i < 10_000; i++) {
      list.add(Util.randomString());
    }
  }

  @Group("sample")
  @Benchmark
  @BenchmarkMode(Mode.Throughput)
  public void addOp() {
    list.add(Util.randomString());
  }

  @Group("sample")
  @TearDown(Level.Invocation)
  public void teardown() {
    list.remove(list.size() - 1);
  }
}