S-JIS[2011-02-14/2011-02-20] 変更履歴
ScalaのBenchmarkは、ベンチマークをとる(実行速度を表示する)為のトレイト。
|
Benchmarkトレイトを使って実行時間を計測するには、以下のようにする。
Benchmarkはmainメソッドも持っているので、Benchmarkを継承したobjectを作れば、scalaコマンドでベンチマークを実行することも出来る。
使ってみた感じでは、計測の初回は実行時間が多めに出ることが多い気がする。(ベンチマークではよくある事)
計測回数は5回くらいでは少ないかも。
REPLで実行する例。
new scala.testing.Benchmark { def run() = { List.range(1, 100*10000).sum } }.runBenchmark(5) res0: List[Long] = List(328, 359, 344, 360, 343) |
runBenchmarkの引数で指定された回数だけ実行し、 実行時間のリストが返ってくる。単位はミリ秒。 なお、1回計測する度にGC(Platform.collectGarbage(System.gc()))が実行されるようになっている。 |
new scala.testing.Benchmark { def run() = { Array.range(1, 100*10000).sum } }.runBenchmark(5) res1: List[Long] = List(188, 156, 141, 140, 140) |
|
new scala.testing.Benchmark { def run() = { List.range(1, 10000).sum } }.runBenchmark(5) res2: List[Long] = List(0, 0, 0, 0, 0) |
1回の処理が早すぎる場合、multiplierを設定することで、 1回の計測時間内にmultiplier回の処理を実行するように出来る。 (左記下側の例では、コンストラクター内でmultiplierに100をセットしている) |
new scala.testing.Benchmark { multiplier = 100 def run() = { List.range(1, 10000).sum } }.runBenchmark(5) res3: List[Long] = List(203, 203, 187, 187, 203) |
REPL上で何度も実行するなら、こんな関数を作っちゃうのも便利かも。
def benchmark(times: Int, mult: Int = 1)(f: =>Any) = new scala.testing.Benchmark{ multiplier = mult; def run() = f }.runBenchmark(times)
scala> benchmark(5){ List.range(1, 100*10000).sum } res4: List[Long] = List(407, 391, 422, 344, 328) scala> benchmark(5,100){ List.range(1, 10000).sum } res5: List[Long] = List(188, 187, 187, 172, 188)
ついでに、最大値・最小値を除いた平均も表示する関数を作ってみた。[2011-02-20]
(3回以上測定する前提)
implicit def benchmark2report(list:List[Long]) = new { def report() = { println(list); println((list.sum - list.max - list.min).toDouble / (list.size-2)) }}
scala benchmark(10){ List.range(1, 100*10000).sum }.report
List(594, 421, 422, 438, 422, 422, 437, 437, 437, 438)
431.625
Benchmarkを継承したオブジェクトを作り、scalaコマンドで実行する例。
(Benchmarkトレイトはmainメソッドを持っているので、実行することが出来る)
import scala.testing.Benchmark
object Sample extends Benchmark {
def run() = {
List.range(1, 10000).sum
}
}
>scala Sample Usage: scala benchmarks.program <runs> or: scala benchmarks.program <runs> <multiplier> The benchmark is run <runs> times, forcing a garbage collection between runs. The optional <multiplier> causes the benchmark to be repeated <multiplier> times, each time for <runs> executions.
第1引数で計測回数(runBenchmark()の引数)、
第2引数でmultiplier(1回の計測当たりの実行回数)
を指定する。
>scala Sample 5 Sample$ 31 0 0 0 0 >scala Sample 5 100 Sample$ 250 203 203 203 203
prefixをオーバーライドしておくと、最初に表示されるメッセージ(デフォルトではクラス名)が変えられる。
import scala.testing.Benchmark object Sample extends Benchmark { override def prefix = "List.sum" def run() = { List.range(1, 10000).sum } }
>scala Sample 5 100
List.sum 250 203 203 203 203