【问题标题】:How do you view a sample of the call stack in ruby?您如何查看 ruby​​ 中的调用堆栈示例?
【发布时间】:2011-09-13 10:21:20
【问题描述】:

我正在研究不同的优化技术,我发现这篇文章Analyzing Code for Efficiency? 的人认为对调用堆栈进行采样比使用分析器更有效。基本思想是,如果您查看调用堆栈,您会看到您的应用程序最有可能花费大部分时间的地方,然后在那里进行优化。

这当然很有趣,他显然是这方面的专家,但我不知道如何在 ruby​​ 中查看调用堆栈。在调试器中我可以说“信息堆栈”,但似乎只显示一行。

编辑:我看到 Mike Dunlavey 的评论:“我只想指出,如果你在调试器下运行,手动中断它,并显示调用堆栈......”

我只是不确定如何手动中断它并显示调用堆栈。

【问题讨论】:

  • 不是像许多分析器那样精确地对堆栈进行采样吗?以 stackprof 为例。

标签: ruby-on-rails ruby optimization profiling


【解决方案1】:

您可以随时抛出异常,然后查看$@ 预定义变量,该变量返回一个回溯数据数组。例如。把它放在 foo.rb 中:

begin                                                                        
  raise 'foo'                                                                
rescue                                                                       
  puts $@                                                                    
end  

然后运行它:

$ ruby foo.rb 
foo.rb:2:in `<main>'

【讨论】:

  • 这是否适用于性能优化?如果想法是在应用程序运行缓慢时查看堆栈跟踪,那么您似乎需要知道瓶颈在哪里的 catch-22 情况,以便在正确的位置添加此代码?
  • @d11wtq,这个想法是在开始和救援之间运行您的应用程序,并在应用程序运行缓慢时按 Ctrl-C。这往往会落在应用程序花费大部分时间做的事情上。优化这将带来最大的收益。
  • 啊,好的,谢谢。当我在 1.9.2 中这样做时。无论begin..rescue 块如何,我都会得到Interrupt 和堆栈跟踪。当进程以SIGINT 终止时,begin..rescue 块在哪里发挥作用?我担心我在这里可能有点金发 o_O
【解决方案2】:

随便放

puts caller

代码中的任何地方。如果您不喜欢它的格式,它是一个字符串数组,因此您可以对所需的输出进行一些正则表达式操作。

【讨论】:

  • p callerputs caller.inspect 将为您提供更好的输出格式。
  • 不需要.join("\n")
  • 这似乎没有回答这个问题。在代码中的特定点打印调用堆栈可能很有用,但它不是随机样本。它不会在随机选择的时间点告诉您堆栈中的内容。
【解决方案3】:

如何向 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_...

在适当的采样时间重复信号。

【讨论】:

    猜你喜欢
    • 2018-09-02
    • 1970-01-01
    • 2017-01-26
    • 2019-04-06
    • 2017-08-05
    • 2012-07-07
    • 2012-01-24
    • 2023-04-06
    • 1970-01-01
    相关资源
    最近更新 更多