前回、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モジュールと違い、繰り返し回数を明記する必要はない



