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 ! PGP Fingerprint: 4CE9 1B75 A798

    28E8 6B1A A8BB 9531 70BC B4FF AFC6 8 !
  2. So that I could do what I want. (Which is

    making Rails great again)
  3. Le Mans is just Nascar for Europe Follow @ juliancheal

    today! (He gave me this joke) Advertisement:
  4. 5

  5. 5

  6. $5

  7. Application Generation [aaron@TC 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
  8. 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
  9. Business Model [aaron@TC rails (master)]$ cd ~/git/omglolwut2 [aaron@TC omglolwut2]$ cat

    app/models/business.rb class Business < ApplicationRecord # Business model end [aaron@TC omglolwut2]$
  10. 5

  11. Run an empty program [aaron@TC ~]$ ruby -v ruby 2.3.0p0

    (2015-12-25 revision 53290) [x86_64-darwin15] [aaron@TC ~]$ time ruby -e' ' real 0m0.101s user 0m0.061s sys 0m0.032s OMG RUBY IS SLOW
  12. Without RubyGems [aaron@TC ~]$ ruby -v ruby 2.3.0p0 (2015-12-25 revision

    53290) [x86_64-darwin15] [aaron@TC ~]$ time ruby -e' ' real 0m0.101s user 0m0.061s sys 0m0.032s [aaron@TC ~]$ time ruby --disable-gems -e' ' real 0m0.051s user 0m0.022s sys 0m0.023s
  13. Gem Prelude if defined?(Gem) require 'rubygems.rb' begin require 'did_you_mean' rescue

    LoadError end if defined?(DidYouMean) end Load Rubygems
  14. Why load RubyGems? [aaron@TC ~]$ ruby -e'require "rubygems"; require "rails"'

    [aaron@TC ~]$ ruby -e'require "rails"' Bad old days of Ruby 1.8 Ruby 1.9+
  15. 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!
  16. Did you mean? [aaron@TC ~]$ ruby -e'Object.new.object_ip' -e:1:in `<main>': undefined

    method `object_ip' for #<Object: 0x007fa7938b4fd8> (NoMethodError) Did you mean? object_id [aaron@TC ~]$ I see you’re trying to call a method!
  17. # 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)
  18. Watch the O(N) $ sudo dtrace -q -n \ 'syscall::stat*:entry

    { printf("%s\n", copyinstr(arg0)); }' \ -c`rbenv which ruby`" -e '\ '"
  19. Run it! [aaron@TC ~]$ sudo dtrace -q -n 'syscall::stat*:entry {

    printf("%s\n", copyinstr(arg0)); }' -c`rbenv which ruby`" -e '\ '" | wc -l 298 [aaron@TC ~]$ sudo dtrace -q -n 'syscall::stat*:entry { printf("%s\n", copyinstr(arg0)); }' -c`rbenv which ruby`" -- disable-did_you_mean -e '\ '" | wc -l 12 [aaron@TC ~]$ sudo dtrace -q -n 'syscall::stat*:entry { printf("%s\n", copyinstr(arg0)); }' -c`rbenv which ruby`" -- disable-gems -e '\ '" | wc -l 5 [aaron@TC ~]$ With RubyGems Without did_you_mean Without Both
  20. 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
  21. 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?
  22. 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`
  23. 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)
  24. 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
  25. `bundle` before RG 2.5.2 [aaron@TC ~]$ tail -3 `rbenv which

    bundler` gem 'bundler', version load Gem.bin_path('bundler', 'bundler', version) [aaron@TC ~]$ O(1)
  26. RG >= 2.5.2, < 2.6.2 [aaron@TC ~]$ tail -3 `rbenv

    which bundler` end load Gem.bin_path('bundler', 'bundler', version) [aaron@TC ~]$ (N)
  27. 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
  28. 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!
  29. 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? <class:Hello>Ehello!EhelloEHelloEputsEcore#define_methodx????8Qj?
  30. 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!
  31. 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"
  32. 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
  33. 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
  34. Compiled vs Non-Compiled [aaron@TC omglolwut (master)]$ time RUBYOPT='-I. -rx' bin/rails

    db:migrate real 0m1.804s user 0m1.487s sys 0m0.414s [aaron@TC 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)
  35. Future Work Upstream new callback Compile code on `gem install`

    Cache invalidation If you like "cache invalidation", try "naming things"! Advertisement:
  36. 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
  37. 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
  38. 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
  39. 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
  40. What class is this? class Hello end var = Hello.new

    Ancestors BasicObject Kernel Object Hello #<Class blah>
  41. 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:
  42. Singleton classes with no new methods are equal to the

    superclass Your ad here! Contact @tenderlove for details Advertisement:
  43. 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
  44. 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
  45. Run it! [aaron@TC ruby (trunk)]$ time ./ruby benchmark/ bm_vm2_poly_singleton.rb real

    0m2.510s user 0m2.453s sys 0m0.024s [aaron@TC ruby (singleton-serial)]$ time ./ruby benchmark/ bm_vm2_poly_singleton.rb real 0m1.380s user 0m1.319s sys 0m0.020s
  46. Ruby Memory Layout Pages Object Object Object Object Object Object

    Object Object Object Object Object Object
  47. GC Happens Pages Object Object Object Object Object Object Object

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

    Object Object Object Object Object Object
  49. CoW wastefulness Pages Object FREE! FREE! Object FREE! FREE! Object

    Object Object Object Object Object Object Parent Child Copied to Child
  50. What do I value? What should I measure How can

    I measure it Does it provide shareholder value?
  51. 5