hakobera's blog

技術メモ。たまに雑談

Java で Ruby の Benchmark みたいなことをやる

「大規模サービス技術入門」に影響されてアルゴリズムの勉強をはじめてから実行時間を計ることが多くなったのだけれど、なんか毎回、同じようなコードを書いているので、少し簡単に書けるように工夫してみた。

参考にしたのは Ruby の Benchmark クラス。

library benchmark

Java だとブロックがないので、ラベルの指定方法があまりかっこよくないけど、ちょっと使う分には便利になった。

Block.java

public abstract class Block {
	public String label;

	public Block(String label) {
		this.label = label;
	}

	public abstract void yield();
}

Benchmark.java

class Benchmark {

	private String labelFormat;
	
	public Benchmark() {
		this(8);
	}
	
	public Benchmark(int labelWidth) {
		this.labelFormat = String.format("%%%ds %%%ds", labelWidth, labelWidth);
	}
	
	public void run(Block... blocks) {
		List<Times> results = new ArrayList<Benchmark.Times>();
		for (Block block : blocks) {
			long start = System.currentTimeMillis();
			block.yield();

			long time = System.currentTimeMillis() - start;
			Times result = new Times(block, time);
			results.add(result);
		}

		System.out.println(String.format(labelFormat, "", "time(ms)"));
		for (Times result : results) {
			System.out.println(result);
		}
	}

	class Times {
		private Block block;
		private long time;

		public Times(Block block, long time) {
			this.block = block;
			this.time = time;
		}

		@Override
		public String toString() {
			return String.format(labelFormat, block.label, time);
		}
	}

}

使用例
404 Blog Not Found:perl - 自動で /a|b|c/ を /[abc]/ にしてくれたら...ベンチマーク が以下のように書ける。

import java.util.ArrayList;
import java.util.List;
import java.util.regex.Pattern;

public class RegexBench {

	public static void main(String[] args) {
		final Pattern p1 = Pattern.compile("s|t|u|v|w|x|y|z");
		final Pattern p2 = Pattern.compile("[stuvwxyz]");

		final String alphabes = "abcdefghijklmnopqrstuvwxyz";
		final String digits = "01234567890123456789012345";

		final int ntimes = 1000000;

		new Benchmark().run(new Block("alt") {
			@Override
			public void yield() {
				for (int i = 0; i < ntimes; ++i) {
					p1.matcher(alphabes);
				}
			}
		}, new Block("cclass") {
			@Override
			public void yield() {
				for (int i = 0; i < ntimes; ++i) {
					p2.matcher(alphabes);
				}
			}
		});

		new Benchmark(7).run(new Block("alt") {
			@Override
			public void yield() {
				for (int i = 0; i < ntimes; ++i) {
					p1.matcher(digits);
				}
			}
		}, new Block("cclass") {
			@Override
			public void yield() {
				for (int i = 0; i < ntimes; ++i) {
					p2.matcher(digits);
				}
			}
		});
	}

}