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

Beyond `puts`: TruffleRuby’s Modern Debugger Using Chrome

Beyond `puts`: TruffleRuby’s Modern Debugger Using Chrome

We all write bugs. How quickly we can identify & understand them depends on the quality of our tools.

In this talk you'll be introduced to TruffleRuby's modern debugger, based on the Chrome browser's DevTools Protocol. TruffleRuby's uniquely powerful set of tools let you debug, profile, and inspect the memory usage of Ruby code, native extensions, and other embedded languages all at the same time. Support for those tools is zero-overhead so you can have them always enabled. I'll show you how it all works and how it lets you step through Ruby code, inspect local variables, evaluate expressions, and more.

Kevin Menard

April 19, 2019
Tweet

More Decks by Kevin Menard

Other Decks in Programming

Transcript

  1. Beyond `puts`: TruffleRuby’s Modern
    Debugger Using Chrome
    Kevin Menard
    Oracle Labs
    @nirvdrum
    @nirvdrum

    View Slide

  2. Copyright © 2016, Oracle and/or its affiliates. All rights reserved. |
    Safe Harbor Statement
    The following is intended to provide some insight into a line of research in Oracle Labs. It
    is intended for information purposes only, and may not be incorporated into any contract.
    It is not a commitment to deliver any material, code, or functionality, and should not be
    relied upon in making purchasing decisions. The development, release, and timing of any
    features or functionality described in connection with any Oracle product or service
    remains at the sole discretion of Oracle. Any views expressed in this presentation are my
    own and do not necessarily reflect the views of Oracle.
    2

    View Slide

  3. Copyright © 2019, Oracle and/or its affiliates. All rights reserved. | 3
    Print Statement Debugging
    require 'net/http'
    require 'uri'
    def process(endpoint)
    res = Net::HTTP.get_response(URI(endpoint))
    if res.code >= 400
    if res.code == 404
    @logger.info "End point '#{endpoint}' does not exist"
    end
    else
    @record.update!(success: true)
    end
    end

    View Slide

  4. Copyright © 2019, Oracle and/or its affiliates. All rights reserved. | 4
    Print Statement Debugging
    Traceback (most recent call last):
    2: from demo.rb:16:in `'
    1: from demo.rb:5:in `process'
    /home/kjmenard/.rbenv/versions/2.6.2/lib/ruby/2.6.0/uri/common.rb:739:in `URI': bad
    argument (expected URI object or URI string) (ArgumentError)

    View Slide

  5. Copyright © 2019, Oracle and/or its affiliates. All rights reserved. | 5
    require 'net/http'
    require 'uri'
    def process(endpoint)
    p "Bad endpoint #{endpoint}"
    res = Net::HTTP.get_response(URI(endpoint))
    if res.code >= 400
    if res.code == 404
    @logger.info "End point '#{endpoint}' does not exist"
    end
    else
    @record.update!(success: true)
    end
    end

    View Slide

  6. Copyright © 2019, Oracle and/or its affiliates. All rights reserved. | 6
    "Bad endpoint: "
    Traceback (most recent call last):
    2: from demo.rb:18:in `'
    1: from demo.rb:7:in `process'
    /home/kjmenard/.rbenv/versions/2.6.2/lib/ruby/2.6.0/uri/common.rb:739:in `URI': bad
    argument (expected URI object or URI string) (ArgumentError)

    View Slide

  7. Copyright © 2019, Oracle and/or its affiliates. All rights reserved. | 7
    require 'net/http'
    require 'uri'
    def process(endpoint)
    p "Bad endpoint #{endpoint.inspect}"
    res = Net::HTTP.get_response(URI(endpoint))
    if res.code >= 400
    if res.code == 404
    @logger.info "End point '#{endpoint}' does not exist"
    end
    else
    @record.update!(success: true)
    end
    end

    View Slide

  8. Copyright © 2019, Oracle and/or its affiliates. All rights reserved. | 8
    "Bad endpoint: nil"
    Traceback (most recent call last):
    2: from demo.rb:18:in `'
    1: from demo.rb:7:in `process'
    /home/kjmenard/.rbenv/versions/2.6.2/lib/ruby/2.6.0/uri/common.rb:739:in `URI': bad
    argument (expected URI object or URI string) (ArgumentError)

    View Slide

  9. Copyright © 2019, Oracle and/or its affiliates. All rights reserved. | 9
    "Bad endpoint: \"http://google.com/\""
    Traceback (most recent call last):
    2: from demo.rb:18:in `'
    1: from demo.rb:9:in `process'
    demo.rb:9:in `>=': comparison of String with 400 failed (ArgumentError)

    View Slide

  10. Copyright © 2019, Oracle and/or its affiliates. All rights reserved. | 10
    require 'net/http'
    require 'uri'
    def process(endpoint)
    begin
    res = Net::HTTP.get_response(URI(endpoint))
    rescue ArgumentError => e
    @logger.error "Bad endpoint #{endpoint.inspect}: #{e.backtrace.inspect}"
    end
    pp res
    if res.code >= 400
    if res.code == 404
    @logger.info "End point '#{endpoint}' does not exist"
    end
    else
    @record.update!(success: true)
    end
    end

    View Slide

  11. Copyright © 2019, Oracle and/or its affiliates. All rights reserved. | 11
    #
    Traceback (most recent call last):
    2: from demo.rb:21:in `'
    1: from demo.rb:12:in `process'
    demo.rb:12:in `>=': comparison of String with 400 failed (ArgumentError)

    View Slide

  12. Copyright © 2019, Oracle and/or its affiliates. All rights reserved. | 12
    require 'net/http'
    require 'uri'
    def process(endpoint)
    begin
    res = Net::HTTP.get_response(URI(endpoint))
    rescue ArgumentError => e
    @logger.error "Bad endpoint #{endpoint.inspect}: #{e.backtrace.inspect}"
    end
    pp res.code
    if res.code >= 400
    if res.code == 404
    @logger.info "End point '#{endpoint}' does not exist"
    end
    else
    @record.update!(success: true)
    end
    end

    View Slide

  13. Copyright © 2019, Oracle and/or its affiliates. All rights reserved. | 13
    "301"
    Traceback (most recent call last):
    2: from demo.rb:21:in `'
    1: from demo.rb:12:in `process'
    demo.rb:12:in `>=': comparison of String with 400 failed (ArgumentError)

    View Slide

  14. Copyright © 2019, Oracle and/or its affiliates. All rights reserved. | 14
    require 'net/http'
    require 'uri'
    def process(endpoint)
    begin
    res = Net::HTTP.get_response(URI(endpoint))
    rescue ArgumentError => e
    @logger.error "Bad endpoint #{endpoint.inspect}: #{e.backtrace.inspect}"
    end
    if res.code.to_i >= 400
    if res.code.to_i == 404
    @logger.info "End point '#{endpoint}' does not exist"
    end
    else
    @record.update!(success: true)
    end
    end

    View Slide

  15. Copyright © 2019, Oracle and/or its affiliates. All rights reserved. | 15
    require 'net/http'
    require 'uri'
    def process(endpoint)
    begin
    res = Net::HTTP.get_response(URI(endpoint))
    rescue ArgumentError => e
    @logger.error "Bad endpoint #{endpoint.inspect}: #{e.backtrace.inspect}"
    end
    if res.code.to_i >= 400
    if res.code.to_i == 404
    @logger.info "End point '#{endpoint}' does not exist"
    end
    puts "WTH? #{res.code}"
    elsif res.code.to_i >= 300
    puts "DEAL WITH LATER"
    else
    puts "SUCCESS!"
    @record.update!(success: true)
    end
    end

    View Slide

  16. Copyright © 2019, Oracle and/or its affiliates. All rights reserved. |
    • TracePoint
    • ObjectSpace
    • caller/caller_locations
    • p/puts/pp
    • logger
    • binding
    • Binding#irb
    • backtrace/backtrace_locations
    • eval/instance_eval
    • instance_variables
    • instance_variable_get
    • instance_variable_set
    • local_variables
    • Class.constants
    16
    Ruby APIs for Debugging

    View Slide

  17. Copyright © 2019, Oracle and/or its affiliates. All rights reserved. |
    – Taken from https://code.visualstudio.com on 15 April, 2019
    17

    View Slide

  18. Copyright © 2019, Oracle and/or its affiliates. All rights reserved. |
    Enter: Debuggers
    • Tools that allow you to inspect program
    state and evaluate expressions without
    modifying the source
    • Ruby has many debuggers available
    – Usually don’t work across major Ruby versions
    – Usually don’t work across Ruby
    implementations
    – Frequently reinvent things due to lack of VM
    support
    18

    View Slide

  19. Copyright © 2019, Oracle and/or its affiliates. All rights reserved. |
    A New Standard for Debuggers: Chrome DevTools Protocol
    • Set of instrumentation & inspection APIs used by Chromium-based
    browsers to communicate with runtimes
    • Commonly used to debug and profile JavaScript in the browser
    • By defining a communication layer, we can replace or re-implement
    components
    19

    View Slide

  20. Copyright © 2019, Oracle and/or its affiliates. All rights reserved. | 20
    Chrome DevTools Protocol
    JavaScript Runtime
    Chromium-based Browser

    View Slide

  21. Copyright © 2019, Oracle and/or its affiliates. All rights reserved. | 21
    Chrome DevTools Protocol
    Chromium-based Browsers
    ?

    View Slide

  22. Copyright © 2019, Oracle and/or its affiliates. All rights reserved. |
    TruffleRuby Debugging Demo in Chrome
    22

    View Slide

  23. Copyright © 2019, Oracle and/or its affiliates. All rights reserved. | 23
    Chrome DevTools Protocol
    Chromium-based Browser

    View Slide

  24. Copyright © 2019, Oracle and/or its affiliates. All rights reserved. | 24
    Chrome DevTools Protocol
    ?

    View Slide

  25. Copyright © 2019, Oracle and/or its affiliates. All rights reserved. |
    TruffleRuby Debugging Demo in VS Code
    25

    View Slide

  26. Copyright © 2019, Oracle and/or its affiliates. All rights reserved. | 26
    Chrome DevTools Protocol

    View Slide

  27. Copyright © 2019, Oracle and/or its affiliates. All rights reserved. | 27
    Chrome DevTools Protocol

    View Slide

  28. Copyright © 2019, Oracle and/or its affiliates. All rights reserved. |
    GraalVM Components
    • Truffle
    – A toolkit for building language runtimes based on self-optimizing AST interpreters
    • Polyglot
    – All Truffle languages can share their AST nodes with one another
    • Cross-language development is a 1st class feature
    • Nodes from different languages can inline with each other, avoiding foreign language call overhead
    • Interop
    – The protocol (set of “messages”) languages can use to import foreign objects and
    read, write, or execute them
    28

    View Slide

  29. Copyright © 2019, Oracle and/or its affiliates. All rights reserved. |
    Message resolution
    29
    Uninitialized
    Dispatch
    js_array.size
    GET_SIZE
    JS get size
    Uninitialized
    Dispatch
    Uninitialized
    Dispatch
    • AST rewriting
    • The message is resolved to a tree
    supplied by a target language

    View Slide

  30. Copyright © 2019, Oracle and/or its affiliates. All rights reserved. |
    Debuggers for Free!
    • Through partial evaluation, Truffle gives you a compiler for free
    • Through language interop, Truffle gives you a debugger for free
    • Truffle is about more than just performance
    – It’s a toolkit for rapidly building complete language runtimes
    30

    View Slide

  31. Copyright © 2019, Oracle and/or its affiliates. All rights reserved. | 31
    Chrome DevTools Protocol

    View Slide

  32. Copyright © 2019, Oracle and/or its affiliates. All rights reserved. |
    GraalVM Polyglot Debugging Demo
    32

    View Slide

  33. Copyright © 2019, Oracle and/or its affiliates. All rights reserved. | 33

    View Slide

  34. Copyright © 2019, Oracle and/or its affiliates. All rights reserved. |
    Debugging Extensions Demo
    34

    View Slide

  35. Copyright © 2019, Oracle and/or its affiliates. All rights reserved. |
    Print Statement Debugging
    • A good first step in the debugging process
    – Fast & easy
    • Everyone knows how to do it regardless of programming proficiency
    • Drawbacks
    – Modifying code to narrow down the problem can be time-consuming
    – Editing code in gems may not be practical
    • E.g., do you have permissions to edit gems on a shared system?
    – Editing code in native extensions very impractical
    • Constantly recompiling to insert `printf` statements is not fun
    35

    View Slide

  36. Copyright © 2019, Oracle and/or its affiliates. All rights reserved. |
    Improving the Developer Experience
    • By implementing Ruby in Ruby, we can make debugging easier
    – Users can step from programs into and out of the VM
    • Seamless cross-language debugging makes polyglot programming a lot
    more practical
    • Being able to debug native extensions directly from Ruby is incredibly
    powerful
    36

    View Slide

  37. Copyright © 2019, Oracle and/or its affiliates. All rights reserved. |
    Summary
    • Debuggers benefit greatly from VM support, but VM-specific support is a
    large undertaking
    – At one extreme, Java’s JVMTI is very powerful, but overfits to Java bytecode
    – At the other end, Ruby delegates debugger support to 3rd party libraries
    • Chrome DevTools Protocol is an emerging standard for debugger
    implementations.
    – There are already multiple languages supported and multiple user interfaces adhering
    to the protocol
    • If all Ruby implementations standardize on the backend support, we can
    save developer time spent on frontends trying to support multiple
    implementations.
    37

    View Slide

  38. Copyright © 2019, Oracle and/or its affiliates. All rights reserved. |
    Team
    38
    Oracle
    Florian Angerer
    Danilo Ansaloni
    Stefan Anzinger
    Martin Balin
    Cosmin Basca
    Daniele Bonetta
    Dušan Bálek
    Matthias Brantner
    Lucas Braun
    Petr Chalupa
    Jürgen Christ
    Laurent Daynès
    Gilles Duboscq
    Svatopluk Dědic
    Martin Entlicher
    Tim Felgentreff
    Pit Fender
    Francois Farquet
    Brandon Fish
    Matthias Grimmer
    Christian Häubl
    Peter Hofer
    Bastian Hossbach
    Christian Humer
    Tomáš Hůrka
    Mick Jordan
    Oracle (continued)
    Vojin Jovanovic
    Anantha Kandukuri
    Harshad Kasture
    Cansu Kaynak
    Peter Kessler
    Duncan MacGregor
    Jiří Maršík
    Kevin Menard
    Miloslav Metelka
    Tomáš Myšík
    Petr Pišl
    Oleg Pliss
    Jakub Podlešák
    Aleksandar Prokopec
    Tom Rodriguez
    Roland Schatz
    Benjamin Schlegel
    Chris Seaton
    Jiří Sedláček
    Doug Simon
    Štěpán Šindelář
    Zbyněk Šlajchrt
    Boris Spasojevic
    Lukas Stadler
    Codrut Stancu
    JKU Linz
    Hanspeter Mössenböck
    Benoit Daloze
    Josef Eisl
    Thomas Feichtinger
    Josef Haider
    Christian Huber
    Jacob Kreindl
    David Leopoldseder
    Stefan Marr
    Thomas Pointhuber
    Manuel Rigger
    Stefan Rumzucker
    Bernhard Urban
    TU Berlin:
    Volker Markl
    Andreas Kunft
    Jens Meiners
    Tilmann Rabl
    University of Edinburgh
    Christophe Dubach
    Juan José Fumero Alfonso
    Ranjeet Singh
    Toomas Remmelg
    LaBRI
    Floréal Morandat
    University of California, Irvine
    Michael Franz
    Yeoul Na
    Mohaned Qunaibit
    Gulfem Savrun Yeniceri
    Wei Zhang
    Purdue University
    Jan Vitek
    Tomas Kalibera
    Petr Maj
    Lei Zhao
    T. U. Dortmund
    Peter Marwedel
    Helena Kotthaus
    Ingo Korb
    University of California, Davis
    Duncan Temple Lang
    Nicholas Ulle
    University of Lugano, Switzerland
    Walter Binder
    Sun Haiyang
    Oracle Interns
    Brian Belleville
    Ondrej Douda
    Juan Fumero
    Miguel Garcia
    Hugo Guiroux
    Shams Imam
    Berkin Ilbeyi
    Hugo Kapp
    Alexey Karyakin
    Stephen Kell
    Andreas Kunft
    Volker Lanting
    Gero Leinemann
    Julian Lettner
    Joe Nash
    Tristan Overney
    Aleksandar Pejovic
    David Piorkowski
    Philipp Riedmann
    Gregor Richards
    Robert Seilbeck
    Rifat Shariyar
    Oracle Alumni
    Erik Eckstein
    Michael Haupt
    Christos Kotselidis
    David Leibs
    Adam Welc
    Till Westmann
    Oracle (continued)
    Jan Štola
    Tomáš Stupka
    Farhan Tauheed
    Jaroslav Tulach
    Alexander Ulrich
    Michael Van De Vanter
    Aleksandar Vitorovic
    Christian Wimmer
    Christian Wirth
    Paul Wögerer
    Mario Wolczko
    Andreas Wöß
    Thomas Würthinger
    Tomáš Zezula
    Yudi Zheng
    Red Hat
    Andrew Dinn
    Andrew Haley
    Intel
    Michael Berg
    Twitter
    Chris Thalinger

    View Slide

  39. Copyright © 2019, Oracle and/or its affiliates. All rights reserved. | 39
    Run Programs Faster Anywhere
    Website
    http://www.graalvm.org/
    Github Repository
    https://github.com/oracle/truffleruby
    Stay Tuned
    [email protected]
    @TruffleRuby @GraalVM /graalvm

    View Slide