The Rubinius Debugger
Join the DZone community and get the full member experience.
Join For FreeWhen I read the posting about Cylon, the Ruby debugger for Visual Studio by SapphireSteel, I immediately thought about the Rubinius debugger highlighted in InfoQ recently. I decided to give it a try and see what I came up with. I wasn’t able to replicate Dermot’s tests exactly (I don’t know where he set his breakpoints, and Rubinius doesn’t support everything he tested), but here are my initial results:
Rubinius no debugger | Rubinius w/debugger no breakpoints | Ruby |
---|---|---|
2.039 seconds | 2.399 seconds | 0.898 seconds |
Rubinius no debugger | Rubinius w/debugger no breakpoints | Ruby |
---|---|---|
13.441 seconds | 13.999 seconds | 4.171 seconds |
Rubinius still has a long performance road ahead of them in terms of general execution, but it’s pretty exciting to see that their debugger is so fast. The cylon debugger (which smoked the other options in their testing) was 25% slower for line based debugging, and 306% slower for call based. By comparison, Rubinius’ debugger only added 17% for line based and 4% for call based (actually, I’m guessing that had the line based run through more iterations, the Rubinius debugger would have done better, I think most of its time is spent in set up).
Using the Rubinius debugger requires that you add a call to the debugger to the program:
debugger
def fac(n)
lvar = n
n == 1 ? 1 : n * fac(n-1)
return n
end
count = 0
tstart = Time.new
0.upto(1000000) {fac(5)} # line based
#0.upto(30000000) {count += 1} # call based
tend = Time.new
puts "%10.3f" % tstart
puts "%10.3f" % tend.to_f
diff = tend - tstart
puts "%10.3f" % diff.to_f
When you run this, you’ll get something like this:
$ ../shotgun/rubinius debug_fac.rb
[Debugger activated]
debug_fac.rb:1 [IP:5]
rbx:debug> c
[Resuming program]
1201801369.694
1201801372.001
2.307
There are several commands available:
command | explanation |
---|---|
h | get a listing of commands |
b | list breakpoints |
b |
set a breakpoint at the start of the method |
n | Step to the next line |
ni | step to the next VM instruction |
c | continue execution until the next breakpoint |
l | list source code around the current breakpoint |
d | decode VM bytecode around the current breakpoint |
v | display local variables and their values |
vs | display the contents of the VM stack |
Some of these are pretty cool, take a look at these examples:
rbx:debug> vs
VM stack [0-5]:
sp => 0: TrueClass true
fp => 1: Class Rubinius::VM
2: String ""
3: String "debug_fac.rb"
4: String "debug_fac.rbc"
5: NilClass nil
...
or:
rbx:debug> d
Bytecode instructions [5-25] in compiled method script:
...
# line 1
0005: pop
# line 3
0006: push_literal #
0008: push_literal :fac
0010: push_self
0011: send_stack :add_method, 2
0014: pop
# line 9
=> 0015: meta_push_0
0016: set_local :count
0018: pop
# line 11
0019: push_const :Time
0021: send_method :new
0023: set_local :tstart
0025: pop
...
which compares to:
rbx:debug> l
Source lines [1-18] in debug_fac.rb:
1: debugger
2:
3: def fac(n)
4: lvar = n
5: n == 1 ? 1 : n * fac(n-1)
6: return n
7: end
8:
=> 9: count = 0
10:
11: tstart = Time.new
12: 0.upto(1000000) {fac(5)} # $-1òølineòù based
13: #0.upto(30000000) {count += 1} #$-1òùcallòù based
14: tend = Time.new
15: puts "%10.3f" % tstart
16: puts "%10.3f" % tend.to_f
17: diff = tend - tstart
18: puts "%10.3f" % diff.to_f
Like a lot of things in Rubinius, the debugger isn’t quite ready for primetime but it sure shows a lot of promise.
Opinions expressed by DZone contributors are their own.
Comments