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

RailsConf 2016 Keynote

RailsConf 2016 Keynote

This is my keynote from RailsConf 2016.

Aaron Patterson

May 26, 2016
Tweet

More Decks by Aaron Patterson

Other Decks in Technology

Transcript

  1. How people build software
    !
    "
    Make Rails Great Again
    A @tenderlove Guide to Things

    View Slide

  2. How people build software
    !
    HELLO!!!!
    2
    !

    View Slide

  3. How people build software
    !
    Aaron Patterson
    3
    !

    View Slide

  4. How people build software
    !
    @tenderlove
    4
    !

    View Slide

  5. View Slide

  6. How people build software
    !
    Ruby Core Team
    Rails Core Team
    6
    !

    View Slide

  7. How people build software
    !
    Ruby Security Team
    Rails Security Team
    7
    !

    View Slide

  8. How people build software
    !
    PGP Fingerprint:
    4CE9 1B75 A798 28E8 6B1A
    A8BB 9531 70BC B4FF AFC6
    8
    !

    View Slide

  9. How people build software
    !
    #2 Committer
    9
    !

    View Slide

  10. View Slide

  11. How people build software
    !
    GitHub
    11
    !

    View Slide

  12. How people build software
    !
    Le Git
    12
    !

    View Slide

  13. How people build software
    !
    GitHug
    13
    !

    View Slide

  14. Plain old slides

    View Slide

  15. Sponsored Talk

    View Slide

  16. Brought to you by
    @ihavenotea

    View Slide

  17. View Slide

  18. View Slide

  19. View Slide

  20. View Slide

  21. I have stickers of my cats

    View Slide

  22. View Slide

  23. My Job at GitHub

    View Slide

  24. GitHub:
    How people build software

    View Slide

  25. Bringing GitHub
    Application Development to
    Everyone

    View Slide

  26. Rails Core Develompent

    View Slide

  27. Ruby Core Development

    View Slide

  28. Buy our products!

    View Slide

  29. My Career Goals

    View Slide

  30. I wanted to get rich.

    View Slide

  31. Why?

    View Slide

  32. So that I could do what I want.
    (Which is making Rails great again)

    View Slide

  33. Become a Cog

    View Slide

  34. I want to be a cog!

    View Slide

  35. New in Rails 5

    View Slide

  36. Rails is in it’s Prime
    5

    View Slide

  37. No more XML situps

    View Slide

  38. JSON burpees

    View Slide

  39. Threading

    View Slide

  40. Race Condition
    VROOOOM!!!!

    View Slide

  41. Le Mans is just Nascar for
    Europe
    Follow @ juliancheal today! (He gave me this joke)
    Advertisement:

    View Slide

  42. Ruby Drama

    View Slide

  43. I am extremely angry at Jeremy

    View Slide

  44. Friday, April 22, 2016
    7:57 pm

    View Slide

  45. View Slide

  46. JEREMY!!!

    View Slide

  47. 5

    View Slide

  48. 5

    View Slide

  49. $5

    View Slide

  50. $5 footlong

    View Slide

  51. WHAT EVEN IS THIS?

    View Slide

  52. Ruby on Rails
    The mainstream
    }The Surplus of Slides

    View Slide

  53. I ❤ u JD!

    View Slide

  54. Major Changes in ActiveRecord

    View Slide

  55. I want to talk about SQL

    View Slide

  56. So I’ve prepared a statement
    Follow @ kerrizor today! ❤
    Advertisement:

    View Slide

  57. ApplicationRecord

    View Slide

  58. Appealing to Startups

    View Slide

  59. Application Generation
    [[email protected] rails (master)]$ ruby railties/exe/rails new ~/git/omglolwut2 --dev --skip-bundle
    create
    create README.md
    create Rakefile
    create config.ru
    create .gitignore
    create Gemfile
    create app
    create app/assets/config/manifest.js
    create app/assets/javascripts/application.js
    create app/assets/javascripts/cable.js
    create app/assets/stylesheets/application.css
    create app/channels/application_cable/channel.rb
    create app/channels/application_cable/connection.rb
    create app/controllers/application_controller.rb
    create app/helpers/application_helper.rb
    create app/jobs/application_job.rb
    create app/mailers/application_mailer.rb
    create app/models/application_record.rb
    create app/models/business.rb
    create app/views/layouts/application.html.erb
    create app/views/layouts/mailer.html.erb
    create app/views/layouts/mailer.text.erb
    create app/assets/images/.keep
    create app/assets/javascripts/channels
    create app/assets/javascripts/channels/.keep
    create app/controllers/concerns/.keep
    create app/models/concerns/.keep
    create bin
    create bin/bundle
    create bin/rails
    create bin/rake
    create bin/setup
    create bin/update
    create config
    create config/routes.rb
    create config/application.rb
    create config/environment.rb
    create config/secrets.yml
    create config/cable.yml
    create config/puma.rb
    om
    glolwut2

    View Slide

  60. Application Generation
    create app/controllers/application_controller.rb
    create app/helpers/application_helper.rb
    create app/jobs/application_job.rb
    create app/mailers/application_mailer.rb
    create app/models/application_record.rb
    create app/models/business.rb
    create app/views/layouts/application.html.erb
    create app/views/layouts/mailer.html.erb

    View Slide

  61. Business Model
    [[email protected] rails (master)]$ cd ~/git/omglolwut2
    [[email protected] omglolwut2]$ cat app/models/business.rb
    class Business < ApplicationRecord
    # Business model
    end
    [[email protected] omglolwut2]$


    View Slide

  62. This is a HackerNews compliant
    business model

    View Slide

  63. Surprises!

    View Slide

  64. PHP templates

    View Slide

  65. View Slide

  66. 5

    View Slide

  67. View Slide

  68. We need to go further

    View Slide

  69. View Slide

  70. Lets get down to business

    View Slide

  71. What have you done for me
    lately?

    View Slide

  72. Yes, but what have you done for
    me *lately*?

    View Slide

  73. Performance

    View Slide

  74. SURPRISE!!!
    GitHub: You can put code there!
    Advertisement:

    View Slide

  75. I

    Performance

    View Slide

  76. Topics
    Boot Time Performance
    Run Time Performance
    Memory Efficiency

    View Slide

  77. Performance is always
    about tradeoffs

    View Slide

  78. Memory for speed

    View Slide

  79. Concurrency for memory

    View Slide

  80. Complexity for memory

    View Slide

  81. Performance is never free

    View Slide

  82. Always understand your
    constraints.

    View Slide

  83. Boot Time Performance
    leftpad-ng.js: for all your padding needs, but only on the left side
    Advertisement:

    View Slide

  84. bundle exec rails s
    RubyGems
    Bundler
    Rails
    Rails

    View Slide

  85. bundle exec rails s
    RubyGems
    Bundler
    Rails
    Rails

    View Slide

  86. Speeding up Ruby
    speeds up everything.

    View Slide

  87. But that doesn’t mean we
    should write slow code.

    View Slide

  88. Two Optimizations
    Ruby (sort of)
    RubyGems

    View Slide

  89. Run an empty program
    [[email protected] ~]$ ruby -v
    ruby 2.3.0p0 (2015-12-25 revision 53290) [x86_64-darwin15]
    [[email protected] ~]$ time ruby -e' '
    real 0m0.101s
    user 0m0.061s
    sys 0m0.032s
    OMG RUBY IS SLOW

    View Slide

  90. Without RubyGems
    [[email protected] ~]$ ruby -v
    ruby 2.3.0p0 (2015-12-25 revision 53290) [x86_64-darwin15]
    [[email protected] ~]$ time ruby -e' '
    real 0m0.101s
    user 0m0.061s
    sys 0m0.032s
    [[email protected] ~]$ time ruby --disable-gems -e' '
    real 0m0.051s
    user 0m0.022s
    sys 0m0.023s

    View Slide

  91. Measurement by Elimination

    View Slide

  92. Placing blame is difficult
    git blame: for all your blame placing needs
    Advertisement:

    View Slide

  93. gem_prelude.rb

    View Slide

  94. Gem Prelude
    if defined?(Gem)
    require 'rubygems.rb'
    begin
    require 'did_you_mean'
    rescue LoadError
    end if defined?(DidYouMean)
    end
    Load Rubygems

    View Slide

  95. Why load RubyGems?
    [[email protected] ~]$ ruby -e'require "rubygems"; require "rails"'
    [[email protected] ~]$ ruby -e'require "rails"'
    Bad
    old
    days
    of Ruby 1.8
    Ruby
    1.9+

    View Slide

  96. Gem Prelude
    if defined?(Gem)
    require 'rubygems.rb'
    begin
    require 'did_you_mean'
    rescue LoadError
    end if defined?(DidYouMean)
    end
    Load Rubygems
    did_you_mean
    New
    in Ruby
    2.3!

    View Slide

  97. Did you mean?
    [[email protected] ~]$ ruby -e'Object.new.object_ip'
    -e:1:in `': undefined method `object_ip' for #0x007fa7938b4fd8> (NoMethodError)
    Did you mean? object_id
    [[email protected] ~]$
    I see you’re
    trying to call a
    method!

    View Slide

  98. did_you_mean is a gem

    View Slide

  99. Gem Prelude
    if defined?(Gem)
    require 'rubygems.rb'
    begin
    require 'did_you_mean'
    rescue LoadError
    end if defined?(DidYouMean)
    end
    did_you_mean

    View Slide

  100. # RubyGems's require: TL;DR
    alias :original_require :require
    def require file
    original_require file
    rescue LoadError
    found_gem = all_gems.find do |gem|
    gem.contains?(file) ||
    gem.contains?(file + ".rb") ||
    gem.contains?(file + ".so") # .bundle on OS X, .dll on Windows
    end
    if found_gem
    found_gem.activate # mutates $LOAD_PATH
    original_require file
    else
    raise "idk lol"
    end
    end
    RubyGems’ Require
    O(3N)
    or just O(N)

    View Slide

  101. The more gems installed, the
    slower `require` gets

    View Slide

  102. The more gems installed, the
    slower `ruby` gets.

    View Slide

  103. Watch the O(N)
    $ sudo dtrace -q -n \
    'syscall::stat*:entry { printf("%s\n", copyinstr(arg0)); }' \
    -c`rbenv which ruby`" -e '\ '"

    View Slide

  104. Run it!
    [[email protected] ~]$ sudo dtrace -q -n 'syscall::stat*:entry
    { printf("%s\n", copyinstr(arg0)); }' -c`rbenv which ruby`" -e
    '\ '" | wc -l
    298
    [[email protected] ~]$ sudo dtrace -q -n 'syscall::stat*:entry
    { printf("%s\n", copyinstr(arg0)); }' -c`rbenv which ruby`" --
    disable-did_you_mean -e '\ '" | wc -l
    12
    [[email protected] ~]$ sudo dtrace -q -n 'syscall::stat*:entry
    { printf("%s\n", copyinstr(arg0)); }' -c`rbenv which ruby`" --
    disable-gems -e '\ '" | wc -l
    5
    [[email protected] ~]$
    With
    RubyGems
    Without
    did_you_mean
    Without Both

    View Slide

  105. File Stats
    actioncable-5.0.0.beta2/lib/did_you_mean
    actioncable-5.0.0.beta2/lib/did_you_mean.rb
    actioncable-5.0.0.beta2/lib/did_you_mean.bundle
    actionmailer-5.0.0.beta2/lib/did_you_mean
    actionmailer-5.0.0.beta2/lib/did_you_mean.rb
    actionmailer-5.0.0.beta2/lib/did_you_mean.bundle
    actionpack-5.0.0.beta2/lib/did_you_mean
    actionpack-5.0.0.beta2/lib/did_you_mean.rb
    actionpack-5.0.0.beta2/lib/did_you_mean.bundle
    actionview-5.0.0.beta2/lib/did_you_mean
    actionview-5.0.0.beta2/lib/did_you_mean.rb
    actionview-5.0.0.beta2/lib/did_you_mean.bundle
    activejob-5.0.0.beta2/lib/did_you_mean
    activejob-5.0.0.beta2/lib/did_you_mean.rb
    activejob-5.0.0.beta2/lib/did_you_mean.bundle

    View Slide

  106. File Stats
    actioncable-5.0.0.beta2/lib/did_you_mean
    actioncable-5.0.0.beta2/lib/did_you_mean.rb
    actioncable-5.0.0.beta2/lib/did_you_mean.bundle
    actionmailer-5.0.0.beta2/lib/did_you_mean
    actionmailer-5.0.0.beta2/lib/did_you_mean.rb
    actionmailer-5.0.0.beta2/lib/did_you_mean.bundle
    actionpack-5.0.0.beta2/lib/did_you_mean
    actionpack-5.0.0.beta2/lib/did_you_mean.rb
    actionpack-5.0.0.beta2/lib/did_you_mean.bundle
    actionview-5.0.0.beta2/lib/did_you_mean
    actionview-5.0.0.beta2/lib/did_you_mean.rb
    actionview-5.0.0.beta2/lib/did_you_mean.bundle
    activejob-5.0.0.beta2/lib/did_you_mean
    activejob-5.0.0.beta2/lib/did_you_mean.rb
    activejob-5.0.0.beta2/lib/did_you_mean.bundle
    Why stat file with no
    extension?

    View Slide

  107. GOOD
    NEWS
    EVERYONE

    View Slide

  108. "d" is pretty early in the
    alphabet!

    View Slide

  109. To speed up Rails, let us
    rename it to AAARails

    View Slide

  110. Improvement

    View Slide

  111. Use `gem`
    $ cat test.rb
    require "did_you_mean"
    $ sudo sh count_syscalls.sh | wc -l
    299
    $ cat test.rb
    gem "did_you_mean"
    require "did_you_mean"
    $ sudo sh count_syscalls.sh | wc -l
    16
    Bare `require`
    `gem` + `require`

    View Slide

  112. Why this is faster:
    def gem gem_name
    spec = load_specfile(gem_name + ".gemspec")
    spec.activate # mutates the load path
    end
    # RubyGems's require: TL;DR
    alias :original_require :require
    def require file
    original_require file
    rescue LoadError
    found_gem = all_gems.find do |gem|
    gem.contains?(file) ||
    gem.contains?(file + ".rb") ||
    gem.contains?(file + ".so") # .dylib on OS X, .dll on Windows
    end
    if found_gem
    found_gem.activate # mutates $LOAD_PATH
    original_require file
    else
    raise "idk lol"
    end
    end
    O(1)
    O(1)*
    *Not actually O(1)

    View Slide

  113. Fix gem_prelude.rb
    diff --git a/gem_prelude.rb b/gem_prelude.rb
    index 3f171d1..be9c419 100644
    --- a/gem_prelude.rb
    +++ b/gem_prelude.rb
    @@ -1,7 +1,8 @@
    if defined?(Gem)
    require 'rubygems.rb'
    begin
    + gem 'did_you_mean'
    require 'did_you_mean'
    - rescue LoadError
    + rescue Gem::LoadError, LoadError
    end if defined?(DidYouMean)
    end

    View Slide

  114. Bare Require: O(N)
    Gem + Require: O(1)

    View Slide

  115. Tradeoffs:
    Complexity for Speed

    View Slide

  116. Complexity does have overhead

    View Slide

  117. bundle exec rails s
    RubyGems
    Bundler
    Rails
    Rails
    Probably want the
    bundler gem

    View Slide

  118. `bundle` before RG 2.5.2
    [[email protected] ~]$ tail -3 `rbenv which bundler`
    gem 'bundler', version
    load Gem.bin_path('bundler', 'bundler', version)
    [[email protected] ~]$
    O(1)

    View Slide

  119. RG >= 2.5.2, < 2.6.2
    [[email protected] ~]$ tail -3 `rbenv which bundler`
    end
    load Gem.bin_path('bundler', 'bundler', version)
    [[email protected] ~]$
    (N)

    View Slide

  120. bundle exec rails s
    RubyGems
    Bundler
    Rails
    Rails

    View Slide

  121. New Technology!!!!*
    *Not actually new

    View Slide

  122. Startup Time
    12%
    13%
    34%
    41% Compilation
    Execution
    Searching
    GC
    These
    Are
    Not
    Actual
    Times

    View Slide

  123. How does GC impact?
    require 'benchmark/ips'
    # GC.disable # Uncomment to measure GC
    Benchmark.ips do |x|
    x.report("something") do
    call_some_method
    end
    end

    View Slide

  124. Startup Time
    12%
    13%
    34%
    41% Compilation
    Execution
    Searching
    GC
    These
    Are
    Not
    Actual
    Times

    View Slide

  125. https://github.com/byroot/
    bootscale
    This link brought to you by GitHub dot com
    Advertisement:

    View Slide

  126. Startup Time
    13%
    39%
    47%
    Compilation
    Execution
    GC
    These
    Are
    Not
    Actual
    Times

    View Slide

  127. Startup Time
    46%
    54%
    Compilation
    Execution
    These
    Are
    Not
    Actual
    Times

    View Slide

  128. Lets tackle compilation!

    View Slide

  129. Go to @_ko1’s talk

    View Slide

  130. that was yesterday…

    View Slide

  131. Program Flow
    Source Code
    Byte Code
    Execution
    Cache this!

    View Slide

  132. Program Flow
    Source Code
    Byte Code
    Execution
    Read Byte Code
    from File
    Byte Code
    Execution

    View Slide

  133. Compilation Script
    input_file = ARGV[0]
    output_file = input_file + "c"
    insns = RubyVM::InstructionSequence.compile_file input_file
    File.binwrite output_file, insns.to_binary
    New
    in
    Ruby 2.3!

    View Slide

  134. Compilation Example
    $ cat hello.rb
    class Hello
    def hello!
    puts "hello"
    end
    end
    $ ruby compile.rb hello.rb
    $ cat hello.rbc
    YARB?
    LX?x86_64-darwin15*0*3
    +3DD*???????**0*3
    $t|????????||T?
    Ehello!EhelloEHelloEputsEcore#define_methodx????8Qj?

    View Slide

  135. 1st half is done

    View Slide

  136. Load & Execute Byte Code
    compiled_file = ARGV[0]
    binary_data = File.binread compiled_file
    insns = RubyVM::InstructionSequence.load_from_binary binary_data
    insns.eval
    Hello.new.hello!
    New
    in
    Ruby 2.3!

    View Slide

  137. Run it
    $ ruby load_compiled_file.rb hello.rbc
    hello

    View Slide

  138. 2nd half is done

    View Slide

  139. 100% done, but Rails isn’t faster

    View Slide

  140. I always give 110%

    View Slide

  141. Integrating with `require`

    View Slide

  142. Require Process
    # a.rb
    require 'b'
    # b.rb
    require 'c'
    # c.rb
    require 'b'

    View Slide

  143. Dependencies
    a.rb
    b.rb
    c.rb

    View Slide

  144. Require Process
    Start to require 'b' Acquire lock for "b"
    Start to require 'c' Acquire lock for "c"
    Try to require 'b' Already locked for "b"
    Finish require 'c'
    Finish require 'b'
    Release lock for "c"
    Release lock for "b"

    View Slide

  145. There are many rules, and I
    don’t want to figure them out.

    View Slide

  146. Load File Hook
    set_load_required_file_func ->(full_file) {
    if can_handle?(full_file)
    # do something
    true
    else
    # do something else
    false
    end
    }
    require 'foo' I want foo.rb!
    /path/to/foo.rb

    View Slide

  147. https://github.com/tenderlove/
    ruby/tree/binload
    ADVERTISING!!


    View Slide

  148. Load Compiled Code
    if ENV['COMP']
    set_load_required_file_func ->(full_path) {
    fname = full_path + "o"
    if File.exist? fname
    insns = RubyVM::InstructionSequence.load_from_binary File.binread fname
    insns.eval
    true
    else
    insns = RubyVM::InstructionSequence.compile_file full_path
    File.binwrite fname, insns.to_binary
    false
    end
    }
    end
    https://gist.github.com/tenderlove/f6f4189db2eb748802b21a8b4fd52c99

    View Slide

  149. Compiled vs Non-Compiled
    [[email protected] omglolwut (master)]$ time RUBYOPT='-I. -rx' bin/rails db:migrate
    real 0m1.804s
    user 0m1.487s
    sys 0m0.414s
    [[email protected] omglolwut (master)]$ time COMP=1 RUBYOPT='-I. -rx' bin/rails db:migrate
    real 0m1.273s
    user 0m1.002s
    sys 0m0.374s
    Before (not compiled)
    After (compiled)

    View Slide

  150. ~30% faster
    Try mechanical keyboards today!
    Advertisement:

    View Slide

  151. The more code,
    the bigger the impact.

    View Slide

  152. Future Work
    Upstream new callback
    Compile code on `gem install`
    Cache invalidation
    If you like "cache invalidation", try "naming things"!
    Advertisement:

    View Slide

  153. Runtime Performance

    View Slide

  154. Polymorphic Inline Caching

    View Slide

  155. Inline Caching
    class Hello
    def bar; end
    end
    def foo(object)
    object.bar
    end
    foo Hello.new
    foo Hello.new
    `object` is Hello, where
    is foo?
    `object` is Hello, I know
    where foo is. HIT!
    Cache Contents
    Key Value
    [Hello, foo] method source

    View Slide

  156. Inline Caching
    class Hello
    def bar; end
    end
    class World
    def bar; end
    end
    def foo(object)
    object.bar
    end
    foo Hello.new
    foo World.new
    `object` is Hello, where
    is foo? MISS
    `object` is World, where
    is foo? MISS
    Cache Contents
    Key Value
    [Hello, foo] method source

    View Slide

  157. Cache size: 1

    View Slide

  158. Monomorphic Inline Cache

    View Slide

  159. Cache size: 2
    class Hello
    def bar; end
    end
    class World
    def bar; end
    end
    def foo(object)
    object.bar
    end
    foo Hello.new
    foo World.new
    foo Hello.new
    foo World.new
    `object` is Hello, where
    is foo? MISS
    `object` is World, where
    is foo? MISS
    `object` is Hello, I know
    foo. HIT
    `object` is World, I know
    foo. HIT
    Cache Contents
    Key Value
    [Hello, foo] method source
    [World, foo] method source

    View Slide

  160. Cache size 2 (or more)

    View Slide

  161. Polymorphic Inline Cachine

    View Slide

  162. Pays off when many call sites
    "see" many types.

    View Slide

  163. Implemented here:
    https://github.com/tenderlove/ruby/tree/PIC_expand

    View Slide

  164. TL;DR: Didn’t help

    View Slide

  165. ~3% of calls saw 2 types
    Test App: https://github.com/manageiq/manageiq
    Current
    Company
    Previous
    Company

    View Slide

  166. Tradeoff:
    Complexity / Memory For Speed

    View Slide

  167. Call site with 1600 types

    View Slide

  168. Class Creation Code
    class Hello
    end
    def foo(object)
    object.bar
    end
    2.times {
    hello = Hello.new
    hello.instance_eval do
    end
    }
    Creates a new subclass
    of Hello
    Always sees an
    anonymous class

    View Slide

  169. What class is this?
    class Hello
    end
    var = Hello.new
    Ancestors
    BasicObject
    Kernel
    Object
    Hello
    #

    View Slide

  170. Singleton Uses
    • instance_eval
    • singleton_class
    • def my_obj.some_method; end

    View Slide

  171. Given "I’m a Rails Dev"
    When "Presented with this info"
    Then "Why should I care?"
    Brought to you by rspec-given. It’s a Given!
    Advertisement:

    View Slide

  172. Some libraries do this

    View Slide

  173. Don’t write code like that

    View Slide

  174. If you think you have to

    View Slide

  175. Just don’t.
    This slide brought to you by singleton classes
    Advertisement:

    View Slide

  176. If you really really really must
    Brought to you by eigenclasses
    Advertisement:

    View Slide

  177. We can speed it up.

    View Slide

  178. Singleton classes with no new
    methods are
    equal to the superclass
    Your ad here! Contact @tenderlove for details
    Advertisement:

    View Slide

  179. Patch to Copy
    $ git diff trunk class.c
    diff --git a/class.c b/class.c
    index 0261838..65428be 100644
    --- a/class.c
    +++ b/class.c
    @@ -1591,7 +1591,9 @@ singleton_class_of(VALUE obj)
    klass = RBASIC(obj)->klass;
    if (!(FL_TEST(klass, FL_SINGLETON) &&
    rb_ivar_get(klass, id_attached) == obj)) {
    + rb_serial_t serial = RCLASS_SERIAL(klass);
    klass = rb_make_metaclass(obj, klass);
    + RCLASS_SERIAL(klass) = serial;
    }
    if (OBJ_TAINTED(obj)) {
    https://github.com/tenderlove/ruby/tree/singleton-serial

    View Slide

  180. Benchmark
    class C1
    def m; 1; end
    end
    o1 = C1.new
    o2 = C1.new
    o2.singleton_class
    i = 0
    while i<6_000_000 # benchmark loop 2
    o = (i % 2 == 0) ? o1 : o2
    o.m; o.m; o.m; o.m; o.m; o.m; o.m; o.m
    i += 1
    end

    View Slide

  181. Run it!
    [[email protected] ruby (trunk)]$ time ./ruby benchmark/
    bm_vm2_poly_singleton.rb
    real 0m2.510s
    user 0m2.453s
    sys 0m0.024s
    [[email protected] ruby (singleton-serial)]$ time ./ruby benchmark/
    bm_vm2_poly_singleton.rb
    real 0m1.380s
    user 0m1.319s
    sys 0m0.020s

    View Slide

  182. 45% faster!

    View Slide

  183. Trade off:
    Complexity for Speed

    View Slide

  184. Memory Efficiency

    View Slide

  185. Copy on Write
    (a.k.a. CoW)
    Milk! It’s what’s for dinner
    Advertisement:

    View Slide

  186. Heap Layout Optimizations

    View Slide

  187. Copy on Write
    Parent
    Process
    Child
    Process
    Child
    Process
    Memory

    View Slide

  188. Copy on Write
    Parent
    Process
    Child
    Process
    Child
    Process
    Memory
    Memory

    View Slide

  189. "Page Fault"

    View Slide

  190. OS copies some of the memory

    View Slide

  191. Ruby Memory Layout
    Pages
    Object
    Object
    Object
    Object
    Object
    Object
    Object
    Object
    Object
    Object
    Object
    Object

    View Slide

  192. GC Happens
    Pages
    Object
    Object
    Object
    Object
    Object
    Object
    Object
    Object
    Object
    Object
    FREE!
    FREE!
    FREE!
    FREE!
    Object
    Object

    View Slide

  193. Objects Don’t Move

    View Slide

  194. Swiss Cheese Memory
    Pages
    Object
    FREE!
    FREE!
    Object
    FREE!
    FREE!
    Object
    Object
    Object
    Object
    Object
    Object

    View Slide

  195. CoW wastefulness
    Pages
    Object
    FREE!
    FREE!
    Object
    FREE!
    FREE!
    Object
    Object
    Object
    Object
    Object
    Object
    Object
    Parent
    Child
    Copied to Child

    View Slide

  196. OS Page Size 4k
    Ruby Page Size 16k
    Ruby Object Size 40 bytes

    View Slide

  197. 1 Ruby Page: ~400 Objects

    View Slide

  198. 1 Ruby Page: 4 OS Pages

    View Slide

  199. 1 OS Page: ~100 Ruby Objects

    View Slide

  200. We’re probably copying too
    many objects.
    Try JRuby: it’s Ruby with a J
    Advertisement:

    View Slide

  201. This only impacts Ruby code
    that forks.

    View Slide

  202. Unicorn
    Ugh. This is the web server we use.

    View Slide

  203. Sideways Ruby Page

    View Slide

  204. Sideways Ruby Page
    Imaginary Ruby Page (Slab)

    View Slide

  205. Pages dedicated to
    "probably old" objects

    View Slide

  206. What are "probably old" objects?

    View Slide

  207. Probably old
    class Foo
    end
    module Bar
    end
    BAZ = "OMGOMG!!"

    View Slide

  208. Tradeoffs?

    View Slide

  209. Complexity for memory?

    View Slide

  210. How complex?

    View Slide

  211. How much memory?

    View Slide

  212. Tools for introspection

    View Slide

  213. github.com/tenderlove/heapfrag
    Sponsored link:

    View Slide

  214. View Slide

  215. Wrap it up!!

    View Slide

  216. 5 lessons

    View Slide

  217. What do I value?
    What should I
    measure
    How can I measure it
    Does it provide
    shareholder value?

    View Slide

  218. 5

    View Slide

  219. 1. What do I value?

    View Slide

  220. 2. What should I measure?

    View Slide

  221. 3. How can I measure it?

    View Slide

  222. 4. Does it provide shareholder
    value?
    ActionCable: it’s a thing!!
    Advertisement:

    View Slide

  223. Make Rails Great Again!

    View Slide

  224. View Slide