はじめに
RubyでベンチマークするのはRuby標準のbenchmarkライブラリを使えば簡単にできます。
さらに、より簡単にベンチマークを取れるbenchmark-ipsというGemもあります。
このGemは、RailsにContributionする際にベンチマークを取る方法として、公式に指定されてもいます。
以下ではこの2つの使い方を簡単に見ていきます。
benchmark-ips
概要
ipsとは"iterations per second"の略になります。
このGemでベンチマークすると「処理回数(イテレーション回数)/秒」を計測してくれます。
次の項で説明するRuby標準のbenchmarkライブラリは自分で実行回数を指定しなければならないのですが、こちらはその手間がなく、かつ処理ごとに何倍の速度差があるかを出してくれるので便利です。
使い方
まずはインストールしましょう
$ gem i benchmark-ips
コードの書き方は以下のとおり。(公式から引用・整形)
require 'benchmark/ips'
Benchmark.ips do |x|
x.report("addition") { 1 + 2 }
x.report("addition2") do |times|
i = 0
while i < times
1 + 2
i += 1
end
end
x.report("addition3", "1 + 2")
x.report("addition-test-long-label") { 1 + 2 }
x.compare!
end
実行結果は以下のようになります
Calculating -------------------------------------
addition 71.254k i/100ms
addition2 68.658k i/100ms
addition3 83.079k i/100ms
addition-test-long-label
70.129k i/100ms
-------------------------------------------------
addition 4.955M (± 8.7%) i/s - 24.155M
addition2 24.011M (± 9.5%) i/s - 114.246M
addition3 23.958M (±10.1%) i/s - 115.064M
addition-test-long-label
5.014M (± 9.1%) i/s - 24.545M
Comparison:
addition2: 24011974.8 i/s
addition3: 23958619.8 i/s - 1.00x slower
addition-test-long-label: 5014756.0 i/s - 4.79x slower
addition: 4955278.9 i/s - 4.85x slower
report
メソッドにテストの名前(必須ではない)と計測したい処理を渡します。
compare!
は必須ではないですが、書いておくと結果に"Comparison"という項目が出来て、
一目で最速の処理や遅い処理は何倍遅いかを表示してくれるので便利です。
設定
細かい挙動は正直よくわかってないのですが、実行時に2つ指定できる設定があります。
time
は計測する時間、warmup
はおそらく処理のオーバーヘッドを少なくするために前処理(ウォーミングアップ)の時間を与えるものだと思います。多分
指定方法は以下の2通りのどちらかでやればOK
Benchmark.ips do |x|
x.config(
time: 8, # default 5
warmup: 3 # default 2
)
# or
x.time = 5
x.warmup = 2
## 後略 ##
end
GC
ベンチマークをしている時だけGCを無効にしたい場合も多々あると思いますが、その時は以下のリンク先のコードをコピペしてやれば大体OK
Benchmark
Ruby標準ベンチマークライブラリの使い方は以下のとおり
ipsとの違いはイテレーション回数を指定しなければいけないことと、Benchmark.bm
を呼び出すことでしょうか。
基本的にはipsの方が便利なので、そっち使いましょう。
require 'benchmark'
n = 10000000
Benchmark.bm(7) do |x| # 引数の7は結果の表示を揃えるためで必須ではないです
x.report("for:") { for i in 1..n; a = "1"; end }
x.report("times:") { n.times do ; a = "1"; end }
x.report("upto:") { 1.upto(n) do ; a = "1"; end }
end
user system total real
for: 1.100000 0.010000 1.110000 ( 1.098665)
times: 1.080000 0.000000 1.080000 ( 1.085871)
upto: 1.070000 0.000000 1.070000 ( 1.065394)