Skip to content
  • Aaron Patterson's avatar
    9edf9225
    Eliminate allocations on Model.respond_to? calls · 9edf9225
    Aaron Patterson authored
    
    
    We're trying to make instantiating models cheaper (for example doing
    `Post.new`), and discovered in the course of profiling that
    `respond_to?` is responsible for some amount of initialization
    allocations.
    
    This patch changes `Model.respond_to?` to not allocate anymore which
    should help initialization performance (as well as other queries).
    
    Here is the benchmark we used:
    
    ```ruby
    require "active_record"
    
    ActiveRecord::Base.establish_connection(adapter: "sqlite3", database: ":memory:")
    
    ActiveRecord::Schema.define do
      create_table :posts, force: true do |t|
        t.string :title, default: "hello"
        t.text :body, default: "i am a blog post"
        t.string :author, default: "aaron"
        t.boolean :published, default: true
        t.integer :likes, default: 1000000
      end
    end
    
    class Post < ActiveRecord::Base
    end
    
    5.times { Post.new }
    
    def m
      x = GC.stat(:total_allocated_objects)
      yield
      GC.stat(:total_allocated_objects) - x
    end
    
    allocs = m { 5000.times { Post.new } }
    p ALLOCATIONS_PER_MODEL: (allocs / 5000)
    
    allocs = m { 5000.times { Post.respond_to?(:default_scope) } }
    p ALLOCATIONS_PER_RESPOND_TO: (allocs / 5000)
    ```
    
    Before this patch:
    
    ```
    $ bundle exec ruby -Iactiverecord/lib:~/git/vernier/lib test.rb
    -- create_table(:posts, {force: true})
       -> 0.0045s
       {ALLOCATIONS_PER_MODEL: 9}
       {ALLOCATIONS_PER_RESPOND_TO: 2}
    ```
    
    After this patch:
    
    ```
    $ bundle exec ruby -Iactiverecord/lib:~/git/vernier/lib test.rb
    -- create_table(:posts, {force: true})
       -> 0.0045s
       {ALLOCATIONS_PER_MODEL: 7}
       {ALLOCATIONS_PER_RESPOND_TO: 0}
    ```
    
    Co-Authored-By: default avatarEileen M. Uchitelle <eileencodes@gmail.com>
    9edf9225
    Eliminate allocations on Model.respond_to? calls
    Aaron Patterson authored
    
    
    We're trying to make instantiating models cheaper (for example doing
    `Post.new`), and discovered in the course of profiling that
    `respond_to?` is responsible for some amount of initialization
    allocations.
    
    This patch changes `Model.respond_to?` to not allocate anymore which
    should help initialization performance (as well as other queries).
    
    Here is the benchmark we used:
    
    ```ruby
    require "active_record"
    
    ActiveRecord::Base.establish_connection(adapter: "sqlite3", database: ":memory:")
    
    ActiveRecord::Schema.define do
      create_table :posts, force: true do |t|
        t.string :title, default: "hello"
        t.text :body, default: "i am a blog post"
        t.string :author, default: "aaron"
        t.boolean :published, default: true
        t.integer :likes, default: 1000000
      end
    end
    
    class Post < ActiveRecord::Base
    end
    
    5.times { Post.new }
    
    def m
      x = GC.stat(:total_allocated_objects)
      yield
      GC.stat(:total_allocated_objects) - x
    end
    
    allocs = m { 5000.times { Post.new } }
    p ALLOCATIONS_PER_MODEL: (allocs / 5000)
    
    allocs = m { 5000.times { Post.respond_to?(:default_scope) } }
    p ALLOCATIONS_PER_RESPOND_TO: (allocs / 5000)
    ```
    
    Before this patch:
    
    ```
    $ bundle exec ruby -Iactiverecord/lib:~/git/vernier/lib test.rb
    -- create_table(:posts, {force: true})
       -> 0.0045s
       {ALLOCATIONS_PER_MODEL: 9}
       {ALLOCATIONS_PER_RESPOND_TO: 2}
    ```
    
    After this patch:
    
    ```
    $ bundle exec ruby -Iactiverecord/lib:~/git/vernier/lib test.rb
    -- create_table(:posts, {force: true})
       -> 0.0045s
       {ALLOCATIONS_PER_MODEL: 7}
       {ALLOCATIONS_PER_RESPOND_TO: 0}
    ```
    
    Co-Authored-By: default avatarEileen M. Uchitelle <eileencodes@gmail.com>
Loading