Date post: | 15-May-2015 |
Category: |
Technology |
Upload: | toster |
View: | 1,001 times |
Download: | 1 times |
Attributes Unwrapped
@jonleighton
I lied to you
Measure
Measure
Refactor
Measure
Refactor
Optimise
LET’S DO SCIENCE
gem 'rails', '3.2.0'
require 'active_record'
ActiveRecord::Base
.establish_connection(
:adapter => 'sqlite3',
:database => ':memory:')
ActiveRecord::Schema.define do
create_table :posts do |t|
t.string :title
end
end
class Post < ActiveRecord::Base
end
p = Post.create(:title => "lol")
require 'benchmark'
n = 1_000_000
Benchmark.report(20) do |r|
r.report('attribute') do
n.times { p.title }
end
r.report('read_attribute') do
n.times { p[:title] }
end
end
attribute
read_attribute
1.09 s
2.87 s
gem install
benchmark_suite
require 'benchmark/ips'
Benchmark.ips do |r|
r.report('attribute') do
p.title
end
r.report('read_attribute') do
p[:title]
end
end
attribute
read_attribute
828,648
299,856
Ruby 1.9
Ruby 1.8
Ruby 1.8
oops!
define_method
method compilation
create_table :roflcopters do |t|
t.string " ROFL:ROFL:ROFL:ROFL"
t.string " _^____ "
t.string " L __/ []\ "
t.string "LOL===_ \ "
t.string " L \_________] "
t.string " I I "
t.string " --------/ "
end
if compilable?
class_eval <<-STR
def #{attr_name}
...
end
STR
else
define_method attr_name do
...
end
end
attr_name
=~
/\A[a-zA-Z_]\w*[!?=]?\z/
:title
=~
/\A[a-zA-Z_]\w*[!?=]?\z/
:title =~ /.../
# => true
Ruby 1.9
Ruby 1.8
:title =~ /.../
# => false
def __temp__
...
end
alias "@#>" :__temp__
undef_method :__temp__
def __temp__
...
end
alias "@#>" :__temp__
undef_method :__temp__
DON'T USE THIS
API Changes
def title
self[:title].upcase
end
def title
super.upcase
end
module A
def foo
"bar"
end
end
class B
include A
def foo
super.upcase
end
end
Don’t fight Ruby
<3 <3 <3
#read_attribute
#[]
def read_attribute(name)
name = "_#{name}"
if respond_to?(name)
send(name)
else
# other stuff
end
end
Module.new
def read_attribute(name)
mod = self.class.methods_module
if mod.respond_to?(name)
mod.send(name, @attributes)
else
# other stuff
end
end
Module.new.respond_to?(:name)
# => true
Module.new { extend self }
Module.new { extend self }
mod.method_defined?(:name)
Module.new { extend self }
INSANE HACKmod.method_defined?(:name)
Still too slow☹
gem install
perftools.rb
if attr_name == 'id'
attr_name =
self.class.primary_key
end
No code is fasterthan no code
def title
cast @attributes['title']
end
def title
cast @attributes[:title]
end
class A
def initialize
@attributes = { :foo => 1 }
end
def foo
@attributes[:foo]
end
end
class B
def initialize
@attributes = { 'foo' => 1 }
end
def foo
@attributes['foo']
end
end
Benchmark.ips do |r|
r.report('symbol') { a.foo }
r.report('string') { b.foo }
end
code = "@attributes['foo']"
iseq =
RubyVM::InstructionSequence
.compile(code)
puts iseq.disassemble
trace 1
getinstancevariable :@attributes
putstring "foo"
opt_aref <ic:2>
leave
trace 1
getinstancevariable :@attributes
putobject :foo
opt_aref <ic:2>
leave
DEFINE_INSN
putstring
(VALUE str)
()
(VALUE val)
{
val = rb_str_resurrect(str);
}
DEFINE_INSN
putobject
(VALUE val)
()
(VALUE val)
{
/* */
}
code = "@attributes['foo']"
compiled =
Rubinius::Compiler
.compile_string(code)
puts compiled.decode
push_ivar 0
push_literal "foo"
string_dup
send_stack :[], 1
pop
push_true
ret
push_ivar 0
push_literal :foo
send_stack :[], 1
pop
push_true
ret
jruby --bytecode
-e "@attributes['foo']"
RubyString
RubyString
RubySymbol
Performance problemsare a code smell
Be a scientist
But...
Avoid roflscaling!
Thanks!IT'S OVER!
Thanks!IT'S OVER!
(♥ @tenderlove ♥)