Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Ruby Debugger Internals

Ruby Debugger Internals

How does a Ruby debugger look and work on the inside? Is it difficult to write a debugger? Hear the full story of supporting Ruby 2.0 straight from the maintainer of the RubyMine debugger. In this session we'll expose debugger internals, including different APIs used by debuggers; review how they evolved; and look at what it takes to keep the performance of a debugged application at a reasonable level. We'll also talk about alternative implementations including JRuby and Rubinius.

Avatar for Dennis Ushakov

Dennis Ushakov

April 23, 2015
Tweet

More Decks by Dennis Ushakov

Other Decks in Programming

Transcript

  1. Measurement • Small sample program • 42M iterations • No

    IO operations • require ‘benchmark’
  2. Sample Program MAGIC_NUMBER = 42_000_000
 
 def goto_rails_conf
 "RailsConf 2015"


    end
 
 def our_action
 MAGIC_NUMBER.times { goto_rails_conf }
 end
  3. Sample Program MAGIC_NUMBER = 42_000_000
 
 def goto_rails_conf
 "RailsConf 2015"


    end
 
 def our_action
 MAGIC_NUMBER.times { goto_rails_conf }
 end 4.97s
  4. Event Types • line • call & return • c-call

    & c-return • class & end • raise • b-call & b-return — Ruby 2.0 • thread-begin & thread-end — Ruby 2.0
  5. Sample Output call sample.rb:7 our_action Object
 line sample.rb:8 our_action Object


    c-call sample.rb:8 times Integer
 line sample.rb:8 our_action Object
 call sample.rb:3 goto_rails_conf Object
 line sample.rb:4 goto_rails_conf Object
 return sample.rb:5 goto_rails_conf Object
 c-return sample.rb:8 times Integer
 return sample.rb:9 our_action Object
  6. Ruby 1.0: set_trace_func MAGIC_NUMBER = 42_000_000
 
 def goto_rails_conf
 "RailsConf

    2015"
 end
 
 def our_action
 MAGIC_NUMBER.times { goto_rails_conf }
 end 120.14s
  7. event_hook gem • If there’s a C API there should

    be a wrapper gem for it • Well, no
  8. debug_inspector gem • If there’s a C API there should

    be a wrapper gem for it that’s obsolete • Well, no
  9. debug_inspector gem RubyVM::DebugInspector.open do |dc|
 locations = dc.backtrace_locations
 locations.size.times do

    |i|
 p dc.frame_binding(i)
 p dc.frame_iseq(i)
 p dc.frame_class(i)
 end
 end
  10. Rubinius • No need for explicit file & line checks

    • Breakpoints are attached to the instruction
  11. Rubinius: set_breakpoint @breakpoints.each { |b|
 if b.source == script.file_path
 exec,

    ip = script.compiled_code.locate_line(b.pos)
 if exec
 exec.set_breakpoint ip, b
 end
 end
 }
  12. JRuby • org.jruby.runtime.EventHook • public boolean isInterestedInEvent(RubyEvent event) • public

    void eventHandler(
 ThreadContext tCtx, 
 String event, 
 String file, int line, 
 String methodName, 
 IRubyObject klass
 )