Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do you view a sample of the call stack in ruby?

I'm investigating different optimization techniques, and I came across this post Analyzing Code for Efficiency? by someone who believes that sampling the call stack is more effective than using a profiler. The basic idea is that if you take a view of the call stack, you see where your application is most likely to be spending most of its time, and then optimize there.

It is certainly interesting, and he is obviously an expert on this, but I don't know how to view the call stack in ruby. In debugger I can say "info stack" but only seems to show one line.

EDIT: I saw this comment by Mike Dunlavey: "I would just like to point out that if you run under the debugger, interrupt it manually, and display the call stack..."

I'm just not sure how to interrupt it manually and dipslay the call stack.

like image 821
Jeremy Smith Avatar asked Jun 12 '11 14:06

Jeremy Smith


People also ask

How can I see the call stack?

While debugging, in the Debug menu, select Windows > Call Stack or press ctrl + alt + C . A yellow arrow identifies the stack frame where the execution pointer is currently located. By default, this stack frame's information appears in the source, Locals, Autos, Watch, and Disassembly windows.

What is a call stack in Ruby?

Whenever you call a method, Ruby places a stack frame on the call stack (or "runtime stack", but often just called "stack"). The stack frame is a memory allocation that holds the method's arguments, some space for internal variables, and the return address of the caller.

What is call stack in debugging?

The call stack is a list of all the active functions that have been called to get to the current point of execution. The call stack includes an entry for each function called, as well as which line of code will be returned to when the function returns.

What is current call stack?

In computer science, a call stack is a stack data structure that stores information about the active subroutines of a computer program. This kind of stack is also known as an execution stack, program stack, control stack, run-time stack, or machine stack, and is often shortened to just "the stack".


3 Answers

Just put

puts caller 

anywhere in the code. If you don't like its format, it's an array of strings, so you can do some regex manipulation for a desired output.

like image 81
sawa Avatar answered Oct 04 '22 00:10

sawa


How about sending signal to the ruby process, and creating a handler for the signal which dumps all stacks?

From http://le-huy.blogspot.com/2012/04/dump-backtrace-of-all-threads-in-ruby.html we have this example :

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 

Then we need to send the signal to the appropriate process :

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

Repeat the signal at appropriate sampling time.

like image 45
YudhiWidyatama Avatar answered Oct 03 '22 23:10

YudhiWidyatama


You can throw an exception at any time, and then look at the $@ predefined variable, which returns an array of backtrace data. E.g. put this in foo.rb:

begin                                                                        
  raise 'foo'                                                                
rescue                                                                       
  puts $@                                                                    
end  

Then run it:

$ ruby foo.rb 
foo.rb:2:in `<main>'
like image 25
Mori Avatar answered Oct 03 '22 22:10

Mori