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. 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
  2. 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
  3. 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 `<main>' 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)
  4. 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
  5. Copyright © 2019, Oracle and/or its affiliates. All rights reserved.

    | 6 "Bad endpoint: " Traceback (most recent call last): 2: from demo.rb:18:in `<main>' 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)
  6. 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
  7. 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 `<main>' 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)
  8. 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 `<main>' 1: from demo.rb:9:in `process' demo.rb:9:in `>=': comparison of String with 400 failed (ArgumentError)
  9. 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
  10. Copyright © 2019, Oracle and/or its affiliates. All rights reserved.

    | 11 #<Net::HTTPMovedPermanently 301 Moved Permanently readbody=true> Traceback (most recent call last): 2: from demo.rb:21:in `<main>' 1: from demo.rb:12:in `process' demo.rb:12:in `>=': comparison of String with 400 failed (ArgumentError)
  11. 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
  12. Copyright © 2019, Oracle and/or its affiliates. All rights reserved.

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

    | – Taken from https://code.visualstudio.com on 15 April, 2019 17
  17. 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
  18. 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
  19. Copyright © 2019, Oracle and/or its affiliates. All rights reserved.

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

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

    | 23 Chrome DevTools Protocol Chromium-based Browser
  22. 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
  23. 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
  24. 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
  25. 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
  26. 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
  27. 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
  28. 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
  29. 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