前回、Ruby標準のBenchmarkモジュールを利用したベンチマークの実行・確認方法でRuby標準のBenchmarkモジュールを利用したベンチマークテストの実行方法について紹介しました。
今回は、Benchmarkモジュールによる計測を『繰り返し回数/時間』という表現に拡張したbenchmark-ipsを利用したベンチマークの実行・確認方法について紹介します。
目次
benchmark-ipsを利用したベンチマークテストの実行方法
benchmark-ipsを利用したベンチマークテストの実行方法について紹介します。
gemのインストール
Gemfile
group :development do
gem 'benchmark-ips'
end
$ bundle
ベンチマークテストの処理を埋め込む
ベンチマークテストの実行方法はBenchmarkモジュールを利用した場合と似ています。
計測対象の処理をBenchmark.ips
で囲むことで、ベンチマークテストの結果がコンソールログに出力されます。
ただし、benchmark-ipsは設定時間の間ベンチマークテストを繰り返し実行してくれるため、Benchmarkモジュールのように試行回数をわざわざ明記する必要がありません。
benchmark-ipsを利用したベンチマークテストの文法は以下の通りです。
Benchmark.ips do |x|
x.report { 計測する処理 }
end
ラベル付けをする場合は以下の通りです。
Benchmark.ips do |x|
x.report(ラベル名) { 計測するロジック }
end
benchmark-ipsで設定できるwarmup
(ウォームアップ時間。デフォルトは2)とtime
(実行時間。デフォルトは5)を変更したい場合は以下のようにします。
Benchmark.ips do |x|
# 方法1
x.config(time: 5, warmup: 2)
# 方法2
x.time = 5
x.warmup = 2
#
# ベンチマークの実行
#
end
x.compare!
でベンチマークの比較結果が出力されます。x.compare!
の記述は任意です。compare!を利用する場合はラベル付けが必須です。
Benchmark.ips do |x|
x.report(ラベル名1) { 計測するロジック }
x.report(ラベル名2) { 計測するロジック }
x.compare! # ラベル名1とラベル名2の比較結果が出力される
end
ベンチマークの確認方法
benchmark-ipsは『繰り返し回数/時間(i/ms)』で処理を評価します。
つまり、数値が大きいほど高速ということを意味しています。
たとえばRailsアプリケーション内でpluck(:id)
とmap(&:id)
のベンチマークテストを実行する場合は以下のようになります。
# 計測中にSQLのログが出力されないようにする
old_logger = ActiveRecord::Base.logger
ActiveRecord::Base.logger = nil
# ベンチマークテストの実行
Benchmark.ips do |x|
x.report("pluck(:id)") { Student.all.pluck(:id) }
x.report("map(&:id)") { Student.all.map(&:id) }
x.compare!
end
# ログの設定を元に戻す
ActiveRecord::Base.logger = old_logger
結果は以下の通りです。
実行結果
Warming up --------------------------------------
pluck(:id) 1.359k i/100ms
map(&:id) 908.000 i/100ms
Calculating -------------------------------------
pluck(:id) 13.704k (± 9.3%) i/s - 67. 5.009733s
map(&:id) 8.929k (± 5.7%) i/s - 44. 4.999683s
Comparison:
pluck(:id): 13703.9 i/s
map(&:id): 8929.1 i/s - 1.53x (± 0.00) slower
Calculating
を確認すると、pluck(:id)
のほうがmap(&:id)
よりも数値が大きいです。つまりpluck(:id)
のほうが高速ということを意味しています。
pluck(:id)
のほうが高速であることは、Comparison
でmap(&:id)
に対してslower
という記述があることからも分かります。
参考: Benchmarkモジュールとbenchmark-ipsのベンチマークテスト比較
比較のため同じベンチマークテストをBenchmarkモジュールで行った場合とbenchmark-ipsで行った場合を掲載しておきます。
Benchmarkモジュールの場合
n = 20000
Benchmark.bm(10) do |x|
x.report("pluck(:id)") { n.times { Student.all.pluck(:id) } }
x.report("map(&:id)") { n.times { Student.all.map(&:id) } }
end
実行結果
user system total real
pluck(:id) 1.444674 0.019573 1.464247 ( 1.468776)
map(&:id) 2.077519 0.005431 2.082950 ( 2.089609)
benchmark-ipsの場合
Benchmark.ips do |x|
x.report("pluck(:id)") { Student.all.pluck(:id) }
x.report("map(&:id)") { Student.all.map(&:id) }
end
実行結果
Warming up --------------------------------------
pluck(:id) 1.471k i/100ms
map(&:id) 912.000 i/100ms
Calculating -------------------------------------
pluck(:id) 12.889k (± 5.4%) i/s - 64.724k in 5.037596s
map(&:id) 8.921k (± 5.1%) i/s - 44.688k in 5.023643s
まとめ
- 『Benchmark.ips do~end』で処理を囲むことでベンチマークテストができる
- ベンチマークは『繰り返し回数/時間』で評価される。値が大きいほど高速
- benchmark-ipsはBenchモジュールと違い、繰り返し回数を明記する必要はない