How to Configure Ruby to Enter the Debugger on Ctrl-C (Sigint)

How do I configure ruby to enter the debugger on Ctrl-C (SIGINT)?

If you want to trap SIGINT while running in the console, the short answer is: you cannot unless you monkey-patch IRB. Every Ruby app (whether padrino, or rails or whatnot) that uses the console will end up calling usr/lib/ruby/1.9.1/irb.rb, and in IRB.start, it does:

trap("SIGINT") do
irb.signal_handle
end

... just before entering the main loop. This will override any trap("SIGINT") you might have put in your startup code.

But if you want to trap SIGINT in a script file (for example, if you want to profile your code as described by Mike Dunlavey here), you can create a script file such as:

# File: profile_complex_operation.rb
trap("SIGINT") { debugger }
MyApp.complex_operation

and then invoke it as in:

$ ruby profile_complex_operation.rb

Now, when you hit ^C (or send SIGINT from another process), it will enter the debugger.

How do I use the keyboard to break into ruby-debug running a rails app?

I recommend pry over ruby-debug. Install the gem and then you can just stick this into your code where you want to debug:

binding.pry

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

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.

What is the difference between Ctrl-C and SIGINT?

^C sends a SIGINT to all the processes in the foreground process group. To do the equivalent with kill, you should send the signal to the process group (OS-level concept):

kill -SIGINT -<pid>

or to the job (shell-level concept, the pipeline ended with &):

kill -SIGINT %

Profiling Ruby Code

Lots of profilers are like that.
What you need to know is not where the program spends its time, but why. Any references on Dynamic Code Analysis?

ADDED: Here's how I find "bottlenecks" in my code. (I hate that word.)
Here's a list of reasons why.

It is perfectly natural to assume that to find "bottlenecks" you have to somehow do a lot of measuring.
It is so natural that nearly all profilers are based on it.

Actually, finding and measuring are not the same problem. Measuring is needed to see if what you found (and fixed) made a difference. Finding what to fix, to me, is more like debugging than measuring.

The simplest way to explain it is to start from an infinite, or nearly infinite loop. How do you find it? You pause it and look at the stack, right? because you know the problem is somewhere on the stack. You only need to pause it once, and then you need to study the code on the stack. Pause it a few times if you want to be sure you've found it.

Suppose the code only takes twice as long as necessary. That means when you pause it, there is a 50% chance you will see it doing the unnecessary thing. If you pause it and look at it 10 times, you will catch it in the act roughly 5 times. In fact, as soon as you see it doing something you can optimize on as few as 2 samples, you've found a "bottleneck". Fix it, measure the speedup, show it off, and repeat.

Even if your biggest problem is not very big, this method will eventually find it.
Also, there's a magnification phenomenon, where small problems become easier to find after you've removed larger ones. That allows you to keep going until the code is nearly optimal.

P.S. After you've done this, there may still be opportunities for speedup. For example, optimization algorithms can depend on numerical stability. Message-driven architectures can make it harder to trace why code is being executed. In real-time software, a performance problem may only happen occasionally, and be less easy to sample. This requires more cleverness. Falling back on just measuring doesn't do it.



Related Topics



Leave a reply



Submit