benchmark
概要
コードの実行時間を測定するツール
ruby標準ライブラリなのでめっちゃ簡単に使える
Time.nowを使って計測した場合の問題点
code:ruby
start_time = Time.now
# 計測処理
puts Time.now - start_time
CPUは他の処理も行っているのでその時間も含まれてしまう
ディスクアクセス/ネットワークアクセスを含む処理の場合はCPUが何もしていない時間も含めて計測してしまう
出力例
code:ruby
require 'benchmark'
time = Benchmark.measure do
sum = 0
1_000_000.times { sum += 1 }
end
puts time
# 出力例
# 0.030158 0.000143 0.030301 ( 0.030381)
# => #<Benchmark::Tms:0x0000000143e70920 @cstime=0.0, @cutime=0.0, @label="", @real=0.030381000600755215, @stime=0.00014300000000000423, @total=0.030301000000000133, @utime=0.03015800000000013> user(utime): プログラム内の処理に費やされたCPU時間
system(stime): OSレベルの処理に費やされたCPU時間。システムコールの処理時間 total: user + system
real: 実際の経過時間
基本的にはuserかtotalどちらかを見れば良い
使い方
benchmark(caption = "", label_width = nil, fmtstr = nil, *labels) {|rep| ...} -> [Benchmark::Tms]
最も低レベルなメソッドで計測結果のカスタマイズが自由にできる
bm / bmbmの基盤となるメソッド
高度なフォーマットが必要な場合に適している
bm(label_width = 0, *labels) {|rep| ... } -> [Benchmark::Tms]
benchmarkメソッドの引数を簡略化したメソッドでbenchmarkと同様に動作する
code:ruby
require 'benchmark'
n = 50000
Benchmark.bm(7) do |x|
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.050000 0.000000 1.050000 ( 0.503462)
# times: 1.533333 0.016667 1.550000 ( 0.735473)
# upto: 1.500000 0.016667 1.516667 ( 0.711239)
code:ruby
require 'benchmark'
n = 50000
Benchmark.bm(7, ">total:", ">avg:") do |x|
tf = x.report("for:") { for i in 1..n; a = "1"; end }
tt = x.report("times:") { n.times do ; a = "1"; end }
tu = x.report("upto:") { 1.upto(n) do ; a = "1"; end }
end
# user system total real
# for: 0.001467 0.004727 0.006194 ( 0.006193)
# times: 0.003814 0.000000 0.003814 ( 0.003814)
# upto: 0.003855 0.000003 0.003858 ( 0.003859)
# >total: 0.009136 0.004730 0.013866 ( 0.013867)
# >avg: 0.003045 0.001577 0.004622 ( 0.004622)
それぞれの処理に対してtotal、avgなども加える
bmbm(width = 0) {|job| ... } -> [Benchmark::Tms]
実際の性能をより正確に測定したい場合に使用する
ベンチマークの結果は GC の影響によって歪められてしまうことがあります。このメソッドは与えられたブロックを二度実行する事によってこの影響を最小化します。一回目は実行環境を安定化するためにリハーサルとして実行します。二回目は本番として実行します。
code:ruby
require 'benchmark'
array = (1..1000000).map { rand }
Benchmark.bmbm do |x|
x.report("sort!") { array.dup.sort! }
x.report("sort") { array.dup.sort }
end
#
# Rehearsal -----------------------------------------
# sort! 11.928000 0.010000 11.938000 ( 12.756000)
# sort 13.048000 0.020000 13.068000 ( 13.857000)
# ------------------------------- total: 25.006000sec
#
# user system total real
# sort! 12.959000 0.010000 12.969000 ( 13.793000)
# sort 12.007000 0.000000 12.007000 ( 12.791000)
measure(label = "") { ... } -> Benchmark::Tms
純粋に1つの処理だけを計測したい場合に便利
出力はヘッダーもないので純粋に結果だけを見たい場合やログ出力したい場合
code:ruby
puts Benchmark.measure { "a"*1_000_000 }
# 1.166667 0.050000 1.216667 ( 0.571355)
realtime { ... } -> Float
userやsystemの情報は不要で、実行にかかった「経過時間」だけが知りたい場合に使う
code:ruby
puts Benchmark.realtime { 0 * (10**8) } # => 1.0929416846483946 table:比較表
メソッド 用途 特徴
benchmark カスタマイズしたフォーマットで結果を出力 高度なフォーマット設定が可能。低レベルなインターフェース。
bm 複数処理の比較(単純) 見やすいヘッダー付き。キャッシュやJITコンパイルの影響は排除されない。
bmbm 複数処理の比較(正確) リハーサルを実行し、キャッシュやJITコンパイルの影響を排除。
measure 単一処理の実行時間を測定 実行時間を簡潔に測定し、文字列で返す。
realtime 実行時間(real time)だけが必要な場合 結果が数値で返される。シンプルな計測用。
複数処理の比較をしたい
→ キャッシュを考慮しないならbm、正確な比較を求めるならbmbm。
単一処理の簡単な計測をしたい
→ measureまたはrealtime。
フォーマットや結果の整形をカスタマイズしたい
→ benchmark。
/icons/hr.icon