$shibayu36->blog;

クラスター株式会社のソフトウェアエンジニアです。エンジニアリングや読書などについて書いています。

nanobenchを使ってJavaのベンチマークを取る

アルゴリズムを学習していると、ある実装の速度がどのくらいか計測したいことがよくある。これまでは、currentTimeMillisを利用して、愚直にベンチマークを取っていたのだけど、結構だるい感じだった。

調べてみると、jmhnanobench という二つのツールがあった。jmhは使ってみたけど、非常に重厚で難しかったので、nanobenchを使ってみた。

ハマったこと

nanobench のREADME.mdを見ていると、nanobench.jarを落としてきて、以下のように実行すると良いと書いてある。

> javac ListBenchmark.java
> java -jar nanobench.jar ListBenchmark

しかし、Java初心者のためか、jarファイルのことがよく分からなかったり、classpathの問題でハマったり、とにかくハマりまくってうまく動かなかった。

また https://github.com/tokuhirom/nanobench/blob/master/examples/microbenchmarks/src/test/java/me/geso/microbenchmarks/HTMLEscapeTest.java に普通にIDEでも実行できそうなサンプルもあったのだが、今は動かなくなってしまっていた。

作戦と実装

とにかくIDEで出来たほうが手軽である。そこで、普通にmainメソッドが実装されたクラスを用意し、それを実行するとベンチマークをキックして実行してくれるようにしてみる。

まずはgradleでnanobenchを依存に追加しておく。

compile group: 'me.geso', name: 'nanobench', version: '0.2.0'

さらに以下のようにして、IDEで実行可能なベンチマークを作る。

src/main/java/ListBenchmark.java

import me.geso.nanobench.Benchmark;
import java.util.List;
import java.util.ArrayList;
import java.util.LinkedList;

public class ListBenchmark {

  public static void main(String[] args) throws Exception {
    // 10回warmupして3秒ずつベンチマークを取る
    // 内部クラスに実際のベンチマークを書いていく
    new Benchmark(new ListBenchmarkInner()).warmup(10).runByTime(3).timethese().cmpthese();
  }

  public static class ListBenchmarkInner {
    @Benchmark.Bench
    public void arrayList() {
      List<Integer> l = new ArrayList<>();
      for (int i = 0; i < 1_000_000; ++i) {
        l.add(i);
      }
    }

    @Benchmark.Bench
    public void linkedList() {
      List<Integer> l = new LinkedList<>();
      for (int i = 0; i < 1_000_000; ++i) {
        l.add(i);
      }
    }
  }
}

そしてmainをIDEから実行する。

Warm up: 10


Score:

arrayList:  3 wallclock secs ( 2.71 usr +  0.31 sys =  3.03 CPU) @ 125.92/s (n=381)
linkedList:  3 wallclock secs ( 3.10 usr +  0.02 sys =  3.12 CPU) @ 172.70/s (n=538)

Comparison chart:

               Rate  arrayList  linkedList
   arrayList  126/s         --        -27%
  linkedList  173/s        37%          --

これで、適当に内部クラスを作って、比べたいものごとにメソッドを追加していくだけで、ベンチマークを取れるようになった。Benchmark.pmのように簡単にベンチマークを取れて便利。

コードは https://github.com/shibayu36/java-playground/blob/master/src/main/java/ListBenchmark.java においてあるので、参考にどうぞ。