Rubyメソッドの測定とベンチマーク時間


87

Rubyでメソッドとそのメソッドの個々のステートメントにかかる時間を測定するにはどうすればよいですか。以下のメソッドが表示された場合、そのメソッドにかかった合計時間と、データベースアクセスおよびredisアクセスにかかった時間を測定したいと思います。すべてのステートメントの前にBenchmark.measureを書きたくありません。ルビーインタプリタはこれを行うためのフックを私たちに与えますか?

def foo
# code to access database
# code to access redis. 
end

new Date()rubyが持っているjavascriptに似たものがありますが、正しい構文を思い出せません。しかし、あなたにまともなグーグルリストを与えるはずです
reagan 2012

1
@Phani正解を選択していただけますか?8年後、ここには確かな答えがあると思います。ありがとう。
Joshua Pinter

回答:


113

Timeオブジェクトを使用できます。(タイムドキュメント

例えば、

start = Time.now
# code to time
finish = Time.now

diff = finish - start

diff 浮動小数点数として、秒単位になります。

編集:end予約されています。


13
ちょっとした修正です。endは予約されているため、他の変数名を使用してください。
ジェイソンキム

4
Time.nowはシステムクロックの調整の影響を受けるため、Process.clock_gettime(Process::CLOCK_MONOTONIC)代わりに使用することをお勧めします。しかし、大まかな計算では、これは重要ではありません。blog.dnsimple.com/2018/03/elapsed-time-with-ruby-the-right-way
PatrickBrinich-Langlois19年

102

最も簡単な方法:

require 'benchmark'

def foo
 time = Benchmark.measure {
  code to test
 }
 puts time.real #or save it to logs
end

サンプル出力:

2.2.3 :001 > foo
  5.230000   0.020000   5.250000 (  5.274806)

値は、CPU時間、システム時間、合計および実際の経過時間です。

出典:rubydocs


40
Benchmark.realtime { block }リアルタイムが必要な場合にも実行できます
jmccure 2015年

35

Benchmarkのレポートを使用する

require 'benchmark' # Might be necessary.

def foo
  Benchmark.bm( 20 ) do |bm|  # The 20 is the width of the first column in the output.
    bm.report( "Access Database:" ) do 
      # Code to access database.
    end
   
    bm.report( "Access Redis:" ) do
      # Code to access redis.
    end
  end
end

これにより、次のような出力が返されます。

                        user     system      total        real
Access Database:    0.020000   0.000000   0.020000 (  0.475375)
Access Redis:       0.000000   0.000000   0.000000 (  0.000037)

<------ 20 -------> # This is where the 20 comes in. NOTE: This is not shown in output.

詳細については、こちらをご覧ください


2
私は自分の答えに戻ったばかりで、ベンチマークがこれをどのように処理するかに(再び)感銘を受けました。Rubyが大好きです。
Joshua Pinter 2017

2
Ruby 2.2以降、Benchmark他の回答で説明されているように、クラスは単調なクロックを使用するため、これが推奨される回答です。たとえば、次のソースコードを参照し、286行目で「defmeasure
ruby

17

回答の多くは、の使用を示唆していますTime.now。しかし、それはTime.now変わる可能性があることを知っておく価値があります。システムクロックはドリフトする可能性があり、システムの管理者またはNTPを介して修正される可能性があります。したがって、Time.nowが前後にジャンプして、ベンチマークに不正確な結果を与える可能性があります。

より良い解決策は、常に前進しているオペレーティングシステムの単調な時計を使用することです。Ruby 2.1以降では、次の方法でこれにアクセスできます。

start = Process.clock_gettime(Process::CLOCK_MONOTONIC)
# code to time
finish = Process.clock_gettime(Process::CLOCK_MONOTONIC)
diff = finish - start # gets time is seconds as a float

詳細については、こちらをご覧ください。また、人気のあるRubyプロジェクトであるSidekiqが単調な時計に切り替えたのを見ることができます。


7

2番目の考えとして、Rubyコードブロック引数を使用してmeasure()関数を定義すると、時間測定コードを単純化するのに役立ちます。

def measure(&block)
  start = Time.now
  block.call
  Time.now - start
end

# t1 and t2 is the executing time for the code blocks.
t1 = measure { sleep(1) }

t2 = measure do
  sleep(2)
end

あなたの定義では、あなたはそれを呼びますbenchmark。あなたがそれを使うとき、それはと呼ばれmeasureます。これを修正してください。
Sandro L

4

wquistの答えの精神で、しかし少し簡単に、あなたは以下のようにそれを行うこともできます:

start = Time.now
# code to time
Time.now - start

この回答は、質問に回答するための(わずかに)異なる方法です。@wquistの答えからそれを理解できたからといって、それが有効でないことを意味するわけではありません。
thesecretmaster 2018年

3

ruby-profパッケージを調べてください。必要なものが含まれているはずです。それはタイミングで巨大なコールスタックを作成します。

http://ruby-prof.rubyforge.org/

細かすぎる可能性があります。その場合は、大きなセクションをラップするだけでBenchmark.measureよいでしょう。


弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.