Rubyで特定の箇所の処理に要する時間を計測したい場合、これまでは

1
2
3
4
5
start_time = Time.now
  # ・・・
  # (計測対象の処理)
  # ・・・
puts Time.now - start_time

なんてコードを書いたりしていたのですが、Rubyには標準モジュールとして benchmark が用意されており、これを使えば簡単に計測が可能なのでした。

複数の処理を一度に計測でき、余計な代入処理が無いのでコード的にも心理的にも(?)良い感じです。
複数の結果もそれぞれ任意のラベルを付けて、見やすい形で出力可能です。

検証環境

Ruby 2.7.1 / 2.1.1

テストコード

Array(配列)への要素の追加を1億回行った場合のメソッドによる処理時間の差を計測してみます。

  • 処理a:[].push(1) を1億回
  • 処理b:[] << 1 を1億回
  • 処理c:[] = [] + [1] を1億回

複数処理の比較も工夫するとすっきり書くことができます。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
# benchmark.rb

require 'benchmark'

n = 100000000

# "10" は結果出力のラベル幅を指定している
Benchmark.bm 10 do |r|
  # 処理a(do-end)
  ## 結果出力の「ラベル」を文字列で指定する
  r.report "Array#push" do
    ary = []
    n.times do
      ary.push(1)
    end
  end

  # 処理b(ブロック)
  r.report("Array#<<") {
    ary = []
    n.times do
      ary << 1
    end
  }

  # 処理c(ブロック1行)
  r.report("Array#+[]") { n.times do; ary = []; ary += [1]; end }
end

出力

実行時にラベル(”Array#push” 等の見出し部分)の幅を指定すると、結果出力の桁が揃うので見やすいです。

1
2
3
4
5
6
7
8
$ ruby -v
ruby 2.7.1p83 (2020-03-31 revision a0c7c23c9c) [x86_64-linux]

$ ruby benchmark.rb
                 user     system      total        real
Array#push   5.078125   1.000000   6.078125 (  6.077756)
Array#<<     3.796875   1.046875   4.843750 (  4.848366)
Array#+[]   10.171875   0.078125  10.250000 ( 10.241070)

旧いバージョンのRubyではパフォーマンスが低下するのも一目瞭然。

1
2
3
4
5
6
7
8
$ ruby -v
ruby 2.1.10p492 (2016-04-01 revision 54464) [x86_64-linux]

$ ruby benchmark.rb
                 user     system      total        real
Array#push   6.640000   0.000000   6.640000 (  6.629305)
Array#<<     5.300000   0.000000   5.300000 (  5.305064)
Array#+[]   10.530000   0.000000  10.530000 ( 10.549397)

参考