web-dev-qa-db-ja.com

Rubyで呼び出しスタックのサンプルをどのように表示しますか?

私はさまざまな最適化手法を調査していて、この投稿に出くわしました コードを効率的に分析していますか? コールスタックのサンプリングがプロファイラーを使用するよりも効果的であると信じている人によって。基本的な考え方は、コールスタックを表示すると、アプリケーションがほとんどの時間を費やす可能性が最も高い場所を確認し、そこで最適化することです。

それは確かに興味深いものであり、彼は明らかにこれに関する専門家ですが、Rubyでコールスタックを表示する方法がわかりません。デバッガでは「情報スタック」と言うことができますが、1行しか表示されないようです。

編集:私はマイクダンレービーのこのコメントを見ました:「デバッガーの下で実行する場合、手動で中断して、コールスタックを表示することを指摘したい...」

手動で中断してコールスタックをディップレイする方法がわかりません。

44
Jeremy Smith

置くだけ

puts caller

コードのどこでも。形式が気に入らない場合は、文字列の配列なので、目的の出力に対して正規表現を操作できます。

84
sawa

Rubyプロセスにシグナルを送信し、すべてのスタックをダンプするシグナルのハンドラーを作成するのはどうですか?

http://le-huy.blogspot.com/2012/04/dump-backtrace-of-all-threads-in-Ruby.html から、次の例があります。

require 'pp'

def backtrace_for_all_threads(signame)
  File.open("/tmp/Ruby_backtrace_#{Process.pid}.txt","a") do |f|
      f.puts "--- got signal #{signame}, dump backtrace for all threads at #{Time.now}"
      if Thread.current.respond_to?(:backtrace)
        Thread.list.each do |t|
          f.puts t.inspect
          PP.pp(t.backtrace.delete_if {|frame| frame =~ /^#{File.expand_path(__FILE__)}/},
               f) # remove frames resulting from calling this method
        end
      else
          PP.pp(caller.delete_if {|frame| frame =~ /^#{File.expand_path(__FILE__)}/},
               f) # remove frames resulting from calling this method
      end
  end
end

Signal.trap(29) do
  backtrace_for_all_threads("INFO")
end

次に、適切なプロセスに信号を送信する必要があります。

ps afxw | grep Ruby
kill -29 <pid>
ls -l /tmp/Ruby*
vi /tmp/Ruby_backtrace_...

適切なサンプリング時間で信号を繰り返します。

6
YudhiWidyatama

いつでも例外をスローしてから、$@事前定義変数。バックトレースデータの配列を返します。例えば。これをfoo.rbに入れます:

begin                                                                        
  raise 'foo'                                                                
rescue                                                                       
  puts $@                                                                    
end  

次にそれを実行します:

$ Ruby foo.rb 
foo.rb:2:in `<main>'
4
Mori