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

Why JRuby (Works)

headius
November 01, 2012

Why JRuby (Works)

Talk on Why JRuby and why the JVM makes JRuby compelling delivered at RubyConf 2012 in Denver, Colorado by Charles Oliver Nutter and Thomas Enebo.

headius

November 01, 2012
Tweet

More Decks by headius

Other Decks in Technology

Transcript

  1. JRuby is Ruby! 1.8.7 & 1.9.3 compatibility drop-in replacement *

    * see next slide Monday, November 12, 12
  2. *caveats • Weak but improving low-level UNIX stuff • No

    C extension support • Not maintained...off by default in 1.7 • Some features differ or unavailable • ObjectSpace, trace funcs, callcc, fork... Monday, November 12, 12
  3. Announcing JRuby 1.7.0 • Ruby 1.9.3 compat (--1.8 for 1.8.7)

    • Java 7 invokedynamic support • Much awesomeness over 1.6.x Monday, November 12, 12
  4. Getting Started 1. Install a JVM 2. rvm install jruby

    3. Profit! % jruby -e ‘puts “wowee”’ Monday, November 12, 12
  5. JRuby Team Charlie Tom Nick Hiro Marcin Nahi Wayne Subbu

    Douglas Douglas Contribs Douglas Douglas OpenJDK Douglas Douglas Android Douglas Douglas Other JVMs Douglas Monday, November 12, 12
  6. We get it for Free! JVM J. Rose Garbage Collection

    Native JIT Profiled Optimizations Native Threading Tooling Cross Platform Monday, November 12, 12
  7. Profile: John Rose • JVM Engineer since 1997 • Invented

    C* Language • JSR 292 lead Monday, November 12, 12
  8. 0 7.5 15 22.5 30 Java 1.4 Java 5 Java

    6 Java 7 Go Java Go! JRuby 1.0.3 (bm_red_black_tree.rb) 300% for free Monday, November 12, 12
  9. 0 7.5 15 22.5 30 Java 1.4 Java 5 Java

    6 Java 7 Go Java Go! JRuby 1.0.3 (bm_red_black_tree.rb) MRI 1.8 300% for free Monday, November 12, 12
  10. JVM is everywhere • Unix++, Windows • Exotic platforms: zLinux,

    OpenVMS, AS/400 • Mobile: Android’s Dalvik, Embedded JVMs Monday, November 12, 12
  11. actionmailer-javamail, active_documentum, activerecord-jdbc-adapter, activerecord-jdbcdbf-adapter, activerecord-jdbcderby-adapter, activerecord-jdbch2- adapter, activerecord-jdbchsqldb-adapter, activerecord-jdbcmssql-adapter, activerecord-jdbcmysql-adapter,

    activerecord-jdbcpostgresql-adapter, activerecord- jdbcsqlite3-adapter, activerecord-netezza-adapter, activerecord-vertica-adapter, akephalos, akephalos-nerian, akephalos2, akka-actor-jars, akka-remote-jars, akubra_llstore_migrate, Antwrap, async-http-client-jars, atomic, atoulme-Antwrap, autotest-java, bbrowning-deltacloud-client, bbrowning-deltacloud-core, bcrypt-ruby, bee_java, berkeley-db-java-jars, bert, bio-maf, blockenspiel, boc, bond, bosdk, bouncy-castle-java, boxed-geminabox, brute-fuzzy, bryanl-gherkin, bson, buby, buildr, buildr-resolver, buildrizpack, butternut, capistrano-java, capybara-java_script_lint, carrierwave-neo4j, carrierwave_imagevoodoo, cassandra- jars, chrest, cloby, commons-io-jars, concurrently, contextual, coupler, cucumber-java, cucumber-jvm, cuke4duke, cuuid, dm-ldap-adapter, dm-lucene-adapter, do-jdbc_sqlserver, do_derby, do_h2, do_hsqldb, do_jdbc, do_mysql, do_openedge, do_oracle, do_postgres, do_sqlite3, do_sqlserver, doubleshot, dripdrop, dubious, duby, engineyard-visualvm, epall-limelight, errbit_zmq_handler, eurydice, euston, euston-daemons, euston-eventstore, euston-projections, euston- rabbitmq, euston-websites, eventmachine, excemel, faye-websocket, ffi, fig, file-find, fishwife, foreman, forkit, forkjoin, gamelan, gemshit, geoip-jars, get_back, gherkin, glassfish, gravitext-util, gravitext-xmlprod, grizzly, guava-jars, hadoop-find, hashdot-test-daemon, hiredis, hitimes, hope, hostor, hot_bunnies, hourglass, hpricot, http_parser.rb, inline_javascript, iudex, iudex-async-httpclient, iudex-barc, iudex-brutefuzzy-protobuf, iudex-brutefuzzy-service, iudex-char-detector, iudex-core, iudex-da, iudex-filter, iudex-html, iudex-http, iudex-http-test, iudex-httpclient-3, iudex-jetty-httpclient, iudex-rome, iudex-simhash, iudex-worker, ivy-jars, iyyov, jactive_support, java-autotest, java-inline, java2ruby-xmldsig, java_bin, java_inline, java_override, java_properties, java_streamify, java_testing_guff, javabean_xml, javaclass, javaeye4r, javagems, javajake, javaobj, javaobjs, javaobs, javaparse, javasand, javascript-securehash-rails, javascript-state- machine-rails, javascript_auto_include, javascript_eraser, javascript_features, javascript_i18n, javascript_localize, javascript_safe_logger, javascript_util_asset_pack, javascripto, javascripto-rails, jdbc-derby, jdbc-hsqldb, jdbc-jtds, jdbc-openedge, jdbc-openedge-internal, jdbc-postgres, jdbc-sqlite3, jedis-jars, jena-jruby, jessica, jettr, jetty, jetty-jsp, jgeoip, jms4r, jpdfer, jrack_handlers, jrtm, jruby-activemq, jruby-akka_jars, jruby-elasticsearch_jars, jruby- httpclient, jruby-launcher, jruby-management, jruby-metrics, jruby-pageant, jruby-vijava, jruby_gc_stats, jruby_sandbox, jruby_threach, jrubyconf-button, jsmetric4java, json, json-jruby, jsound, kb-activerecord-jdbc-adapter, kirk, kyotocabinet-java, ladle, latex-decode, launchy, libnotify, limelight, linecache, logback, logback-jars, looksee, lumix, mack-javascript, markdownj, maven_irb_plugin, metrics-core-jars, metrics-java, mguymon-buildr, mikka, mini_aether, mirah, mirah_model, miso-java, mixology, mm_mq, mongrel, msgpack-idl-java, msgpack-jruby, multimeter, naether, nanoc-javascript-concatenator, neo4j, neo4j-admin, neo4j-advanced, neo4j-community, neo4j-core, neo4j-enterprise, neo4j-spatial, neo4j-will_paginate, neo4j-wrapper, netty-jars, ning-compress-jars, nio4r, nokogiri, nokogiri-fitzsimmons, nokogiri-maven, nosqoop4u, ontomde-demo-java5, ontomde-java, ontomde-java-frontend, ontomde-uml2-java, ontomde-uml2- kbjava, open_nlp, pacer, pacer-dex, pacer-neo4j, pacer-orient, pelops-jars, persvr, pg_array_parser, protobuf-jars, pry, puma, qtjruby-core, qwirk_active_mq_adapter, qwirk_jms_adapter, rabbitmqadmin-cli, ragweed, rails_javascript_helpers, rakejava, rave, rcov, realityforge-jekyll, realityforge- jekylltask, redcar-bundles, redcar-clojure, redcar-filter-through-command, redcar-groovy, redcar-icons, redcar-javamateview, redcar-javascript, redcar-mirah, redcar-svnkit, redcar-xulrunner-win, RedCloth, refinerycms-javascripts, reigns, revo-nokogiri, rika, rjack-async-httpclient, rjack-commons-codec, rjack- commons-dbcp, rjack-commons-dbutils, rjack-commons-pool, rjack-httpclient-3, rjack-httpclient-4, rjack-icu, rjack-jackson, rjack-jdom, rjack-jets3t, rjack-jetty, rjack-jetty-jsp, rjack-jms, rjack-jms-spec, rjack-logback, rjack-lucene, rjack-maven, rjack-mina, rjack-nekohtml, rjack-protobuf, rjack-qpid-client, rjack-rome, rjack-slf4j, rjack-solr, rjack-tarpit, rjack-xerces, rmagick4j, rmodbus, rtm-javatmapi, rtm-majortom, rtm-ontopia, rtm-tinytim, rtm-tmql, rubeus, rubinius-core- api, ruby-blockcache, ruby-debug-base, ruby-maven, ruby2java, rubydoop, rubyjedi-nokogiri_java, scala-inline, scala-library-jars, scriptty, slf4j, slf4j-jars, slyphon- zookeeper, slyphon-zookeeper_jar, smackr, smartimage, SNMP4JR, solr_sail, spiegela-jruby-httpclient, sproutcore, spymemcached, sqldroid, steamcannon- deltacloud-client, steamcannon-deltacloud-core, stilts-stomp-client, supermarket, svm_toolkit, swt, theduke, thick, to-javascript, torquebox-base, torquebox- cache, torquebox-configure, torquebox-container-foundation, torquebox-core, torquebox-messaging, torquebox-messaging-container, torquebox-naming, torquebox-naming-container, torquebox-security, torquebox-server, torquebox-vfs, torquebox-web, twitter4j4r, UDJrb, unageanu-javaclass, unimidi, universe- javascript, url_escape, weakling, webbit-jars, wildnet-jackson, wildnet-netty, wildnet-server, wildsonet-hazelcast, wildsonet-netty, wildsonet-server, wildsonet- streamer, wrest, wrong, xdojava, xqruby, zookeeper Monday, November 12, 12
  12. actionmailer-javamail, active_documentum, activerecord-jdbc-adapter, activerecord-jdbcdbf-adapter, activerecord-jdbcderby-adapter, activerecord-jdbch2- adapter, activerecord-jdbchsqldb-adapter, activerecord-jdbcmssql-adapter, activerecord-jdbcmysql-adapter,

    activerecord-jdbcpostgresql-adapter, activerecord- jdbcsqlite3-adapter, activerecord-netezza-adapter, activerecord-vertica-adapter, akephalos, akephalos-nerian, akephalos2, akka-actor-jars, akka-remote-jars, akubra_llstore_migrate, Antwrap, async-http-client-jars, atomic, atoulme-Antwrap, autotest-java, bbrowning-deltacloud-client, bbrowning-deltacloud-core, bcrypt-ruby, bee_java, berkeley-db-java-jars, bert, bio-maf, blockenspiel, boc, bond, bosdk, bouncy-castle-java, boxed-geminabox, brute-fuzzy, bryanl-gherkin, bson, buby, buildr, buildr-resolver, buildrizpack, butternut, capistrano-java, capybara-java_script_lint, carrierwave-neo4j, carrierwave_imagevoodoo, cassandra- jars, chrest, cloby, commons-io-jars, concurrently, contextual, coupler, cucumber-java, cucumber-jvm, cuke4duke, cuuid, dm-ldap-adapter, dm-lucene-adapter, do-jdbc_sqlserver, do_derby, do_h2, do_hsqldb, do_jdbc, do_mysql, do_openedge, do_oracle, do_postgres, do_sqlite3, do_sqlserver, doubleshot, dripdrop, dubious, duby, engineyard-visualvm, epall-limelight, errbit_zmq_handler, eurydice, euston, euston-daemons, euston-eventstore, euston-projections, euston- rabbitmq, euston-websites, eventmachine, excemel, faye-websocket, ffi, fig, file-find, fishwife, foreman, forkit, forkjoin, gamelan, gemshit, geoip-jars, get_back, gherkin, glassfish, gravitext-util, gravitext-xmlprod, grizzly, guava-jars, hadoop-find, hashdot-test-daemon, hiredis, hitimes, hope, hostor, hot_bunnies, hourglass, hpricot, http_parser.rb, inline_javascript, iudex, iudex-async-httpclient, iudex-barc, iudex-brutefuzzy-protobuf, iudex-brutefuzzy-service, iudex-char-detector, iudex-core, iudex-da, iudex-filter, iudex-html, iudex-http, iudex-http-test, iudex-httpclient-3, iudex-jetty-httpclient, iudex-rome, iudex-simhash, iudex-worker, ivy-jars, iyyov, jactive_support, java-autotest, java-inline, java2ruby-xmldsig, java_bin, java_inline, java_override, java_properties, java_streamify, java_testing_guff, javabean_xml, javaclass, javaeye4r, javagems, javajake, javaobj, javaobjs, javaobs, javaparse, javasand, javascript-securehash-rails, javascript-state- machine-rails, javascript_auto_include, javascript_eraser, javascript_features, javascript_i18n, javascript_localize, javascript_safe_logger, javascript_util_asset_pack, javascripto, javascripto-rails, jdbc-derby, jdbc-hsqldb, jdbc-jtds, jdbc-openedge, jdbc-openedge-internal, jdbc-postgres, jdbc-sqlite3, jedis-jars, jena-jruby, jessica, jettr, jetty, jetty-jsp, jgeoip, jms4r, jpdfer, jrack_handlers, jrtm, jruby-activemq, jruby-akka_jars, jruby-elasticsearch_jars, jruby- httpclient, jruby-launcher, jruby-management, jruby-metrics, jruby-pageant, jruby-vijava, jruby_gc_stats, jruby_sandbox, jruby_threach, jrubyconf-button, jsmetric4java, json, json-jruby, jsound, kb-activerecord-jdbc-adapter, kirk, kyotocabinet-java, ladle, latex-decode, launchy, libnotify, limelight, linecache, logback, logback-jars, looksee, lumix, mack-javascript, markdownj, maven_irb_plugin, metrics-core-jars, metrics-java, mguymon-buildr, mikka, mini_aether, mirah, mirah_model, miso-java, mixology, mm_mq, mongrel, msgpack-idl-java, msgpack-jruby, multimeter, naether, nanoc-javascript-concatenator, neo4j, neo4j-admin, neo4j-advanced, neo4j-community, neo4j-core, neo4j-enterprise, neo4j-spatial, neo4j-will_paginate, neo4j-wrapper, netty-jars, ning-compress-jars, nio4r, nokogiri, nokogiri-fitzsimmons, nokogiri-maven, nosqoop4u, ontomde-demo-java5, ontomde-java, ontomde-java-frontend, ontomde-uml2-java, ontomde-uml2- kbjava, open_nlp, pacer, pacer-dex, pacer-neo4j, pacer-orient, pelops-jars, persvr, pg_array_parser, protobuf-jars, pry, puma, qtjruby-core, qwirk_active_mq_adapter, qwirk_jms_adapter, rabbitmqadmin-cli, ragweed, rails_javascript_helpers, rakejava, rave, rcov, realityforge-jekyll, realityforge- jekylltask, redcar-bundles, redcar-clojure, redcar-filter-through-command, redcar-groovy, redcar-icons, redcar-javamateview, redcar-javascript, redcar-mirah, redcar-svnkit, redcar-xulrunner-win, RedCloth, refinerycms-javascripts, reigns, revo-nokogiri, rika, rjack-async-httpclient, rjack-commons-codec, rjack- commons-dbcp, rjack-commons-dbutils, rjack-commons-pool, rjack-httpclient-3, rjack-httpclient-4, rjack-icu, rjack-jackson, rjack-jdom, rjack-jets3t, rjack-jetty, rjack-jetty-jsp, rjack-jms, rjack-jms-spec, rjack-logback, rjack-lucene, rjack-maven, rjack-mina, rjack-nekohtml, rjack-protobuf, rjack-qpid-client, rjack-rome, rjack-slf4j, rjack-solr, rjack-tarpit, rjack-xerces, rmagick4j, rmodbus, rtm-javatmapi, rtm-majortom, rtm-ontopia, rtm-tinytim, rtm-tmql, rubeus, rubinius-core- api, ruby-blockcache, ruby-debug-base, ruby-maven, ruby2java, rubydoop, rubyjedi-nokogiri_java, scala-inline, scala-library-jars, scriptty, slf4j, slf4j-jars, slyphon- zookeeper, slyphon-zookeeper_jar, smackr, smartimage, SNMP4JR, solr_sail, spiegela-jruby-httpclient, sproutcore, spymemcached, sqldroid, steamcannon- deltacloud-client, steamcannon-deltacloud-core, stilts-stomp-client, supermarket, svm_toolkit, swt, theduke, thick, to-javascript, torquebox-base, torquebox- cache, torquebox-configure, torquebox-container-foundation, torquebox-core, torquebox-messaging, torquebox-messaging-container, torquebox-naming, torquebox-naming-container, torquebox-security, torquebox-server, torquebox-vfs, torquebox-web, twitter4j4r, UDJrb, unageanu-javaclass, unimidi, universe- javascript, url_escape, weakling, webbit-jars, wildnet-jackson, wildnet-netty, wildnet-server, wildsonet-hazelcast, wildsonet-netty, wildsonet-server, wildsonet- streamer, wrest, wrong, xdojava, xqruby, zookeeper No build tools! Monday, November 12, 12
  13. Polyglot • Use right tool for the right job •

    Running in the same VM • Another dimension of libraries Monday, November 12, 12
  14. GC Matters • Applications grow over time • Ruby is

    very object-heavy • Multiprocess multiplies the problem • You will eventually have issues Monday, November 12, 12
  15. JVM GC • Wide array of options • Many GCs

    to choose from • Scales up to massive heaps • Best GCs in the world! Monday, November 12, 12
  16. OpenJDK GCs • Parallel: multi-core stop-the-world • Concurrent: STW young,

    concurrent old • G1: concurrent young and old • Serial: single-thread STW Monday, November 12, 12
  17. Object Homogeneity • Everything expressed as JVM objects • Everything

    shares the same infrastructure • Including extensions, libraries, etc • One GC to rule them all • And one standard memory model Monday, November 12, 12
  18. gc_demo.rb • Heavy GC, mix of old and young •

    Steadily growing heap use Monday, November 12, 12
  19. class Simple attr_accessor :next end top = Simple.new puts Benchmark.measure

    { outer = 10 total = 100000 per = 100 outer.times do total.times do per.times { Simple.new } s = Simple.new top.next = s top = s end end } Monday, November 12, 12
  20. 0 3.75 7.5 11.25 15 GC time % Ruby 1.9.3

    JRuby Monday, November 12, 12
  21. 0ms 75ms 150ms 225ms 300ms 188KB/29MB 27MB/127MB 199MB/238MB Time per

    GC versus heap usage Time per GC Heap usage (MRI/JRuby) Ruby 2.0.0 JRuby Monday, November 12, 12
  22. :-) :-| :-/ :-( :-( 188KB/29MB 27MB/127MB 199MB/238MB Time per

    GC versus heap usage User Unhappiness Heap usage (MRI/JRuby) Ruby 2.0.0 JRuby Monday, November 12, 12
  23. 0 1,000 2,000 3,000 4,000 0M 1,250M 2,500M 3,750M 5,000M

    Time Per GC (ms) Heap Size Ruby 2.0.0 Monday, November 12, 12
  24. Findings • Lower, more uniform GC times • Reduced or

    eliminated pauses • Very large heaps are no problem • Predictable, consistent experience Monday, November 12, 12
  25. Real Parallellism • Ruby thread = JVM thread = native

    thread • One process can use all cores • One server can handle all requests Monday, November 12, 12
  26. require 'benchmark' ary = (1..1000000).to_a loop { puts Benchmark.measure {

    10.times { ary.each {|i|} } } } Monday, November 12, 12
  27. require 'benchmark' ary = (1..1000000).to_a loop { puts Benchmark.measure {

    (1..10).map { Thread.new { ary.each {|i|} } }.map(&:join) } } Monday, November 12, 12
  28. 0.2s 0.35s 0.5s 0.65s 0.8s one thread two threads three

    threads four threads Per-iteration time versus thread count threaded_reverse Monday, November 12, 12
  29. Nonlinear? • More work means more objects • Allocation/GC needs

    memory bandwidth • No different from multi-process Monday, November 12, 12
  30. Profiling • Java profilers • VisualVM, YourKit, NetBeans, JXInsight •

    jruby [--profile | --profile.graph] • jruby -Xreify.classes=true • JVM command-line profilers Monday, November 12, 12
  31. Monitoring • Java Management Extensions (JMX) • Gems available for

    clients and servers • jconsole and VisualVM • Most servers provide additional tools • New Relic, etc have JVM support Monday, November 12, 12
  32. VisualVM • CPU, memory, thread monitoring • CPU and memory

    profiling • VisualGC • Heap analysis Monday, November 12, 12
  33. @minute_hand = Path.new.tap do |mh| mh.setFill(Color::BLACK) mh.getElements.add MoveTo.new(4, -4) mh.getElements.add

    ArcTo.new(-1, -1, 0, -4, -4, false, false) mh.getElements.add LineTo.new(0, -radius) mh.getTransforms.add Rotate.new end class Refresher include EventHandler def handle(event); event.source.refresh; end end Timeline.new.tap do |time| time.setCycleCount Timeline::INDEFINITE time.getKeyFrames.add(Keyframe.new(Duration.millis(1000)), Refresher.new) time.play end Draw minute hand Implement Java Event handler refresh timeline every 1s Monday, November 12, 12
  34. getFooBar -> fooBar @minute_hand = Path.new.tap do |mh| mh.setFill(Color::BLACK) mh.elements.add

    MoveTo.new(4, -4) mh.elements.add ArcTo.new(-1, -1, 0, -4, -4, false, false) mh.elements.add LineTo.new(0, -radius) mh.transforms.add Rotate.new end class Refresher include EventHandler def handle(event); event.source.refresh; end end Timeline.new.tap do |time| time.setCycleCount Timeline::INDEFINITE time.keyFrames.add(Keyframe.new(Duration.millis(1000)), Refresher.new) time.play end was getElements was getTransforms was getKeyFrames Monday, November 12, 12
  35. setFoo(a) -> foo = a @minute_hand = Path.new.tap do |mh|

    mh.fill = Color::BLACK mh.elements.add MoveTo.new(4, -4) mh.elements.add ArcTo.new(-1, -1, 0, -4, -4, false, false) mh.elements.add LineTo.new(0, -radius) mh.transforms.add Rotate.new end class Refresher include EventHandler def handle(event); event.source.refresh; end end Timeline.new.tap do |time| time.cycleCount = Timeline::INDEFINITE time.keyFrames.add(Keyframe.new(Duration.millis(1000)), Refresher.new) time.play end was setFill was setCycleCount Monday, November 12, 12
  36. camelCase -> camel_case @minute_hand = Path.new.tap do |mh| mh.fill =

    Color::BLACK mh.elements.add MoveTo.new(4, -4) mh.elements.add ArcTo.new(-1, -1, 0, -4, -4, false, false) mh.elements.add LineTo.new(0, -radius) mh.transforms.add Rotate.new end class Refresher include EventHandler def handle(event); event.source.refresh; end end Timeline.new.tap do |time| time.cycle_count = Timeline::INDEFINITE time.key_frames.add(Keyframe.new(Duration.millis(1000)), Refresher.new) time.play end was cycleCount was keyFrames Monday, November 12, 12
  37. Procs as interfaces @minute_hand = Path.new.tap do |mh| mh.fill =

    Color::BLACK mh.elements.add MoveTo.new(4, -4) mh.elements.add ArcTo.new(-1, -1, 0, -4, -4, false, false) mh.elements.add LineTo.new(0, -radius) mh.transforms.add Rotate.new end Timeline.new.tap do |time| time.cycle_count = Timeline::INDEFINITE time.key_frames.add Keyframe.new(Duration.millis(1000)) {refresh} time.play end No more extra class Monday, November 12, 12
  38. Common Adornments @minute_hand = Path.new.tap do |mh| mh.fill = Color::BLACK

    mh.elements << MoveTo.new(4, -4) mh.elements << ArcTo.new(-1, -1, 0, -4, -4, false, false) mh.elements << LineTo.new(0, -radius) mh.transforms << Rotate.new end Timeline.new.tap do |time| time.cycle_count = Timeline::INDEFINITE time.key_frames << Keyframe.new(Duration.millis(1000)) {refresh} time.play end ‘add’ becomes ‘<<‘ Monday, November 12, 12
  39. Purugin • Minecraft scripting in JRuby • Clean and simple

    DSL • Purogo: LOGO for Minecraft Monday, November 12, 12
  40. turtle("four-sided triangle") do |*args| dim = (args[0] || 5).to_i block_type

    = (args[1] || :stone).to_sym layer do 4.times do |i| forward dim turnleft 90 end end pivot do block :none forward 1 turnleft 90 forward 1 turnup 90 forward 1 turndown 90 turnright 90 block block_type end block block_type (1...dim).step(2).to_a.reverse.each do |i| dim = i layer pivot end end Monday, November 12, 12
  41. “Look, nobody enjoys shooting penguins, but if you have to

    shoot penguins, well, you might as well enjoy it.” - Free Waterfall Sr. Native Extensions Suck Monday, November 12, 12
  42. Flowchart of Shame Can I write it in Ruby? Does

    it need to be n times faster? Can I use FFI? Native Extension yes no no no Script Java? no Monday, November 12, 12
  43. Java Native Extensions • Written in Java • Have same

    performance as Java • Use same GC as JRuby • First Class Citizens Monday, November 12, 12
  44. 0 7.5 15 22.5 30 Java 1.4 Java 5 Java

    6 Java 7 Go Java Go! JRuby 1.0.3 (bm_red_black_tree.rb) 300% for free Monday, November 12, 12
  45. 0 2 4 6 8 1.0.3 1.1.6 1.4.0 1.5.6 1.6.8

    1.7.0 OpenJDK 8 (bm_red_black_tree.rb) Go JRuby Go! Monday, November 12, 12
  46. 0 2.25 4.5 6.75 9 1.0.3 1.1.6 1.4.0 1.5.6 1.6.8

    1.7.0 OpenJDK 8 (bm_red_black_tree.rb) Severe perf bottleneck(s) Severe gains??? Monday, November 12, 12
  47. 1.0.3 & red_black_tree [GC (Allocation Failure) 223608K->96408K(330752K), 0.0159780 secs] [GC

    (Allocation Failure) 208920K->100792K(335168K), 0.0157550 secs] [GC (Allocation Failure) 213304K->105144K(332160K), 0.0181010 secs] [GC (Allocation Failure) 205112K->108920K(334400K), 0.0187580 secs] [GC (Allocation Failure) 208888K->112712K(329152K), 0.0154440 secs] 8.1s -J-verbose:gc [GC (Allocation Failure) 313780K->199892K(339072K), 0.0142010 secs] [GC (Allocation Failure) 318420K->204420K(331520K), 0.0175690 secs] [GC (Allocation Failure) 306948K->208316K(335680K), 0.0188120 secs] [Full GC (Ergonomics) 208316K->54991K(352256K), 0.2709750 secs] [GC (Allocation Failure) 157519K->58959K(349248K), 0.0120840 secs] 8.4s Moar Objects! +28 more +28 more +28 more +28 more Monday, November 12, 12
  48. 1.7.0 & red_black_tree +28 more [GC (Allocation Failure) 155729K->39697K(207296K), 0.0072730

    secs] 0.963s [GC (Allocation Failure) 160785K->40657K(208320K), 0.0108620 secs] 0.968s [GC (Allocation Failure) 161745K->41649K(210112K), 0.0083760 secs] 0.968s [GC (Allocation Failure) 166193K->39729K(210688K), 0.0070670 secs] 0.99s -J-verbose:gc Monday, November 12, 12
  49. 0 0.75 1.5 2.25 3 1.1.6 1.4.0 1.5.6 1.6.8 1.7.0

    OpenJDK 8 (bm_red_black_tree.rb) Monday, November 12, 12
  50. 0 0.75 1.5 2.25 3 1.1.6 1.4.0 1.5.6 1.6.8 1.7.0

    OpenJDK 8 (bm_red_black_tree.rb) JVM Feature! Monday, November 12, 12
  51. Performance • JRuby compiles Ruby to JVM bytecode • JVM

    compiles bytecode to native • Best JIT technology in the world • Getting even better with invokedynamic Monday, November 12, 12
  52. How to Optimize Ruby • Do less work • Reduce

    dispatch and call overhead • Reduce memory overhead • Find static patterns • Profile running code • Emit optimized version with guards Monday, November 12, 12
  53. JVM Optimizations • Profiling • Watch code, optimize hottest paths

    • Inlining • Combine code, optimize as a whole • Escape analysis • Eliminate transient objects Monday, November 12, 12
  54. def foo; Object.new; end def invoker; foo; end i =

    0 while i < 10000 invoker i+=1 end Monday, November 12, 12
  55. def invoker; Object.new; end i = 0 while i <

    10000 invoker i+=1 end Inline foo into invoker Monday, November 12, 12
  56. i = 0 while i < 10000 Object.new i+=1 end

    Inline invoker into loop Monday, November 12, 12
  57. i = 0 while i < 10000 i+=1 end Object

    is transient Monday, November 12, 12
  58. InvokeDynamic • Java 7+ feature • Allows us to teach

    JVM about Ruby • Dynamic calls can inline • Constants become truly constant • JVM’s best optimizations can work Monday, November 12, 12
  59. def foo; 1; end def invoker; foo; end N.times do

    i = 0 while i < 10000 invoker i+=1 end end Monday, November 12, 12
  60. $ jruby -J-XX:+UnlockDiagnosticVMOptions \ -J-XX:+PrintInlining \ -J-XX:+PrintCompilation \ script.rb 79

    1 b java.lang.String::hashCode (55 bytes) 109 2 b java.util.Properties$LineReader::readLine (452 bytes) @ 48 java.io.Reader::read (9 bytes) never executed @ 62 java.io.FilterInputStream::read (9 bytes) @ 303 java.lang.System::arraycopy (0 bytes) (intrinsic) @ 388 java.io.Reader::read (9 bytes) never executed .... Monday, November 12, 12
  61. 3321 190 b ruby.__dash_e__::block_0$RUBY$__file__ (83 bytes) @ 6 org.jruby.RubyFixnum::op_lt (22

    bytes) inline (hot) @ 66 org.jruby.RubyBasicObject::isTrue (15 bytes) inline (hot) @ 6 ruby.__dash_e__::method__1$RUBY$invoker (9 bytes) inline (hot) @ 6 ruby.__dash_e__::method__0$RUBY$foo (7 bytes) inline (hot) @ 5 org.jruby.RubyFixnum::op_plus_one (31 bytes) inline (hot) def foo; 1; end def invoker; foo; end N.times do i = 0 while i < 10000 invoker i+=1 end end Monday, November 12, 12
  62. 3321 190 b ruby.__dash_e__::block_0$RUBY$__file__ (83 bytes) @ 6 org.jruby.RubyFixnum::op_lt (22

    bytes) inline (hot) @ 66 org.jruby.RubyBasicObject::isTrue (15 bytes) inline (hot) @ 6 ruby.__dash_e__::method__1$RUBY$invoker (9 bytes) inline (hot) @ 6 ruby.__dash_e__::method__0$RUBY$foo (7 bytes) inline (hot) @ 5 org.jruby.RubyFixnum::op_plus_one (31 bytes) inline (hot) def foo; 1; end def invoker; foo; end N.times do i = 0 while i < 10000 invoker i+=1 end end Monday, November 12, 12
  63. 3321 190 b ruby.__dash_e__::block_0$RUBY$__file__ (83 bytes) @ 6 org.jruby.RubyFixnum::op_lt (22

    bytes) inline (hot) @ 66 org.jruby.RubyBasicObject::isTrue (15 bytes) inline (hot) @ 6 ruby.__dash_e__::method__1$RUBY$invoker (9 bytes) inline (hot) @ 6 ruby.__dash_e__::method__0$RUBY$foo (7 bytes) inline (hot) @ 5 org.jruby.RubyFixnum::op_plus_one (31 bytes) inline (hot) def foo; 1; end def invoker; foo; end N.times do i = 0 while i < 10000 invoker i+=1 end end Monday, November 12, 12
  64. 3321 190 b ruby.__dash_e__::block_0$RUBY$__file__ (83 bytes) @ 6 org.jruby.RubyFixnum::op_lt (22

    bytes) inline (hot) @ 66 org.jruby.RubyBasicObject::isTrue (15 bytes) inline (hot) @ 6 ruby.__dash_e__::method__1$RUBY$invoker (9 bytes) inline (hot) @ 6 ruby.__dash_e__::method__0$RUBY$foo (7 bytes) inline (hot) @ 5 org.jruby.RubyFixnum::op_plus_one (31 bytes) inline (hot) def foo; 1; end def invoker; foo; end N.times do i = 0 while i < 10000 invoker i+=1 end end Monday, November 12, 12
  65. 3321 190 b ruby.__dash_e__::block_0$RUBY$__file__ (83 bytes) @ 6 org.jruby.RubyFixnum::op_lt (22

    bytes) inline (hot) @ 66 org.jruby.RubyBasicObject::isTrue (15 bytes) inline (hot) @ 6 ruby.__dash_e__::method__1$RUBY$invoker (9 bytes) inline (hot) @ 6 ruby.__dash_e__::method__0$RUBY$foo (7 bytes) inline (hot) @ 5 org.jruby.RubyFixnum::op_plus_one (31 bytes) inline (hot) def foo; 1; end def invoker; foo; end N.times do i = 0 while i < 10000 invoker i+=1 end end Monday, November 12, 12
  66. 3321 190 b ruby.__dash_e__::block_0$RUBY$__file__ (83 bytes) @ 6 org.jruby.RubyFixnum::op_lt (22

    bytes) inline (hot) @ 66 org.jruby.RubyBasicObject::isTrue (15 bytes) inline (hot) @ 6 ruby.__dash_e__::method__1$RUBY$invoker (9 bytes) inline (hot) @ 6 ruby.__dash_e__::method__0$RUBY$foo (7 bytes) inline (hot) @ 5 org.jruby.RubyFixnum::op_plus_one (31 bytes) inline (hot) def foo; 1; end def invoker; foo; end N.times do i = 0 while i < 10000 invoker i+=1 end end Monday, November 12, 12
  67. 3321 190 b ruby.__dash_e__::block_0$RUBY$__file__ (83 bytes) @ 6 org.jruby.RubyFixnum::op_lt (22

    bytes) inline (hot) @ 66 org.jruby.RubyBasicObject::isTrue (15 bytes) inline (hot) @ 6 ruby.__dash_e__::method__1$RUBY$invoker (9 bytes) inline (hot) @ 6 ruby.__dash_e__::method__0$RUBY$foo (7 bytes) inline (hot) @ 5 org.jruby.RubyFixnum::op_plus_one (31 bytes) inline (hot) def foo; 1; end def invoker; foo; end N.times do i = 0 while i < 10000 invoker i+=1 end end Monday, November 12, 12
  68. 3321 190 b ruby.__dash_e__::block_0$RUBY$__file__ (83 bytes) @ 6 org.jruby.RubyFixnum::op_lt (22

    bytes) inline (hot) @ 66 org.jruby.RubyBasicObject::isTrue (15 bytes) inline (hot) @ 6 ruby.__dash_e__::method__1$RUBY$invoker (9 bytes) inline (hot) @ 6 ruby.__dash_e__::method__0$RUBY$foo (7 bytes) inline (hot) @ 5 org.jruby.RubyFixnum::op_plus_one (31 bytes) inline (hot) def foo; 1; end def invoker; foo; end N.times do i = 0 while i < 10000 invoker i+=1 end end Monday, November 12, 12
  69. base64 richards neural mandelbrot redblack 0 1.25 2.5 3.75 5

    Times Faster than Ruby 1.9.3 JRuby/Java 6 JRuby/Java 7 Monday, November 12, 12
  70. base64 richards neural mandelbrot redblack 0 1.25 2.5 3.75 5

    1.346 1.538 1.914 1.806 1.565 Times Faster than Ruby 1.9.3 JRuby/Java 6 JRuby/Java 7 Monday, November 12, 12
  71. base64 richards neural mandelbrot redblack 0 1.25 2.5 3.75 5

    1.346 1.538 1.914 1.806 1.565 2.658 3.44 3.66 4.226 4.32 Times Faster than Ruby 1.9.3 JRuby/Java 6 JRuby/Java 7 Monday, November 12, 12
  72. smooth_sort # Original Author: Keith Schwarz ([email protected]) # # Translated

    to Ruby by Chuck Remes (chuckremes on github) # # An implementation of Dijkstra's Smoothsort algorithm, a modification of # heapsort that runs in O(n lg n) in the worst case, but O(n) if the data # are already sorted. For more information about how this algorithm works # and some of the details necessary for its proper operation, please see # # http://www.keithschwarz.com/smoothsort/ Monday, November 12, 12
  73. 0 25000 50000 75000 100000 Iterations per second 19590.7 11439

    4750 Ruby 1.8.7 Ruby 1.9.3 Ruby 2.0.0 JRuby Monday, November 12, 12
  74. Your Turn • Try your apps on JRuby and tell

    us • Turn on JRuby in @travisci • Let us know what you think of JRuby • Help us make JRuby even better! • JRuby BOF in Room C at 6:30PM Monday, November 12, 12