Skip to content

Instantly share code, notes, and snippets.

@dvandersluis
Last active November 23, 2018 16:29
Show Gist options
  • Save dvandersluis/1fcb26ae809115ef9dfc48fe07b70f18 to your computer and use it in GitHub Desktop.
Save dvandersluis/1fcb26ae809115ef9dfc48fe07b70f18 to your computer and use it in GitHub Desktop.
Rails attribute lookup
require 'benchmark/ips'
user = User.last
Benchmark.ips do |x|
x.report('.attr') { user.name }
x.report('[attr]') { user.[]('name') }
# What rails calls for user['name']
x.report('read_attr/missing') { user.read_attribute('name') { |n| missing_attribute(n, caller) } }
# Drilling down into read_attribute without missing_attribute
x.report('read_attribute') { user.read_attribute('name') }
x.report('attribute_set[].value') { user.instance_variable_get(:@attributes)['name'].value }
# We wouldn't want to do this because type casting is important, but just for curiousity as to how much time
# type casting takes
x.report('attribute_set[].value_before_type_cast') { user.instance_variable_get(:@attributes)['name'].value_before_type_cast }
x.compare!
end
## Method trace with sources:
user[:name]
# https://github.com/rails/rails/blob/master/activerecord/lib/active_record/attribute_methods.rb#L372-L374
user.read_attribute(:name) { |n| missing_attribute(n, caller) }
# https://github.com/rails/rails/blob/master/activerecord/lib/active_record/attribute_methods/read.rb#L31-L41
user._read_attribute(:name, &block)
# https://github.com/rails/rails/blob/master/activerecord/lib/active_record/attribute_methods/read.rb#L45-L55
user.@attributes.fetch_value('name') { |n| yield n if block_given? }
# https://github.com/rails/rails/blob/master/activemodel/lib/active_model/attribute_set.rb#L40-L50
attribute_set['name']
# https://github.com/rails/rails/blob/master/activemodel/lib/active_model/attribute_set.rb#L15-L17
...value
# https://github.com/rails/rails/blob/master/activemodel/lib/active_model/attribute.rb#L40-L44
Warming up --------------------------------------
.attr 148.416k i/100ms
[attr] 54.464k i/100ms
read_attr/missing 64.984k i/100ms
read_attribute 101.857k i/100ms
attribute_set[].value
171.315k i/100ms
attribute_set[].value_before_type_cast
181.550k i/100ms
Calculating -------------------------------------
.attr 2.802M (± 2.1%) i/s - 14.100M in 5.034267s
[attr] 837.030k (± 4.9%) i/s - 4.194M in 5.021677s
read_attr/missing 856.952k (± 4.4%) i/s - 4.289M in 5.013995s
read_attribute 1.426M (± 2.9%) i/s - 7.130M in 5.002834s
attribute_set[].value
2.927M (± 3.6%) i/s - 14.733M in 5.040511s
attribute_set[].value_before_type_cast
3.350M (± 3.5%) i/s - 16.884M in 5.047108s
Comparison:
attribute_set[].value_before_type_cast: 3349508.8 i/s
attribute_set[].value: 2926736.1 i/s - 1.14x slower
.attr: 2802032.7 i/s - 1.20x slower
read_attribute: 1426429.5 i/s - 2.35x slower
read_attr/missing: 856952.2 i/s - 3.91x slower
[attr]: 837030.3 i/s - 4.00x slower
Benchmark.ips do |x|
x.report('read_attribute') { user.read_attribute(:name) }
x.report('_read_attribute') { user._read_attribute(:name) }
x.compare!
end
# Warming up --------------------------------------
# read_attribute 79.511k i/100ms
# _read_attribute 136.627k i/100ms
# Calculating -------------------------------------
# read_attribute 1.207M (± 4.4%) i/s - 6.043M in 5.017097s
# _read_attribute 2.355M (± 4.8%) i/s - 11.750M in 5.001814s
# Comparison:
# _read_attribute: 2354831.7 i/s
# read_attribute: 1206808.2 i/s - 1.95x slower
module ActiveRecord
module AttributeMethods
alias_method :old_lookup, :[]
def [](attr_name)
public_send(attr_name)
end
end
end
Benchmark.ips do |x|
x.report('old') { tag.old_lookup(:name) }
x.report('new') { tag[:name] }
x.report('method') { tag.name }
x.compare!
end
# Warming up --------------------------------------
# old 59.763k i/100ms
# new 125.890k i/100ms
# method 149.602k i/100ms
# Calculating -------------------------------------
# old 719.833k (± 4.6%) i/s - 3.646M in 5.075733s
# new 2.029M (± 1.9%) i/s - 10.197M in 5.028319s
# method 2.341M (± 9.9%) i/s - 11.669M in 5.042085s
# Comparison:
# method: 2340888.5 i/s
# new: 2028720.4 i/s - 1.15x slower
# old: 719832.8 i/s - 3.25x slower
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment