web-dev-qa-db-fra.com

Comment voyez-vous un échantillon de la pile d'appels en rubis?

J'étudie différentes techniques d'optimisation, et je suis tombé sur ce post Analyzing Code for Efficiency? par quelqu'un qui pense que l'échantillonnage de la pile d'appels est plus efficace que l'utilisation d'un profileur. L'idée de base est que si vous regardez la pile d'appels, vous voyez où votre application est la plus susceptible de passer la plupart de son temps, puis vous y optimisez.

C'est certainement intéressant, et il est évidemment un expert en la matière, mais je ne sais pas comment afficher la pile d'appels dans Ruby. Dans le débogueur, je peux dire "pile d'informations" mais ne semble montrer qu'une seule ligne.

EDIT: J'ai vu ce commentaire de Mike Dunlavey: "Je voudrais juste souligner que si vous exécutez sous le débogueur, interrompez-le manuellement et affichez la pile des appels ..."

Je ne sais pas comment l'interrompre manuellement et afficher la pile d'appels.

44
Jeremy Smith

Mettez juste

puts caller

n'importe où dans le code. Si vous n'aimez pas son format, c'est un tableau de chaînes, vous pouvez donc faire quelques manipulations regex pour une sortie souhaitée.

84
sawa

Que diriez-vous d'envoyer un signal au processus Ruby, et de créer un gestionnaire pour le signal qui vide toutes les piles?

De http://le-huy.blogspot.com/2012/04/dump-backtrace-of-all-threads-in-Ruby.html nous avons cet exemple:

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

Ensuite, nous devons envoyer le signal au processus approprié:

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

Répétez le signal au moment d'échantillonnage approprié.

6
YudhiWidyatama

Vous pouvez lever une exception à tout moment, puis regarder le $@ variable prédéfinie, qui renvoie un tableau de données de suivi. Par exemple. mettez ceci dans foo.rb:

begin                                                                        
  raise 'foo'                                                                
rescue                                                                       
  puts $@                                                                    
end  

Exécutez-le ensuite:

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