Nokogiri のお母さん
Thursday, November 11, 2010
@flavorjones
Thursday, November 11, 2010
ZOMG!!!!!
Thursday, November 11, 2010
HAPPY
THURSDAY!!
Thursday, November 11, 2010
WELCOME TO
RubyConf X!
Thursday, November 11, 2010
X-TREME
RUBYCONF!!!!!
Thursday, November 11, 2010
Aaron Patterson
Thursday, November 11, 2010
AT&T, AT&T logo and all AT&T related marks are trademarks of AT&T Intellectual Property and/or AT&T affiliated companies.
...
@tenderlove
Thursday, November 11, 2010
aaron.patterson@gmail.com
Thursday, November 11, 2010
Thursday, November 11, 2010
ruby committer
Thursday, November 11, 2010
rails committer
Thursday, November 11, 2010
Committer
HOWTO
Thursday, November 11, 2010
Ruby
Thursday, November 11, 2010
Thursday, November 11, 2010
♥
Thursday, November 11, 2010
Rails
Thursday, November 11, 2010
Thursday, November 11, 2010
♥
Thursday, November 11, 2010
RubyConf
Thursday, November 11, 2010
Thursday, November 11, 2010
♥
Thursday, November 11, 2010
WWFMD?
Thursday, November 11, 2010
RubyConf 5k
Thursday, November 11, 2010
RUBYCONF
FIVE THOUSAND
Thursday, November 11, 2010
Thursday, November 11, 2010
Thursday, November 11, 2010
ZOMG WHY IS THIS
CODE SO SLOW?
Thursday, November 11, 2010
Performance
Thursday, November 11, 2010
Code Analysis
Thursday, November 11, 2010
Story Form
Thursday, November 11, 2010
Thursday, November 11, 2010
IRL
Tools
IRL
Theory
IRL
Thursday, November 11, 2010
ARel
Thursday, November 11, 2010
What is it?
Thursday, November 11, 2010
"Relational Algebra"
Thursday, November 11, 2010
AST Manipulation
Thursday, November 11, 2010
Statement
Column Sources
Table
Conditions
Thursday, November 11, 2010
Statement
Column Sources
Table
Conditions
Table 1 = 1
Thursday, November 11, 2010
AST Translation
Thursday, November 11, 2010
Statement
Column Sources
Table
Conditions
Table 1 = 1
Thursday, November 11, 2010
Statement
Column Sources
Table
Conditions
Table 1 = 1
Statement
Column Sources
Table
Conditions
Table 1 = 1
Thursday, Nove...
SELECT COLUMN
FROM TABLE, TABLE
WHERE 1 = 1
Thursday, November 11, 2010
Relationship with
Rails
Thursday, November 11, 2010
ActiveRecord
User (YOU!)
ARel
Thursday, November 11, 2010
ActiveRecord
User (YOU!)
ARel
Records PLZ
SQL STMT
Thursday, November 11, 2010
Thursday, November 11, 2010
The More You Know™
Thursday, November 11, 2010
Getting Started
Thursday, November 11, 2010
AT&T, AT&T logo and all AT&T related marks are trademarks of AT&T Intellectual Property and/or AT&T affiliated companies.
...
Rails
Thursday, November 11, 2010
Prepared Statement
Caching
Thursday, November 11, 2010
Thursday, November 11, 2010
DEEPER
UNDERSTANDING
REQUIRED
Thursday, November 11, 2010
ActiveRecord 5x
slower than Rails
2.3.5
Thursday, November 11, 2010
http://bit.ly/omgslow
Thursday, November 11, 2010
5x Slower?!?
Thursday, November 11, 2010
WTF?
Thursday, November 11, 2010
Yes, 5x Slower
Thursday, November 11, 2010
What could possibly
go wrong?
Thursday, November 11, 2010
Motivation
Thursday, November 11, 2010
Why do you care
about speed?
Thursday, November 11, 2010
Scaling Ruby
Thursday, November 11, 2010
Thursday, November 11, 2010
Thursday, November 11, 2010
When should I make
my code faster?
Thursday, November 11, 2010
When it isn't fast
enough.
Thursday, November 11, 2010
What is
"fast enough"?
Thursday, November 11, 2010
Do people notice it?
Thursday, November 11, 2010
In comparison to?
Thursday, November 11, 2010
Finishes in a
reasonable amount
of time.
Thursday, November 11, 2010
What code should I
improve?
Thursday, November 11, 2010
*Only* the code that
matters.
Thursday, November 11, 2010
Don't believe me.
Thursday, November 11, 2010
Think Critically
Thursday, November 11, 2010
Discovery
Thursday, November 11, 2010
What to measure?
Thursday, November 11, 2010
Breakdown
Thursday, November 11, 2010
Thursday, November 11, 2010
Post.find(1)
ARel....
find_by_sql()
execute()
log()
Thursday, November 11, 2010
find_by_sql()
execute()
log()
Thursday, November 11, 2010
Work per Time
Thursday, November 11, 2010
Performance
Degraded
Thursday, November 11, 2010
Benchmarking
Thursday, November 11, 2010
Our Enemies
Thursday, November 11, 2010
Time
Thursday, November 11, 2010
Space
Thursday, November 11, 2010
For Performance:
Thursday, November 11, 2010
Things To Reduce
•Method calls
•Branching and looping
•Objects (memory consumption)
Thursday, November 11, 2010
For Clean Code:
Thursday, November 11, 2010
Things To Reduce
•Method calls
•Branching and looping
•Objects (memory consumption)
Thursday, November 11, 2010
∴
(therefore)
Thursday, November 11, 2010
Clean Code
==
Performant code
Thursday, November 11, 2010
Measurement is
Paramount
Thursday, November 11, 2010
require 'benchmark'
Thursday, November 11, 2010
require 'benchmark'
def fib n
a = 0
b = 1
n.times { a, b = b, a + b }
a
end
Benchmark.bm(7) do |x|
x.report("fib") do
3000...
user system total real
fib 1.570000 0.000000 1.570000 ( 1.570726)
Thursday, November 11, 2010
user
system
total
real
1.570000
0.000000
1.570000
1.570726
Thursday, November 11, 2010
Benchmark.bm(10) do |x|
[1, 10, 100, 1000, 10000].each do |n|
x.report("fib #{n}") do
n.times { fib(1000) }
end
end
end
Th...
user system total real
fib 1 0.000000 0.000000 0.000000 ( 0.000671)
fib 10 0.010000 0.000000 0.010000 ( 0.008352)
fib 100 ...
0
2
4
6
8
0 2500 5000 7500 10000
y = 0.0007x - 1.899E-5
fib (n, 1 - 10000)
Thursday, November 11, 2010
minitest/benchmark
Thursday, November 11, 2010
require 'rubygems'
require 'minitest/autorun'
require 'minitest/benchmark'
class BenchFib < MiniTest::Unit::TestCase
def f...
Benchmark.bm(10) do |x|
[1, 10, 100, 1000, 10000].each do |n|
x.report("fib #{n}") do
n.times { fib(1000) }
end
end
end
Th...
assert_performance_linear 0.99 do |n|
n.times { fib(1000) }
end
Thursday, November 11, 2010
BenchFib 1 10 100 1000 10000
bench_fib 0.000571 0.005318 0.052582 0.825676 8.180719
Thursday, November 11, 2010
0
2.25
4.5
6.75
9
0 2500 5000 7500 10000
y = 0.0008x - 0.0067
BenchFib
Thursday, November 11, 2010
def bench_find_by_sql
assert_performance_linear 0.999 do |n|
n.times do
Post.find_by_sql(
'SELECT * FROM posts WHERE id = ...
execute()
def bench_execute
conn = Post.connection
assert_performance_linear 0.999 do |n|
n.times do
conn.execute(
'SELECT...
log()
def bench_log
conn = Post.connection
class << conn
public :log
end
assert_performance_linear 0.999 do |n|
n.times do...
0
0.75
1.5
2.25
3
0 2500 5000 7500 10000
y = 0.0001x - 0.0097
y = 0.0002x - 0.0135
y = 0.0002x - 0.0047
ActiveRecord 3.0 B...
0
0.75
1.5
2.25
3
0 2500 5000 7500 10000
y = 5.164E-5x - 0.0121
y = 0.0001x - 0.0037
y = 0.0002x - 0.0053
ActiveRecord 2.3...
0
0.75
1.5
2.25
3
0 2500 5000 7500 10000
bench_log 2.3.x + 3.0
bench_log (2.3) bench_log (3.0)
Thursday, November 11, 2010
Δ find_by_sql()
=
Δ execute()
=
Δ log()
Thursday, November 11, 2010
Δ execute() - Δ log() = 0
Thursday, November 11, 2010
Method Call
Analysis
Thursday, November 11, 2010
perftools.rb
http://github.com/tmm1/perftools.rb/
Thursday, November 11, 2010
CPUPROFILE=/tmp/
my_profile RUBYOPT="-
r`gem which perftools | tail
-1`" ruby ...
Thursday, November 11, 2010
CPUPROFILE=/tmp/
my_profile RUBYOPT="-
r`gem which perftools | tail
-1`" ruby ...
Thursday, November 11, 2010
Rails 3.0 Beta
Thursday, November 11, 2010
/System/Library/Frameworks/Ruby.framework/Versions/1.8/usr/bin/ruby
Total samples: 468
Focusing on: 468
Dropped nodes with...
k/Versions/1.8/usr/bin/ruby
Integer#times
25 (5.3%)
of 293 (62.6%)
ActiveRecord
ConnectionAdapters
AbstractAdapter#log
55 ...
Total: 468 samples
122 26.1% 26.1% 130 27.8% Benchmark.ms
113 24.1% 50.2% 113 24.1% garbage_collector
55 11.8% 62.0% 268 5...
Rails 2-3-stable
Thursday, November 11, 2010
/System/Library/Frameworks/Ruby.framework/Versions/1.8/usr/bin/ruby
Total samples: 212
Focusing on: 212
Dropped nodes with...
orks/Ruby.framework/Versions/1.8/usr/bin/ruby
1 abs(samples)
0 samples
Integer#times
4 (1.9%)
of 104 (49.1%)
ActiveRecord
...
Total: 212 samples
80 37.7% 37.7% 94 44.3% Benchmark.ms
55 25.9% 63.7% 55 25.9% garbage_collector
14 6.6% 70.3% 14 6.6% ::...
ruby-prof
Thursday, November 11, 2010
Usage
result = RubyProf.profile do
...
end
printer = RubyProf::FlatPrinter.new(result)
printer.print(STDOUT, 0)
Thursday, ...
n = 1000
Thursday, November 11, 2010
Rails 3.0 Beta
Thursday, November 11, 2010
Total: 0.160831
%self total self wait child calls name
28.26 0.15 0.05 0.00 0.10 1000 <::Notifications>#instrument
9.36 0....
Rails 2-3-stable
Thursday, November 11, 2010
Thread ID: 2148237740
Total: 0.051336
%self total self wait child calls name
27.00 0.03 0.01 0.00 0.01 1000 <Module::Bench...
Methods in Common
•<Class::Time>#now
•<Class::Time>#allocate
Thursday, November 11, 2010
Time#now
Time#allocate
3.0 Beta 2-3 Stable
4000 2000
4000 2000
n = 1000
Thursday, November 11, 2010
http://bit.ly/omgslow
Thursday, November 11, 2010
"It's all fixed!"
Thursday, November 11, 2010
Wait a few hours...
Thursday, November 11, 2010
"It's better, but still
2x slower"
Thursday, November 11, 2010
Post.find(1)
ARel....
find_by_sql()
execute()
log()
Thursday, November 11, 2010
ARel....
Thursday, November 11, 2010
Side note:
This is when Ryan
told me to rewrite.
Thursday, November 11, 2010
Superficial
Improvements
Thursday, November 11, 2010
Limited
Domain / System
Knowledge
Thursday, November 11, 2010
VM Tricks
Thursday, November 11, 2010
See Results Quickly
Thursday, November 11, 2010
Tapers off Over
Time
Thursday, November 11, 2010
Kowledge/Improvement
Time
Improvements (S) System Knowledge
System Impact
Thursday, November 11, 2010
attr_*
Thursday, November 11, 2010
def some_attribute
@some_attribute
end
# vs
attr_reader :some_attribute
Thursday, November 11, 2010
0
0.075
0.15
0.225
0.3
0 250000 500000 750000 1000000
y = 1.965E-7x + 0.0002
y = 2.934E-7x + 0.0009
bench_method bench_rea...
case VM_METHOD_TYPE_IVAR: {
if (argc != 0) {
rb_raise(rb_eArgError,
"wrong number of arguments (%d for 0)", argc);
}
val =...
method call
case VM_METHOD_TYPE_ISEQ: {
rb_control_frame_t *reg_cfp;
int i;
rb_vm_set_finish_env(th);
reg_cfp = th->cfp;
C...
vm_setup_method
•Check for stack overflow
•Pushing a stack frame
•Copying arguments
Thursday, November 11, 2010
class Foo
attr_reader :some_attribute
def some_attribute?
@some_attribute
end
end
Predicate Methods
Thursday, November 11,...
class Foo
attr_reader :some_attribute
alias :some_attribute? :some_attribute
end
Predicate Methods
Thursday, November 11, ...
Hash[] vs inject({})
Thursday, November 11, 2010
inject({})
some_list.inject({}) do |hash,val|
hash[val] = some_transform(val)
hash
end
Thursday, November 11, 2010
Hash[]
values = some_list.map { |val|
[val, some_transform(val)]
}
Hash[values]
Thursday, November 11, 2010
@list.inject({}) do |hash,val|
hash[val] = val.length
hash
end
# vs
Hash[@list.map { |val| [val,val.length] }]
Thursday, N...
0
1.75
3.5
5.25
7
0 250000 500000 750000 1000000
y = 6.17E-6x - 0.0108
y = 5.268E-6x - 0.0075
Hash[] inject({})
Thursday, ...
Strangeness
Thursday, November 11, 2010
def bench_naked_each
assert_performance_linear 0.999 do |n|
m = nil
n.times { @list.each { |v| m = v } }
end
end
def bench...
0
0.75
1.5
2.25
3
0 250000 500000 750000 1000000
y = 2.746E-6x - 0.0043
y = 1.04E-6x - 0.0016
naked each naked inject
Thur...
TANGENT
Thursday, November 11, 2010
When to use inject()
Thursday, November 11, 2010
When one
calculation depends
on the previous
Thursday, November 11, 2010
@list.inject({}) do |hash,val|
hash[val] = val.length
hash
end
# vs
Hash[@list.map { |val| [val,val.length] }]
Thursday, N...
%w{
Foo
Bar
Baz
}.inject(Object) { |klass,string|
klass.const_get(string.to_sym)
}
Thursday, November 11, 2010
Proc Activation
Thursday, November 11, 2010
lambda { ... }
# vs
class Callable
def call; ... end
end
Thursday, November 11, 2010
0
0.01
0.02
0.03
0.04
0 25000 50000 75000 100000
lambda method
Thursday, November 11, 2010
is_a?(Proc)
Thursday, November 11, 2010
respond_to?(:call)
Thursday, November 11, 2010
class Callable
def call(...)
...
end
end
Thursday, November 11, 2010
define_method
Thursday, November 11, 2010
class Foo
def foo; end
define_method :bar do; end
class_eval %{ def baz; end }
end
Thursday, November 11, 2010
-0.15
0
0.15
0.3
0.45
0.6
0 250000 500000 750000 1000000
method class_eval define_method
Thursday, November 11, 2010
Explicit Block
Parameters
Thursday, November 11, 2010
class Foo
def explicit &block
yield
end
def implicit
yield
end
end
Thursday, November 11, 2010
-3.75
0
3.75
7.5
11.25
15
0 250000 500000 750000 1000000
explicit implicit
Thursday, November 11, 2010
def sometimes_block
if block_given?
Proc.new.call
end
end
sometimes_block { puts "hi" }
sometimes_block
Thursday, November...
Symbol to Proc
Thursday, November 11, 2010
@list.map(&:to_i)
# vs
@list.map { |x| x.to_i }
Thursday, November 11, 2010
-5
1.25
7.5
13.75
20
0 250000 500000 750000 1000000
sym to proc block form
Thursday, November 11, 2010
-5
1.25
7.5
13.75
20
0 250000 500000 750000 1000000
symbol to proc block method
Thursday, November 11, 2010
Know Your
Audience
Thursday, November 11, 2010
return value
caching
Thursday, November 11, 2010
def some_method
@some_method ||= some_expensive_op
end
Thursday, November 11, 2010
How many times?
Thursday, November 11, 2010
Can the caller
cache?
Thursday, November 11, 2010
Made our
improvements
Thursday, November 11, 2010
Feeling better!
Thursday, November 11, 2010
:-D
Thursday, November 11, 2010
0
200000
400000
600000
800000
0 25000 50000 75000 100000
before (3.0 beta) after (3.0 beta) Rails 2.3
Thursday, November 1...
What do we do?
Thursday, November 11, 2010
We have to go deeper
Thursday, November 11, 2010
$ git grep 'include Relation' | wc -l
6
$ git grep 'def bind' | wc -l
12
$
Thursday, November 11, 2010
Everything is_a
Relation
Thursday, November 11, 2010
Everything
Responds to "bind"
Thursday, November 11, 2010
Everything has a
"relation"
Thursday, November 11, 2010
bind() is recursively
called on relation
Thursday, November 11, 2010
How does it work?
Thursday, November 11, 2010
Array#map
13 (0.3%)
of 136 (3.6%)
Class#new
632 (16.7%)
of 806 (21.2%)
Arel
Project#initialize
60 (1.6%)
of 149 (3.9%)
149...
y
Integer#times
41 (1.1%)
of 2720 (71.7%)
Object#find
48 (1.3%)
of 2718 (71.6%)
2666
Object#find_with_ids
71 (1.9%)
of 2717 ...
Data Structure
Analysis
Thursday, November 11, 2010
Graphviz
graphviz.org
Thursday, November 11, 2010
digraph "foo" {
node [width=0.375,height=0.25];
N1 [label="hello"];
N2 [label="world"];
N1 -> N2;
}
Thursday, November 11,...
hello
world
Thursday, November 11, 2010
Visitor Pattern
Thursday, November 11, 2010
class Visitor
def accept(object)
method = object.class.name.split('::').join('_')
send("visit_#{method}", object)
end
end
...
class Visitor
def accept(object)
method = object.class.name.split('::').join('_')
send("visit_#{method}", object)
end
def ...
class Visitor
def accept(object)
method = object.class.name.split('::').join('_')
send("visit_#{method}", object)
end
def ...
Thursday, November 11, 2010
Thursday, November 11, 2010
Linked List
Thursday, November 11, 2010
Relation Relation Relation Relation
value valuevalue value
Thursday, November 11, 2010
Relation Relation Relation Relation
value valuevalue value
Thursday, November 11, 2010
Relation Relation Relation Relation
Bind() +
Dup
Bind() +
Dup
Bind() +
Dup
Bind() +
Dup
Thursday, November 11, 2010
Relation Relation Relation Relation
Bind() +
Dup
Bind() +
Dup
Bind() +
Dup
Bind() +
Dup
Bind() +
Dup
Bind() +
Dup
Bind() +...
Where Where Where Where
1 = 1 3 = 32 = 2 4 = 4
Thursday, November 11, 2010
Where Where Where Where
1 = 1 3 = 32 = 2 4 = 4
2 = 2
3 = 3
1 = 1
1 = 1
2 = 21 = 1
Thursday, November 11, 2010
Big O!
Thursday, November 11, 2010
OMG
Thursday, November 11, 2010
ZOMG
Thursday, November 11, 2010
Mathematical
Representation
Thursday, November 11, 2010
0
1.25
2.5
3.75
5
0 2.25 4.5 6.75 9
y = 2
Thursday, November 11, 2010
0
1.25
2.5
3.75
5
1 4.5 8 11.5 15
y = log(n)
Thursday, November 11, 2010
0
2.25
4.5
6.75
9
0 2.25 4.5 6.75 9
y = x
Thursday, November 11, 2010
-10
0
10
20
30
40
1 4.5 8 11.5 15
y = n log(n)
Thursday, November 11, 2010
0
50
100
150
200
0 3.75 7.5 11.25 15
y = n^2
Thursday, November 11, 2010
Finding Big O
•Give input
•Measure output
•Plot Results
Thursday, November 11, 2010
ARel's Big O
0
12.5
25
37.5
50
0 2.25 4.5 6.75 9
objects and funcalls
Thursday, November 11, 2010
ARel's Big O
0
12.5
25
37.5
50
0 2.25 4.5 6.75 9
objects and funcalls
Thursday, November 11, 2010
ARel's Big O
0
12.5
25
37.5
50
0 2.25 4.5 6.75 9
objects and funcalls
Thursday, November 11, 2010
ARel's Big O
0
12.5
25
37.5
50
0 2.25 4.5 6.75 9
objects and funcalls
Thursday, November 11, 2010
ARel's Big O
0
12.5
25
37.5
50
0 2.25 4.5 6.75 9
objects and funcalls
Thursday, November 11, 2010
Thursday, November 11, 2010
Thursday, November 11, 2010
ActiveRecord/Arel
takes over 2
minutes to generate
a pseudo-complex
SQL query.
http://bit.ly/omgslow2
Thursday, November 1...
Deep Improvements
Thursday, November 11, 2010
Kowledge/Improvement
Time
Improvements (S) System Knowledge
System Impact
Thursday, November 11, 2010
AST + Visitor
Thursday, November 11, 2010
O(n)
Thursday, November 11, 2010
Should I rewrite?
•Clear solution
•Tests are numerous (Rails)
•Public API is limited
Thursday, November 11, 2010
YES
Thursday, November 11, 2010
6 Weeks Later...
Thursday, November 11, 2010
ARel Today
Thursday, November 11, 2010
Data Sheet
•O(n)
•6 Weeks to Rewrite
•2x faster (for simple queries)
•Adapter Specific code is DRY
Thursday, November 11, 2...
flog (before)
2533.1: flog total
6.8: flog/method average
116.6: OracleCompiler#select_sql
78.0: PostgreSQLCompiler#select_...
flog (after)
1864.6: flog total
6.5: flog/method average
81.4: main#none
75.9: Dot#none
59.1: Oracle# lib/arel/visitors/ora...
flay (before)
Total score (lower is better) = 684
12 complaints
Thursday, November 11, 2010
flay (after)
Total score (lower is better) = 420
7 complaints
Thursday, November 11, 2010
Post.where("id = 1").to_dot
Thursday, November 11, 2010
Arel::Nodes::SelectStatement
Array
cores
NilClass
offset limit
Array
orders
Arel::Nodes::SelectCore
0
Arel::Table
froms
Ar...
ARel Tomorrow
Thursday, November 11, 2010
Conclusion
Thursday, November 11, 2010
AKA:
Things I've Learned
Thursday, November 11, 2010
Kowledge/Improvement
Time
Improvements (S) System Knowledge Improvements (D)
System Impact
Thursday, November 11, 2010
When Should I
Rewrite?
Thursday, November 11, 2010
Rewrite Timeline
Thursday, November 11, 2010
Rewrite Timeline
Thursday, November 11, 2010
We emphasize
the art
of Code
Thursday, November 11, 2010
We should not forget
the Science
Thursday, November 11, 2010
Learn
The Specific
Thursday, November 11, 2010
But Embrace
The Generic
Thursday, November 11, 2010
Photo Credits
• DHH: http://www.flickr.com/photos/pdcawley/250813158/
• Matz: http://www.flickr.com/photos/kakutani/41273548...
Thanks @ebiltwin
Thursday, November 11, 2010
Thank you!
Thursday, November 11, 2010
One More Thing...
Thursday, November 11, 2010
It's RubyConf 10!
Thursday, November 11, 2010
Give Ryan a Kiss!
<3
Thursday, November 11, 2010
Thursday, November 11, 2010
♥
Thursday, November 11, 2010
Questions?
Thursday, November 11, 2010
Upcoming SlideShare
Loading in...5
×

ZOMG WHY IS THIS CODE SO SLOW

19,437

Published on

My RubyConf 2010 talk

Published in: Technology
5 Comments
38 Likes
Statistics
Notes
No Downloads
Views
Total Views
19,437
On Slideshare
0
From Embeds
0
Number of Embeds
4
Actions
Shares
0
Downloads
248
Comments
5
Likes
38
Embeds 0
No embeds

No notes for slide

ZOMG WHY IS THIS CODE SO SLOW

  1. 1. Nokogiri のお母さん Thursday, November 11, 2010
  2. 2. @flavorjones Thursday, November 11, 2010
  3. 3. ZOMG!!!!! Thursday, November 11, 2010
  4. 4. HAPPY THURSDAY!! Thursday, November 11, 2010
  5. 5. WELCOME TO RubyConf X! Thursday, November 11, 2010
  6. 6. X-TREME RUBYCONF!!!!! Thursday, November 11, 2010
  7. 7. Aaron Patterson Thursday, November 11, 2010
  8. 8. AT&T, AT&T logo and all AT&T related marks are trademarks of AT&T Intellectual Property and/or AT&T affiliated companies. Thursday, November 11, 2010
  9. 9. @tenderlove Thursday, November 11, 2010
  10. 10. aaron.patterson@gmail.com Thursday, November 11, 2010
  11. 11. Thursday, November 11, 2010
  12. 12. ruby committer Thursday, November 11, 2010
  13. 13. rails committer Thursday, November 11, 2010
  14. 14. Committer HOWTO Thursday, November 11, 2010
  15. 15. Ruby Thursday, November 11, 2010
  16. 16. Thursday, November 11, 2010
  17. 17. ♥ Thursday, November 11, 2010
  18. 18. Rails Thursday, November 11, 2010
  19. 19. Thursday, November 11, 2010
  20. 20. ♥ Thursday, November 11, 2010
  21. 21. RubyConf Thursday, November 11, 2010
  22. 22. Thursday, November 11, 2010
  23. 23. ♥ Thursday, November 11, 2010
  24. 24. WWFMD? Thursday, November 11, 2010
  25. 25. RubyConf 5k Thursday, November 11, 2010
  26. 26. RUBYCONF FIVE THOUSAND Thursday, November 11, 2010
  27. 27. Thursday, November 11, 2010
  28. 28. Thursday, November 11, 2010
  29. 29. ZOMG WHY IS THIS CODE SO SLOW? Thursday, November 11, 2010
  30. 30. Performance Thursday, November 11, 2010
  31. 31. Code Analysis Thursday, November 11, 2010
  32. 32. Story Form Thursday, November 11, 2010
  33. 33. Thursday, November 11, 2010
  34. 34. IRL Tools IRL Theory IRL Thursday, November 11, 2010
  35. 35. ARel Thursday, November 11, 2010
  36. 36. What is it? Thursday, November 11, 2010
  37. 37. "Relational Algebra" Thursday, November 11, 2010
  38. 38. AST Manipulation Thursday, November 11, 2010
  39. 39. Statement Column Sources Table Conditions Thursday, November 11, 2010
  40. 40. Statement Column Sources Table Conditions Table 1 = 1 Thursday, November 11, 2010
  41. 41. AST Translation Thursday, November 11, 2010
  42. 42. Statement Column Sources Table Conditions Table 1 = 1 Thursday, November 11, 2010
  43. 43. Statement Column Sources Table Conditions Table 1 = 1 Statement Column Sources Table Conditions Table 1 = 1 Thursday, November 11, 2010
  44. 44. SELECT COLUMN FROM TABLE, TABLE WHERE 1 = 1 Thursday, November 11, 2010
  45. 45. Relationship with Rails Thursday, November 11, 2010
  46. 46. ActiveRecord User (YOU!) ARel Thursday, November 11, 2010
  47. 47. ActiveRecord User (YOU!) ARel Records PLZ SQL STMT Thursday, November 11, 2010
  48. 48. Thursday, November 11, 2010
  49. 49. The More You Know™ Thursday, November 11, 2010
  50. 50. Getting Started Thursday, November 11, 2010
  51. 51. AT&T, AT&T logo and all AT&T related marks are trademarks of AT&T Intellectual Property and/or AT&T affiliated companies. Thursday, November 11, 2010
  52. 52. Rails Thursday, November 11, 2010
  53. 53. Prepared Statement Caching Thursday, November 11, 2010
  54. 54. Thursday, November 11, 2010
  55. 55. DEEPER UNDERSTANDING REQUIRED Thursday, November 11, 2010
  56. 56. ActiveRecord 5x slower than Rails 2.3.5 Thursday, November 11, 2010
  57. 57. http://bit.ly/omgslow Thursday, November 11, 2010
  58. 58. 5x Slower?!? Thursday, November 11, 2010
  59. 59. WTF? Thursday, November 11, 2010
  60. 60. Yes, 5x Slower Thursday, November 11, 2010
  61. 61. What could possibly go wrong? Thursday, November 11, 2010
  62. 62. Motivation Thursday, November 11, 2010
  63. 63. Why do you care about speed? Thursday, November 11, 2010
  64. 64. Scaling Ruby Thursday, November 11, 2010
  65. 65. Thursday, November 11, 2010
  66. 66. Thursday, November 11, 2010
  67. 67. When should I make my code faster? Thursday, November 11, 2010
  68. 68. When it isn't fast enough. Thursday, November 11, 2010
  69. 69. What is "fast enough"? Thursday, November 11, 2010
  70. 70. Do people notice it? Thursday, November 11, 2010
  71. 71. In comparison to? Thursday, November 11, 2010
  72. 72. Finishes in a reasonable amount of time. Thursday, November 11, 2010
  73. 73. What code should I improve? Thursday, November 11, 2010
  74. 74. *Only* the code that matters. Thursday, November 11, 2010
  75. 75. Don't believe me. Thursday, November 11, 2010
  76. 76. Think Critically Thursday, November 11, 2010
  77. 77. Discovery Thursday, November 11, 2010
  78. 78. What to measure? Thursday, November 11, 2010
  79. 79. Breakdown Thursday, November 11, 2010
  80. 80. Thursday, November 11, 2010
  81. 81. Post.find(1) ARel.... find_by_sql() execute() log() Thursday, November 11, 2010
  82. 82. find_by_sql() execute() log() Thursday, November 11, 2010
  83. 83. Work per Time Thursday, November 11, 2010
  84. 84. Performance Degraded Thursday, November 11, 2010
  85. 85. Benchmarking Thursday, November 11, 2010
  86. 86. Our Enemies Thursday, November 11, 2010
  87. 87. Time Thursday, November 11, 2010
  88. 88. Space Thursday, November 11, 2010
  89. 89. For Performance: Thursday, November 11, 2010
  90. 90. Things To Reduce •Method calls •Branching and looping •Objects (memory consumption) Thursday, November 11, 2010
  91. 91. For Clean Code: Thursday, November 11, 2010
  92. 92. Things To Reduce •Method calls •Branching and looping •Objects (memory consumption) Thursday, November 11, 2010
  93. 93. ∴ (therefore) Thursday, November 11, 2010
  94. 94. Clean Code == Performant code Thursday, November 11, 2010
  95. 95. Measurement is Paramount Thursday, November 11, 2010
  96. 96. require 'benchmark' Thursday, November 11, 2010
  97. 97. require 'benchmark' def fib n a = 0 b = 1 n.times { a, b = b, a + b } a end Benchmark.bm(7) do |x| x.report("fib") do 3000.times do |i| fib(1000) end end end Thursday, November 11, 2010
  98. 98. user system total real fib 1.570000 0.000000 1.570000 ( 1.570726) Thursday, November 11, 2010
  99. 99. user system total real 1.570000 0.000000 1.570000 1.570726 Thursday, November 11, 2010
  100. 100. Benchmark.bm(10) do |x| [1, 10, 100, 1000, 10000].each do |n| x.report("fib #{n}") do n.times { fib(1000) } end end end Thursday, November 11, 2010
  101. 101. user system total real fib 1 0.000000 0.000000 0.000000 ( 0.000671) fib 10 0.010000 0.000000 0.010000 ( 0.008352) fib 100 0.070000 0.000000 0.070000 ( 0.074577) fib 1000 0.740000 0.000000 0.740000 ( 0.734922) fib 10000 7.330000 0.000000 7.330000 ( 7.370046) Thursday, November 11, 2010
  102. 102. 0 2 4 6 8 0 2500 5000 7500 10000 y = 0.0007x - 1.899E-5 fib (n, 1 - 10000) Thursday, November 11, 2010
  103. 103. minitest/benchmark Thursday, November 11, 2010
  104. 104. require 'rubygems' require 'minitest/autorun' require 'minitest/benchmark' class BenchFib < MiniTest::Unit::TestCase def fib n a = 0 b = 1 n.times { a, b = b, a + b } a end def bench_fib assert_performance_linear 0.99 do |n| n.times { fib(1000) } end end end Thursday, November 11, 2010
  105. 105. Benchmark.bm(10) do |x| [1, 10, 100, 1000, 10000].each do |n| x.report("fib #{n}") do n.times { fib(1000) } end end end Thursday, November 11, 2010
  106. 106. assert_performance_linear 0.99 do |n| n.times { fib(1000) } end Thursday, November 11, 2010
  107. 107. BenchFib 1 10 100 1000 10000 bench_fib 0.000571 0.005318 0.052582 0.825676 8.180719 Thursday, November 11, 2010
  108. 108. 0 2.25 4.5 6.75 9 0 2500 5000 7500 10000 y = 0.0008x - 0.0067 BenchFib Thursday, November 11, 2010
  109. 109. def bench_find_by_sql assert_performance_linear 0.999 do |n| n.times do Post.find_by_sql( 'SELECT * FROM posts WHERE id = 1') end end end find_by_sql Thursday, November 11, 2010
  110. 110. execute() def bench_execute conn = Post.connection assert_performance_linear 0.999 do |n| n.times do conn.execute( 'SELECT * FROM posts WHERE id = 1') end end end Thursday, November 11, 2010
  111. 111. log() def bench_log conn = Post.connection class << conn public :log end assert_performance_linear 0.999 do |n| n.times do conn.log('SQL', 'hi mom!') {} end end end Thursday, November 11, 2010
  112. 112. 0 0.75 1.5 2.25 3 0 2500 5000 7500 10000 y = 0.0001x - 0.0097 y = 0.0002x - 0.0135 y = 0.0002x - 0.0047 ActiveRecord 3.0 Beta bench_find_by_sql bench_execute bench_log Thursday, November 11, 2010
  113. 113. 0 0.75 1.5 2.25 3 0 2500 5000 7500 10000 y = 5.164E-5x - 0.0121 y = 0.0001x - 0.0037 y = 0.0002x - 0.0053 ActiveRecord 2.3.x bench_find_by_sql bench_execute bench_log Thursday, November 11, 2010
  114. 114. 0 0.75 1.5 2.25 3 0 2500 5000 7500 10000 bench_log 2.3.x + 3.0 bench_log (2.3) bench_log (3.0) Thursday, November 11, 2010
  115. 115. Δ find_by_sql() = Δ execute() = Δ log() Thursday, November 11, 2010
  116. 116. Δ execute() - Δ log() = 0 Thursday, November 11, 2010
  117. 117. Method Call Analysis Thursday, November 11, 2010
  118. 118. perftools.rb http://github.com/tmm1/perftools.rb/ Thursday, November 11, 2010
  119. 119. CPUPROFILE=/tmp/ my_profile RUBYOPT="- r`gem which perftools | tail -1`" ruby ... Thursday, November 11, 2010
  120. 120. CPUPROFILE=/tmp/ my_profile RUBYOPT="- r`gem which perftools | tail -1`" ruby ... Thursday, November 11, 2010
  121. 121. Rails 3.0 Beta Thursday, November 11, 2010
  122. 122. /System/Library/Frameworks/Ruby.framework/Versions/1.8/usr/bin/ruby Total samples: 468 Focusing on: 468 Dropped nodes with <= 2 abs(samples) Dropped edges with <= 0 samples Integer#times 25 (5.3%) of 293 (62.6%) ActiveRecord ConnectionAdapters AbstractAdapter#log 55 (11.8%) of 268 (57.3%) 268 ActiveSupport Notifications.instrument 32 (6.8%) of 213 (45.5%) 213 Benchmark.ms 122 (26.1%) of 130 (27.8%) 130 ActiveSupport Notifications Instrumenter#instrument 6 (1.3%) of 180 (38.5%) 180 130 ActiveSupport Notifications Fanout#publish 3 (0.6%) of 35 (7.5%) 35 Time.now 15 (3.2%) 9 Benchmark.realtime 2 (0.4%) of 9 (1.9%) 9 garbage_collector 113 (24.1%) Array#each 12 (2.6%) of 70 (15.0%) Object#require 9 (1.9%) of 51 (10.9%) 1 23 Gem.load_plugins 0 (0.0%) of 18 (3.8%) 2 Gem GemPathSearcher#initialize 0 (0.0%) of 16 (3.4%) 1 Gem SourceIndex#load_gems_in 0 (0.0%) of 15 (3.2%) 15 Object#find 0 (0.0%) of 10 (2.1%) 10 ActiveSupport Dependencies WatchStack#new_constants_for 0 (0.0%) of 5 (1.1%) 4 46 Kernel#gem_original_require 8 (1.7%) of 28 (6.0%) 48 Object#load_dependency 0 (0.0%) of 28 (6.0%) 5218 Gem GemPathSearcher#find 0 (0.0%) of 10 (2.1%) 10 34 ActiveSupport Notifications Fanout Subscriber#publish 3 (0.6%) of 21 (4.5%) 21 44 Module#new_constants_in 0 (0.0%) of 28 (6.0%) 45 5 ActiveSupport Dependencies WatchStack#add_modules 0 (0.0%) of 4 (0.9%) 4 45 54 ActiveSupport LogSubscriber#call 18 (3.8%) 18 Class#new 2 (0.4%) of 19 (4.1%) 14 Gem Specification#initialize 0 (0.0%) of 5 (1.1%) 5 Gem Version#initialize 0 (0.0%) of 3 (0.6%) 3 2 Gem.find_files 1 (0.2%) of 16 (3.4%) 16 Gem.searcher 0 (0.0%) of 14 (3.0%) 12 Array#map 1 (0.2%) of 6 (1.3%) 1 Gem GemPathSearcher#find_all 0 (0.0%) of 3 (0.6%) 3 1 Gem GemPathSearcher#init_gemspecs 0 (0.0%) of 15 (3.2%) 15 Gem SourceIndex.from_installed_gems 0 (0.0%) of 16 (3.4%) Gem SourceIndex.from_gems_in 0 (0.0%) of 15 (3.2%) 15 Array#reverse_each 0 (0.0%) of 15 (3.2%) 15 Gem.source_index 0 (0.0%) of 15 (3.2%) 15 15 15 15 Gem SourceIndex.load_specification 9 (1.9%) of 15 (3.2%) 15 Gem SourceIndex#refresh! 0 (0.0%) of 15 (3.2%) 15 15 9 6 14 Mutex#synchronize 0 (0.0%) of 13 (2.8%) 12 Gem GemPathSearcher#matching_file? 0 (0.0%) of 13 (2.8%) Gem GemPathSearcher#matching_files 13 (2.8%) 13 13 10 10 10 10 1 6 Object#require_library_or_gem 0 (0.0%) of 9 (1.9%) 9 Object#silence_warnings 0 (0.0%) of 4 (0.9%) 4 Module#class_eval 3 (0.6%) of 8 (1.7%) 1 4 Module#local_constant_names 1 (0.2%) of 8 (1.7%) 1 Module#local_constants 5 (1.1%) of 6 (1.3%) 6 1 4 Array#select 1 (0.2%) of 4 (0.9%) 1 5 4 4 ActiveRecord Base.sqlite3_connection 0 (0.0%) of 4 (0.9%) 4 ActiveRecord ConnectionAdapters ConnectionPool#checkout_new_connection 0 (0.0%) of 4 (0.9%) ActiveRecord ConnectionAdapters ConnectionPool#new_connection 0 (0.0%) of 4 (0.9%) 4 4 4 4 3 4 Object#with_warnings 0 (0.0%) of 4 (0.9%) 4 4 33 Gem Version#segments 3 (0.6%) 3 Thursday, November 11, 2010
  123. 123. k/Versions/1.8/usr/bin/ruby Integer#times 25 (5.3%) of 293 (62.6%) ActiveRecord ConnectionAdapters AbstractAdapter#log 55 (11.8%) of 268 (57.3%) 268 ActiveSupport Notifications.instrument 32 (6.8%) of 213 (45.5%) 213 Benchmark.ms 122 (26.1%) of 130 (27.8%) 130 ActiveSupport Notifications Instrumenter#instrument 6 (1.3%) of 180 (38.5%) 180 130 ActiveSupport Notifications Fanout#publish 3 (0.6%) of 35 (7.5%) 35 Time.now 15 (3.2%) 9 Benchmark.realtime 2 (0.4%) of 9 (1.9%) 9 garbage_collector 113 (24.1%) Array#each 12 (2.6%) of 70 (15.0%) 2334 ActiveSupport Notifications Fanout Subscriber#publish 3 (0.6%) 21 1 6 Object#require_library_or_gem 0 (0.0%) of 9 (1.9%) Module#class_eval 3 (0.6%) of 8 (1.7%) 1 4 ActiveRecord Base.sqlite3_connection 0 (0.0%) of 4 (0.9%) 4 ActiveRecord ConnectionAdapters ConnectionPool#checkout_new_connection 0 (0.0%) of 4 (0.9%) ActiveRecord ConnectionAdapters ConnectionPool#new_connection 0 (0.0%) of 4 (0.9%) 4 4 Thursday, November 11, 2010
  124. 124. Total: 468 samples 122 26.1% 26.1% 130 27.8% Benchmark.ms 113 24.1% 50.2% 113 24.1% garbage_collector 55 11.8% 62.0% 268 57.3% ::AbstractAdapter#log 32 6.8% 68.8% 213 45.5% ::Notifications.instrument 25 5.3% 74.1% 293 62.6% Integer#times 18 3.8% 78.0% 18 3.8%::LogSubscriber#call 15 3.2% 81.2% 15 3.2% Time.now 13 2.8% 84.0% 13 2.8% GemPathSearcher#matching_files 12 2.6% 86.5% 70 15.0% Array#each 9 1.9% 88.5% 15 3.2% SourceIndex.load_specification 9 1.9% 90.4% 51 10.9% Object#require Thursday, November 11, 2010
  125. 125. Rails 2-3-stable Thursday, November 11, 2010
  126. 126. /System/Library/Frameworks/Ruby.framework/Versions/1.8/usr/bin/ruby Total samples: 212 Focusing on: 212 Dropped nodes with <= 1 abs(samples) Dropped edges with <= 0 samples Integer#times 4 (1.9%) of 104 (49.1%) ActiveRecord ConnectionAdapters AbstractAdapter#log 6 (2.8%) of 100 (47.2%) 100 Benchmark.ms 80 (37.7%) of 94 (44.3%) 94 Benchmark.realtime 8 (3.8%) of 15 (7.1%) 15 garbage_collector 55 (25.9%) Object#require 5 (2.4%) of 43 (20.3%) 30 Kernel#gem_original_require 9 (4.2%) of 20 (9.4%) 55 Gem.load_plugins 0 (0.0%) of 16 (7.5%) 16 Module#new_constants_in 0 (0.0%) of 16 (7.5%) 31 Gem GemPathSearcher#find 0 (0.0%) of 11 (5.2%) 11 Array#each 1 (0.5%) of 34 (16.0%) 8 Gem GemPathSearcher#initialize 0 (0.0%) of 17 (8.0%) 1 Gem SourceIndex#load_gems_in 0 (0.0%) of 15 (7.1%) 15 Object#find 0 (0.0%) of 11 (5.2%) 11 Gem Specification#assign_defaults 2 (0.9%) 2 38 8 Class#new 1 (0.5%) of 19 (9.0%) 17 Gem Specification#initialize 0 (0.0%) of 5 (2.4%) 5 Gem ConfigFile#initialize 0 (0.0%) of 2 (0.9%) 2 Gem Version#initialize 0 (0.0%) of 2 (0.9%) 2 Gem.find_files 1 (0.5%) of 17 (8.0%) Gem.searcher 0 (0.0%) of 17 (8.0%) 13 Gem GemPathSearcher#find_all 0 (0.0%) of 3 (1.4%) 3 Array#map 0 (0.0%) of 2 (0.9%) 1 17 Mutex#synchronize 0 (0.0%) of 16 (7.5%) 13 1 Gem GemPathSearcher#init_gemspecs 0 (0.0%) of 16 (7.5%) 16 Gem SourceIndex.from_installed_gems 0 (0.0%) of 17 (8.0%) Gem SourceIndex.from_gems_in 0 (0.0%) of 15 (7.1%) 15 Gem SourceIndex.installed_spec_directories 0 (0.0%) of 2 (0.9%) 2 16 Gem.source_index 0 (0.0%) of 16 (7.5%) 16 16 29 Array#collect 0 (0.0%) of 2 (0.9%) 2 Object#local_constant_names 0 (0.0%) of 2 (0.9%) 2 16 Array#reverse_each 0 (0.0%) of 15 (7.1%) 15 1 Time.now 6 (2.8%) 6 15 15 Gem SourceIndex.load_specification 10 (4.7%) of 15 (7.1%) 15 Gem SourceIndex#refresh! 0 (0.0%) of 15 (7.1%) 15 15 7 5 Gem GemPathSearcher#matching_file? 0 (0.0%) of 14 (6.6%) Gem GemPathSearcher#matching_files 14 (6.6%) 14 11 11 11 11 ActiveRecord Base.sqlite3_connection 0 (0.0%) of 8 (3.8%) Object#require_library_or_gem 0 (0.0%) of 8 (3.8%) 8 ActiveRecord ConnectionAdapters ConnectionPool#new_connection 0 (0.0%) of 8 (3.8%) 8 8 Object#silence_warnings 0 (0.0%) of 8 (3.8%) 88 ActiveRecord ConnectionAdapters ConnectionPool#checkout 0 (0.0%) of 5 (2.4%) ActiveRecord ConnectionAdapters ConnectionPool#checkout_new_connection 0 (0.0%) of 5 (2.4%) 5 Object#loop 0 (0.0%) of 4 (1.9%) 4 5 3 2 Module#class_eval 3 (1.4%) of 4 (1.9%) 1 MonitorMixin#synchronize 0 (0.0%) of 4 (1.9%) 4 4 Array#select 0 (0.0%) of 3 (1.4%) 33 3 2 1 Gem.configuration 0 (0.0%) of 2 (0.9%) 2 Gem.path 0 (0.0%) of 2 (0.9%) 2 Gem ConfigFile#load_file 0 (0.0%) of 2 (0.9%) 2 2 2 2 Gem Specification#full_gem_path 2 (0.9%) Object#local_constants 2 (0.9%) 2 Thursday, November 11, 2010
  127. 127. orks/Ruby.framework/Versions/1.8/usr/bin/ruby 1 abs(samples) 0 samples Integer#times 4 (1.9%) of 104 (49.1%) ActiveRecord ConnectionAdapters AbstractAdapter#log 6 (2.8%) of 100 (47.2%) 100 Benchmark.ms 80 (37.7%) of 94 (44.3%) 94 Benchmark.realtime 8 (3.8%) of 15 (7.1%) 15 garbage_collector 55 (25.9%) Object#require 5 (2.4%) of 43 (20.3%) 30 55 163138 29 1 Time.now 6 (2.8%) 6 ActiveRecord Base.sqlite3_connection 0 (0.0%) of 8 (3.8%) Object#require_library_or_gem 0 (0.0%) of 8 (3.8%) 8 ActiveRecord ConnectionAdapters ConnectionPool#new_connection 0 (0.0%) of 8 (3.8%) 8 8 Object#silence_warnings 0 (0.0%) of 8 (3.8%) 88 ActiveRecord ConnectionAdapters ConnectionPool#checkout 0 (0.0%) of 5 (2.4%) ActiveRecord ConnectionAdapters ConnectionPool#checkout_new_connection 0 (0.0%) of 5 (2.4%) 5 Object#loop 0 (0.0%) of 4 (1.9%) 4 5 MonitorMixin#synchronize 0 (0.0%) of 4 (1.9%) 4 4 Gem Specification#full_gem_path 2 (0.9%) Thursday, November 11, 2010
  128. 128. Total: 212 samples 80 37.7% 37.7% 94 44.3% Benchmark.ms 55 25.9% 63.7% 55 25.9% garbage_collector 14 6.6% 70.3% 14 6.6% ::GemPathSearcher#matching_files 10 4.7% 75.0% 15 7.1% ::SourceIndex.load_specification 9 4.2% 79.2% 20 9.4% Kernel#gem_original_require 8 3.8% 83.0% 15 7.1% Benchmark.realtime 6 2.8% 85.8% 100 47.2% ::AbstractAdapter#log 6 2.8% 88.7% 6 2.8% Time.now 5 2.4% 91.0% 43 20.3% Object#require 4 1.9% 92.9% 104 49.1% Integer#times 3 1.4% 94.3% 4 1.9% Module#class_eval 2 0.9% 95.3% 2 0.9% ::Specification#assign_defaults 2 0.9% 96.2% 2 0.9% Gem::Specification#full_gem_path 2 0.9% 97.2% 2 0.9% Object#local_constants Thursday, November 11, 2010
  129. 129. ruby-prof Thursday, November 11, 2010
  130. 130. Usage result = RubyProf.profile do ... end printer = RubyProf::FlatPrinter.new(result) printer.print(STDOUT, 0) Thursday, November 11, 2010
  131. 131. n = 1000 Thursday, November 11, 2010
  132. 132. Rails 3.0 Beta Thursday, November 11, 2010
  133. 133. Total: 0.160831 %self total self wait child calls name 28.26 0.15 0.05 0.00 0.10 1000 <::Notifications>#instrument 9.36 0.03 0.02 0.00 0.01 1000 <::Benchmark>#realtime 9.16 0.09 0.01 0.00 0.07 1000 ::Instrumenter#instrument 7.28 0.02 0.01 0.00 0.01 4000 <Class::Time>#now 5.41 0.16 0.01 0.00 0.15 1000 ::AbstractAdapter#log 5.10 0.01 0.01 0.00 0.01 1000 <::Notifications>#instrumenter 2.92 0.00 0.00 0.00 0.00 4000 <Class::Time>#allocate 2.73 0.02 0.00 0.00 0.01 1000 Array#each 2.57 0.03 0.00 0.00 0.03 1000 <Module::Benchmark>#ms 2.57 0.00 0.00 0.00 0.00 4000 Time#initialize 2.55 0.03 0.00 0.00 0.02 1000 Notifications::Fanout#publish 2.45 0.01 0.00 0.00 0.01 1000 LogSubscriber#call 2.37 0.01 0.00 0.00 0.01 1000 ::Fanout::Subscriber#publish 2.04 0.01 0.00 0.00 0.00 1000 LogSubscriber#logger 1.84 0.00 0.00 0.00 0.00 1000 ::Fanout#listeners_for 1.64 0.16 0.00 0.00 0.16 1 Integer#times Thursday, November 11, 2010
  134. 134. Rails 2-3-stable Thursday, November 11, 2010
  135. 135. Thread ID: 2148237740 Total: 0.051336 %self total self wait child calls name 27.00 0.03 0.01 0.00 0.01 1000 <Module::Benchmark>#realtime 23.35 0.05 0.01 0.00 0.04 1000 ::AbstractAdapter#log 11.67 0.01 0.01 0.00 0.00 2000 <Class::Time>#now 7.66 0.03 0.00 0.00 0.03 1000 <Module::Benchmark>#ms 5.37 0.00 0.00 0.00 0.00 1000 ::AbstractAdapter#log_info 5.11 0.05 0.00 0.00 0.05 1 Integer#times 4.52 0.00 0.00 0.00 0.00 2000 <Class::Time>#allocate 3.89 0.00 0.00 0.00 0.00 2000 Time#initialize 3.83 0.00 0.00 0.00 0.00 2000 Time#to_f Thursday, November 11, 2010
  136. 136. Methods in Common •<Class::Time>#now •<Class::Time>#allocate Thursday, November 11, 2010
  137. 137. Time#now Time#allocate 3.0 Beta 2-3 Stable 4000 2000 4000 2000 n = 1000 Thursday, November 11, 2010
  138. 138. http://bit.ly/omgslow Thursday, November 11, 2010
  139. 139. "It's all fixed!" Thursday, November 11, 2010
  140. 140. Wait a few hours... Thursday, November 11, 2010
  141. 141. "It's better, but still 2x slower" Thursday, November 11, 2010
  142. 142. Post.find(1) ARel.... find_by_sql() execute() log() Thursday, November 11, 2010
  143. 143. ARel.... Thursday, November 11, 2010
  144. 144. Side note: This is when Ryan told me to rewrite. Thursday, November 11, 2010
  145. 145. Superficial Improvements Thursday, November 11, 2010
  146. 146. Limited Domain / System Knowledge Thursday, November 11, 2010
  147. 147. VM Tricks Thursday, November 11, 2010
  148. 148. See Results Quickly Thursday, November 11, 2010
  149. 149. Tapers off Over Time Thursday, November 11, 2010
  150. 150. Kowledge/Improvement Time Improvements (S) System Knowledge System Impact Thursday, November 11, 2010
  151. 151. attr_* Thursday, November 11, 2010
  152. 152. def some_attribute @some_attribute end # vs attr_reader :some_attribute Thursday, November 11, 2010
  153. 153. 0 0.075 0.15 0.225 0.3 0 250000 500000 750000 1000000 y = 1.965E-7x + 0.0002 y = 2.934E-7x + 0.0009 bench_method bench_reader Thursday, November 11, 2010
  154. 154. case VM_METHOD_TYPE_IVAR: { if (argc != 0) { rb_raise(rb_eArgError, "wrong number of arguments (%d for 0)", argc); } val = rb_attr_get(recv, def->body.attr.id); break; } attr_reader Thursday, November 11, 2010
  155. 155. method call case VM_METHOD_TYPE_ISEQ: { rb_control_frame_t *reg_cfp; int i; rb_vm_set_finish_env(th); reg_cfp = th->cfp; CHECK_STACK_OVERFLOW(reg_cfp, argc + 1); *reg_cfp->sp++ = recv; for (i = 0; i < argc; i++) { *reg_cfp->sp++ = argv[i]; } vm_setup_method(th, reg_cfp, recv, argc, blockptr, 0 /* flag */, me); val = vm_exec(th); break; } Thursday, November 11, 2010
  156. 156. vm_setup_method •Check for stack overflow •Pushing a stack frame •Copying arguments Thursday, November 11, 2010
  157. 157. class Foo attr_reader :some_attribute def some_attribute? @some_attribute end end Predicate Methods Thursday, November 11, 2010
  158. 158. class Foo attr_reader :some_attribute alias :some_attribute? :some_attribute end Predicate Methods Thursday, November 11, 2010
  159. 159. Hash[] vs inject({}) Thursday, November 11, 2010
  160. 160. inject({}) some_list.inject({}) do |hash,val| hash[val] = some_transform(val) hash end Thursday, November 11, 2010
  161. 161. Hash[] values = some_list.map { |val| [val, some_transform(val)] } Hash[values] Thursday, November 11, 2010
  162. 162. @list.inject({}) do |hash,val| hash[val] = val.length hash end # vs Hash[@list.map { |val| [val,val.length] }] Thursday, November 11, 2010
  163. 163. 0 1.75 3.5 5.25 7 0 250000 500000 750000 1000000 y = 6.17E-6x - 0.0108 y = 5.268E-6x - 0.0075 Hash[] inject({}) Thursday, November 11, 2010
  164. 164. Strangeness Thursday, November 11, 2010
  165. 165. def bench_naked_each assert_performance_linear 0.999 do |n| m = nil n.times { @list.each { |v| m = v } } end end def bench_naked_inject assert_performance_linear 0.999 do |n| n.times { @list.inject { |m,v| m = v } } end end Thursday, November 11, 2010
  166. 166. 0 0.75 1.5 2.25 3 0 250000 500000 750000 1000000 y = 2.746E-6x - 0.0043 y = 1.04E-6x - 0.0016 naked each naked inject Thursday, November 11, 2010
  167. 167. TANGENT Thursday, November 11, 2010
  168. 168. When to use inject() Thursday, November 11, 2010
  169. 169. When one calculation depends on the previous Thursday, November 11, 2010
  170. 170. @list.inject({}) do |hash,val| hash[val] = val.length hash end # vs Hash[@list.map { |val| [val,val.length] }] Thursday, November 11, 2010
  171. 171. %w{ Foo Bar Baz }.inject(Object) { |klass,string| klass.const_get(string.to_sym) } Thursday, November 11, 2010
  172. 172. Proc Activation Thursday, November 11, 2010
  173. 173. lambda { ... } # vs class Callable def call; ... end end Thursday, November 11, 2010
  174. 174. 0 0.01 0.02 0.03 0.04 0 25000 50000 75000 100000 lambda method Thursday, November 11, 2010
  175. 175. is_a?(Proc) Thursday, November 11, 2010
  176. 176. respond_to?(:call) Thursday, November 11, 2010
  177. 177. class Callable def call(...) ... end end Thursday, November 11, 2010
  178. 178. define_method Thursday, November 11, 2010
  179. 179. class Foo def foo; end define_method :bar do; end class_eval %{ def baz; end } end Thursday, November 11, 2010
  180. 180. -0.15 0 0.15 0.3 0.45 0.6 0 250000 500000 750000 1000000 method class_eval define_method Thursday, November 11, 2010
  181. 181. Explicit Block Parameters Thursday, November 11, 2010
  182. 182. class Foo def explicit &block yield end def implicit yield end end Thursday, November 11, 2010
  183. 183. -3.75 0 3.75 7.5 11.25 15 0 250000 500000 750000 1000000 explicit implicit Thursday, November 11, 2010
  184. 184. def sometimes_block if block_given? Proc.new.call end end sometimes_block { puts "hi" } sometimes_block Thursday, November 11, 2010
  185. 185. Symbol to Proc Thursday, November 11, 2010
  186. 186. @list.map(&:to_i) # vs @list.map { |x| x.to_i } Thursday, November 11, 2010
  187. 187. -5 1.25 7.5 13.75 20 0 250000 500000 750000 1000000 sym to proc block form Thursday, November 11, 2010
  188. 188. -5 1.25 7.5 13.75 20 0 250000 500000 750000 1000000 symbol to proc block method Thursday, November 11, 2010
  189. 189. Know Your Audience Thursday, November 11, 2010
  190. 190. return value caching Thursday, November 11, 2010
  191. 191. def some_method @some_method ||= some_expensive_op end Thursday, November 11, 2010
  192. 192. How many times? Thursday, November 11, 2010
  193. 193. Can the caller cache? Thursday, November 11, 2010
  194. 194. Made our improvements Thursday, November 11, 2010
  195. 195. Feeling better! Thursday, November 11, 2010
  196. 196. :-D Thursday, November 11, 2010
  197. 197. 0 200000 400000 600000 800000 0 25000 50000 75000 100000 before (3.0 beta) after (3.0 beta) Rails 2.3 Thursday, November 11, 2010
  198. 198. What do we do? Thursday, November 11, 2010
  199. 199. We have to go deeper Thursday, November 11, 2010
  200. 200. $ git grep 'include Relation' | wc -l 6 $ git grep 'def bind' | wc -l 12 $ Thursday, November 11, 2010
  201. 201. Everything is_a Relation Thursday, November 11, 2010
  202. 202. Everything Responds to "bind" Thursday, November 11, 2010
  203. 203. Everything has a "relation" Thursday, November 11, 2010
  204. 204. bind() is recursively called on relation Thursday, November 11, 2010
  205. 205. How does it work? Thursday, November 11, 2010
  206. 206. Array#map 13 (0.3%) of 136 (3.6%) Class#new 632 (16.7%) of 806 (21.2%) Arel Project#initialize 60 (1.6%) of 149 (3.9%) 149 Arel Where#initialize 20 (0.5%) 37 Arel Take#initialize 32 (0.8%) 32 Arel Attribute#to_sql 14 (0.4%) of 114 (3.0%) 49 46 36 42 14 18 24 e_for 0.5%) 1.0%) Arel e#bind 2 (0.1%) (1.2%) 45 46 43 17 Thursday, November 11, 2010
  207. 207. y Integer#times 41 (1.1%) of 2720 (71.7%) Object#find 48 (1.3%) of 2718 (71.6%) 2666 Object#find_with_ids 71 (1.9%) of 2717 (71.6%) 2656 Object#find_one 28 (0.7%) of 2648 (69.8%) 2646 garbage_collector 840 (22.1%) Thursday, November 11, 2010
  208. 208. Data Structure Analysis Thursday, November 11, 2010
  209. 209. Graphviz graphviz.org Thursday, November 11, 2010
  210. 210. digraph "foo" { node [width=0.375,height=0.25]; N1 [label="hello"]; N2 [label="world"]; N1 -> N2; } Thursday, November 11, 2010
  211. 211. hello world Thursday, November 11, 2010
  212. 212. Visitor Pattern Thursday, November 11, 2010
  213. 213. class Visitor def accept(object) method = object.class.name.split('::').join('_') send("visit_#{method}", object) end end Thursday, November 11, 2010
  214. 214. class Visitor def accept(object) method = object.class.name.split('::').join('_') send("visit_#{method}", object) end def visit_Arel_Alias(node) # keep track of the node called accept(node.attribute) end end Thursday, November 11, 2010
  215. 215. class Visitor def accept(object) method = object.class.name.split('::').join('_') send("visit_#{method}", object) end def visit_Arel_Alias(node) # keep track of the node called accept(node.attribute) end def visit_Arel_Table(node) # keep track of the node called accept(node.name) node.columns.each { |c| accept(c) } end end Thursday, November 11, 2010
  216. 216. Thursday, November 11, 2010
  217. 217. Thursday, November 11, 2010
  218. 218. Linked List Thursday, November 11, 2010
  219. 219. Relation Relation Relation Relation value valuevalue value Thursday, November 11, 2010
  220. 220. Relation Relation Relation Relation value valuevalue value Thursday, November 11, 2010
  221. 221. Relation Relation Relation Relation Bind() + Dup Bind() + Dup Bind() + Dup Bind() + Dup Thursday, November 11, 2010
  222. 222. Relation Relation Relation Relation Bind() + Dup Bind() + Dup Bind() + Dup Bind() + Dup Bind() + Dup Bind() + Dup Bind() + Dup Bind() + Dup Bind() + Dup Bind() + Dup Thursday, November 11, 2010
  223. 223. Where Where Where Where 1 = 1 3 = 32 = 2 4 = 4 Thursday, November 11, 2010
  224. 224. Where Where Where Where 1 = 1 3 = 32 = 2 4 = 4 2 = 2 3 = 3 1 = 1 1 = 1 2 = 21 = 1 Thursday, November 11, 2010
  225. 225. Big O! Thursday, November 11, 2010
  226. 226. OMG Thursday, November 11, 2010
  227. 227. ZOMG Thursday, November 11, 2010
  228. 228. Mathematical Representation Thursday, November 11, 2010
  229. 229. 0 1.25 2.5 3.75 5 0 2.25 4.5 6.75 9 y = 2 Thursday, November 11, 2010
  230. 230. 0 1.25 2.5 3.75 5 1 4.5 8 11.5 15 y = log(n) Thursday, November 11, 2010
  231. 231. 0 2.25 4.5 6.75 9 0 2.25 4.5 6.75 9 y = x Thursday, November 11, 2010
  232. 232. -10 0 10 20 30 40 1 4.5 8 11.5 15 y = n log(n) Thursday, November 11, 2010
  233. 233. 0 50 100 150 200 0 3.75 7.5 11.25 15 y = n^2 Thursday, November 11, 2010
  234. 234. Finding Big O •Give input •Measure output •Plot Results Thursday, November 11, 2010
  235. 235. ARel's Big O 0 12.5 25 37.5 50 0 2.25 4.5 6.75 9 objects and funcalls Thursday, November 11, 2010
  236. 236. ARel's Big O 0 12.5 25 37.5 50 0 2.25 4.5 6.75 9 objects and funcalls Thursday, November 11, 2010
  237. 237. ARel's Big O 0 12.5 25 37.5 50 0 2.25 4.5 6.75 9 objects and funcalls Thursday, November 11, 2010
  238. 238. ARel's Big O 0 12.5 25 37.5 50 0 2.25 4.5 6.75 9 objects and funcalls Thursday, November 11, 2010
  239. 239. ARel's Big O 0 12.5 25 37.5 50 0 2.25 4.5 6.75 9 objects and funcalls Thursday, November 11, 2010
  240. 240. Thursday, November 11, 2010
  241. 241. Thursday, November 11, 2010
  242. 242. ActiveRecord/Arel takes over 2 minutes to generate a pseudo-complex SQL query. http://bit.ly/omgslow2 Thursday, November 11, 2010
  243. 243. Deep Improvements Thursday, November 11, 2010
  244. 244. Kowledge/Improvement Time Improvements (S) System Knowledge System Impact Thursday, November 11, 2010
  245. 245. AST + Visitor Thursday, November 11, 2010
  246. 246. O(n) Thursday, November 11, 2010
  247. 247. Should I rewrite? •Clear solution •Tests are numerous (Rails) •Public API is limited Thursday, November 11, 2010
  248. 248. YES Thursday, November 11, 2010
  249. 249. 6 Weeks Later... Thursday, November 11, 2010
  250. 250. ARel Today Thursday, November 11, 2010
  251. 251. Data Sheet •O(n) •6 Weeks to Rewrite •2x faster (for simple queries) •Adapter Specific code is DRY Thursday, November 11, 2010
  252. 252. flog (before) 2533.1: flog total 6.8: flog/method average 116.6: OracleCompiler#select_sql 78.0: PostgreSQLCompiler#select_sql 64.9: main#none 59.4: GenericCompiler#insert_sql 52.4: Join#joins Thursday, November 11, 2010
  253. 253. flog (after) 1864.6: flog total 6.5: flog/method average 81.4: main#none 75.9: Dot#none 59.1: Oracle# lib/arel/visitors/oracle.rb:6 54.0: ToSql#lib/arel/visitors/to_sql.rb:31 51.6: ToSql#none Thursday, November 11, 2010
  254. 254. flay (before) Total score (lower is better) = 684 12 complaints Thursday, November 11, 2010
  255. 255. flay (after) Total score (lower is better) = 420 7 complaints Thursday, November 11, 2010
  256. 256. Post.where("id = 1").to_dot Thursday, November 11, 2010
  257. 257. Arel::Nodes::SelectStatement Array cores NilClass offset limit Array orders Arel::Nodes::SelectCore 0 Arel::Table froms Array projections Array wheres String posts name Arel::Nodes::SqlLiteral "posts".* 0 Arel::Nodes::Grouping 0 Arel::Nodes::SqlLiteral id = 1 expr Thursday, November 11, 2010
  258. 258. ARel Tomorrow Thursday, November 11, 2010
  259. 259. Conclusion Thursday, November 11, 2010
  260. 260. AKA: Things I've Learned Thursday, November 11, 2010
  261. 261. Kowledge/Improvement Time Improvements (S) System Knowledge Improvements (D) System Impact Thursday, November 11, 2010
  262. 262. When Should I Rewrite? Thursday, November 11, 2010
  263. 263. Rewrite Timeline Thursday, November 11, 2010
  264. 264. Rewrite Timeline Thursday, November 11, 2010
  265. 265. We emphasize the art of Code Thursday, November 11, 2010
  266. 266. We should not forget the Science Thursday, November 11, 2010
  267. 267. Learn The Specific Thursday, November 11, 2010
  268. 268. But Embrace The Generic Thursday, November 11, 2010
  269. 269. Photo Credits • DHH: http://www.flickr.com/photos/pdcawley/250813158/ • Matz: http://www.flickr.com/photos/kakutani/4127354831/ • Chad Fowler: http://www.flickr.com/photos/fraserspeirs/ 3386558579/ Thursday, November 11, 2010
  270. 270. Thanks @ebiltwin Thursday, November 11, 2010
  271. 271. Thank you! Thursday, November 11, 2010
  272. 272. One More Thing... Thursday, November 11, 2010
  273. 273. It's RubyConf 10! Thursday, November 11, 2010
  274. 274. Give Ryan a Kiss! <3 Thursday, November 11, 2010
  275. 275. Thursday, November 11, 2010
  276. 276. ♥ Thursday, November 11, 2010
  277. 277. Questions? Thursday, November 11, 2010
  1. A particular slide catching your eye?

    Clipping is a handy way to collect important slides you want to go back to later.

×