アルゴリズムを学習していると、ある実装の速度がどのくらいか計測したいことがよくある。これまでは、currentTimeMillis
を利用して、愚直にベンチマークを取っていたのだけど、結構だるい感じだった。
調べてみると、jmh と nanobench という二つのツールがあった。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 においてあるので、参考にどうぞ。
参考
- http://openjdk.java.net/projects/code-tools/jmh/
- https://github.com/tokuhirom/nanobench
- https://github.com/moznion/micro-html-escape/blob/7a74ac3fcce085332d478e7c38a9f9aac7eba276/author/BasicBench.java
- https://github.com/moznion/sprint-bench/blob/9ff61f5c6e5c2f566b716456a4a3d7566e5bb848/src/main/java/net/moznion/sprint/bench/BenchmarkApp.java