web-dev-qa-db-ja.com

プロファイリングRubyコード

Ruby-profとコアBenchmarkクラスに加えて、Rubyコードのプロファイルを作成するために何を使用しますか?特に、コードのボトルネックをどのように見つけますか?ほとんど私がする必要があるように感じます自分の小さなツールを使って、コードのどこですべての時間が費やされているかを把握します。

Ruby-profがこれを提供していることは理解していますが、出力は率直に言って非常に紛らわしく、自分のコードの実際のブロックが問題の原因であるかどうかを簡単に見つけることができません(どのメソッド呼び出しに最も時間がかかったかがわかります)しかし)。ですから、私はそれを私が望むほど多くは得られておらず、実際にそれを利用することができていません。

おそらく私はそれを間違っているのですか?代替手段はありますか?グーグル検索は私にとって何ももたらさない。

33
ehsanul

多くのプロファイラーはそのようなものです。あなたが知る必要があるのは、プログラムが時間を費やすwhereではなく、why動的コード分析に関する参照はありますか?

追加: 方法は次のとおりです コードに「ボトルネック」が見つかりました。 (私はその言葉が嫌いです。) ここにリストがあります 理由の。

「ボトルネック」を見つけるには、どういうわけか多くの測定をしなければならないと考えるのは完全に自然なことです。ほとんどすべてのプロファイラーがそれに基づいているのはとても自然なことです。

実際、発見と測定は同じ問題ではありません。あなたが見つけた(そして修正した)ものが違いを生んだかどうかを見るために測定が必要です。私にとって、何を修正するかを見つけることは、測定というよりはデバッグに似ています。

それを説明する最も簡単な方法は、無限ループまたはほぼ無限ループから始めることです。どうやって見つけますか?一時停止してスタックを確認しますよね?問題がスタックのどこかにあることがわかっているからです。一時停止する必要があるのは1回だけで、その後、スタック上のコードを調べる必要があります。確実に見つけたい場合は、数回一時停止してください。

コードに必要な時間の2倍しかかからないとします。つまり、一時停止すると、50%の確率で不要な処理を実行していることがわかります。一時停止して10回見ると、約5回の演技で捕まえます。実際、わずか2つのサンプルで最適化できることを実行しているのを見るとすぐに、「ボトルネック」が見つかります。それを修正し、スピードアップを測定し、見せびらかして、繰り返します。

あなたの最大の問題がそれほど大きくなくても、この方法は最終的にそれを見つけるでしょう。また、拡大現象があり、大きな問題を削除すると小さな問題が見つけやすくなります。これにより、コードがほぼ最適になるまで続行できます。

P.S.これを行った後でも、スピードアップの機会があるかもしれません。たとえば、最適化アルゴリズムは数値的安定性に依存する可能性があります。メッセージ駆動型アーキテクチャでは、コードが実行されている理由を追跡するのが難しくなる可能性があります。リアルタイムソフトウェアでは、パフォーマンスの問題はたまにしか発生しない可能性があり、サンプリングが簡単ではありません。これにはもっと賢さが必要です。測定だけに頼るだけではうまくいきません。

6
Mike Dunlavey

コードを実際に掘り下げるには、 stackprof を試してください。

使用方法の簡単な解決策は次のとおりです。gemをインストールします:_gem install stackprof_。コードに次を追加します:_require 'stackprof'_そしてこれでチェックしたい部分を囲みます:

StackProf.run(mode: :cpu, out: 'stackprof-output.dump') do {YOUR_CODE} end

Rubyスクリプトを実行した後、_stackprof stackprof.dump_を使用してターミナルの出力を確認してください。

_Mode: cpu(1000)
Samples: 9145 (1.25% miss rate)
GC: 448 (4.90%)

 TOTAL    (pct)     SAMPLES    (pct)     FRAME
   236   (2.6%)         231   (2.5%)     String#blank?
   546   (6.0%)         216   (2.4%)     ActiveRecord::ConnectionAdapters::Mysql2Adapter#select
   212   (2.3%)         199   (2.2%)     Mysql2::Client#query_with_timing
   190   (2.1%)         155   (1.7%)     ERB::Util#html_escape``
_

ここでは、多くの時間を必要とするすべてのメソッドを確認できます。ここで素晴らしい部分です。ドリルインするには、_stackprof stackprof.dump --method String#blank?_を実行するだけで、特定のメソッドの出力が得られます。

_String#blank? (lib/active_support/core_ext/object/blank.rb:80)
  samples:   231 self (2.5%)  /    236 total (2.6%)
  callers:
    112  (   47.5%)  Object#present?
  code:
                                  |    80  |   def blank?
  187    (2.0%) /   187   (2.0%)  |    81  |     self !~ /[^[:space:]]/
                                  |    82  |   end
_

また、コードのどの部分の実行に時間がかかるかを簡単に把握できます。

視覚的な出力を取得したい場合は、_stackprof stackprof.dump --graphviz >> stackprof.dot_を実行し、graphviz(_brew install graphviz_)_dot -T pdf -o stackprof.pdf stackprof.dot_を使用して美しいPDF出力を取得します。これにより、実行するメソッドが強調表示されます。実行するのに長い時間。

10
conscho

これは私自身の質問ですが、プロファイリングに非常に優れたツールを見つけたので、ここに追加する必要があります。

http://samsaffron.com/archive/2013/03/19/flame-graphs-in-Ruby-miniprofiler

フレームグラフは、バックトレースを見ると比較して、パフォーマンスの問題の原因を驚くほど明白にします。

3
ehsanul

もあります Ruby -rprofileまたは同等にRuby source、require 'profile'

ドキュメンテーション:

https://Ruby-doc.org/stdlib-2.1.0/libdoc/profiler/rdoc/Profiler__.html

2