Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
高度なコード
Search
Sponsored
·
Your Podcast. Everywhere. Effortlessly.
Share. Educate. Inspire. Entertain. You do you. We'll handle the rest.
→
Aaron Patterson
September 22, 2014
Technology
13
1.3k
高度なコード
Aaron Patterson
September 22, 2014
Tweet
Share
More Decks by Aaron Patterson
See All by Aaron Patterson
RubyKaigi 2025: Class New, A New Approach
tenderlove
0
120
RubyKaigi Dev Meeting 2025
tenderlove
1
4.3k
Speeding up Instance Variables in Ruby 3.3
tenderlove
2
500
[Feature #20425] Speeding up delegate methods
tenderlove
3
310
RailsConf 2023
tenderlove
30
1.3k
Don't @ Me! Faster Instance Variables with Object Shapes
tenderlove
1
500
RailsConf 2022 Keynote
tenderlove
2
620
Some Assembly Required
tenderlove
1
600
HexDevs 2021
tenderlove
1
520
Other Decks in Technology
See All in Technology
15 years with Rails and DDD (AI Edition)
andrzejkrzywda
0
100
Databricks Free Edition講座 データサイエンス編
taka_aki
0
250
JuliaTokaiとしてはこれが最後かもしれない(仮) for NGK2026S
antimon2
0
130
【NGK2026S】日本株のシステムトレードに入門してみた
kazuhitotakahashi
0
250
ドキュメントからはじめる未来のソフトウェア
pkshadeck
4
2.1k
日本語テキストと音楽の対照学習の技術とその応用
lycorptech_jp
PRO
1
380
2026年はチャンキングを極める!
shibuiwilliam
8
1.7k
Digitization部 紹介資料
sansan33
PRO
1
6.7k
SREの仕事を自動化する際にやっておきたい5つのポイント
jacopen
6
1.2k
変化するコーディングエージェントとの現実的な付き合い方 〜Cursor安定択説と、ツールに依存しない「資産」〜
empitsu
3
820
GCASアップデート(202510-202601)
techniczna
0
210
ゼロから始めたFindy初のモバイルアプリ開発
grandbig
2
550
Featured
See All Featured
Leveraging Curiosity to Care for An Aging Population
cassininazir
1
150
Documentation Writing (for coders)
carmenintech
77
5.2k
Testing 201, or: Great Expectations
jmmastey
46
8k
SEOcharity - Dark patterns in SEO and UX: How to avoid them and build a more ethical web
sarafernandez
0
110
Why Mistakes Are the Best Teachers: Turning Failure into a Pathway for Growth
auna
0
48
[SF Ruby Conf 2025] Rails X
palkan
0
730
jQuery: Nuts, Bolts and Bling
dougneiner
65
8.4k
Optimizing for Happiness
mojombo
379
71k
The Limits of Empathy - UXLibs8
cassininazir
1
210
A Guide to Academic Writing Using Generative AI - A Workshop
ks91
PRO
0
190
I Don’t Have Time: Getting Over the Fear to Launch Your Podcast
jcasabona
34
2.6k
sira's awesome portfolio website redesign presentation
elsirapls
0
140
Transcript
( ͡ ° ͜ ʖ ͡ °) .oO(Hi)
ຖ߃ྫ$ ͷ$ ຊޠೳྗࢼݧ
Thanks!!!
Aaron Patterson
Ϩου ϋτ
None
None
Ruby Core Rails Core
ί ϛ ο τ ͠ ͯ! ϙ Π ϯ τ
Β ͓ ͏ ʂ
Revert Commits Count Too!
More mistakes == more points!!!!
ΦΨϫ͞Μ
ΰϒͪΌΜ
νϡʔνϡʔ
None
Ϗοάσʔλ
ϝλϧʹ$ ۙ͘ͳΔͨΊʹ
Node.JS
None
Speeding up Rails 4.2
ߟ͑ࣄ
Rack
͏ऴΘΓ
Rack ָ͡Όͳ͍
Rack 2.0 ൃද͠ͳ͍* * Rack 2.0 ൃද͠·͢ɻ
the_metal http://github.com/tenderlove/the_metal
def call(env) end άϩʔόϧม R ack 1.x
ετϦʔϛϯά class Stream def each loop { yield "hello world\n"
} end end $ def call(env) [200, {}, Stream.new] end R ack 1.x
def call(request, response) end IO IO the_m etal
request IOͱ ϦΩΣετͷใ! Λ͍࣋ͬͯ·͢ɻ
responseIOͱ Ϩεϙϯεͷใ! Λ͍࣋ͬͯ·͢ɻ
શ࣮ྫ TheMetal.create_server(->(req, res) { res.write_head 200, 'Content-Type' => 'text/plain' res.write
"Hello World\n" res.finish }).listen 9292, '0.0.0.0'
Great for HTTP/1.1 Extendable to HTTP/ 2.0
RackΛͬͯ ָΛ͠·͠ΐ͏
ߟ͑ࣄ͚ͩɻ
ಡΜͰԼ͍͞ʂ http://github.com/tenderlove/the_metal
Speeding up Rails 4.2
Adequate$ Record
Performance$ Tools
benchmark/ips
benchmark/ips require 'benchmark/ips' require 'set' $ list = ('a'..'zzzz').to_a set
= Set.new list $ Benchmark.ips do |x| x.report("set access") { set.include? "foo" } $ x.report("ary access") { list.include? "foo" } end G EM
ग़ྗ Calculating ------------------------------------- set access 68622 i/100ms ary access 395
i/100ms ------------------------------------------------- set access 3047175.3 (±12.7%) i/s - 14959596 in 5.018692s ary access 3899.2 (±7.1%) i/s - 19750 in 5.096118s ߹ ܭ IPS
Set Include: 3047175.3 / sec
Array Include: 3899.2 / sec
IPS: Higher Is Better
Blackbox Testing
Ωϟογϡͷςετ cache1 = Cache1.new cache2 = Cache2.new $ cache1["x"] =
Object.new cache2["x"] = Object.new $ Benchmark.ips do |x| x.report("cache1") { cache1["x"] } x.report("cache2") { cache2["x"] } end
࣮ߦͷάϥϑ 10,000 ܁Γฦ࣌ؒ͢ (seconds) 0.01 0.1 1 10 100 ΩϟογϡɹαΠζ
10 elements 100 elements 1000 elements 100000 elements Ωϟογϡ 1 Ωϟογϡ 2
Cacheͷ࣮ class Cache1 def initialize @cache = {} end def
[] k; @cache[k]; end def []= k,v; @cache[k] = v; end end $ class Cache2 def initialize @cache = [] end def [] k; x, = @cache.assoc(k); x; end def []= k,v; @cache << [k, v]; end end ఆ ઢܗ
۩ମతͳྫ Routes
Route දͷେ͖͞ link_to ʹؔ͋Δʁ
route ΛೖΕΔ class MyTest routes = ActionDispatch::Routing::RouteSet.new routes.draw { resources(:articles)
N.times do |num| resources num.to_s.to_sym end } end 10, 100, 1000
Sec /100k calls 9.5 9.7 9.9 10.1 10.3 1 2
3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 link_to
URL ͷ͞ ࣮ߦʹ ؔ͋Γ·͔͢ʁ
͞ΛมԽ class MyTest routes = ActionDispatch::Routing::RouteSet.new link = N.times.map(&:to_s).join '/'
$ routes.draw { get "/#{link}/:id", :as => :article, :controller => :articles, :action => :show } end 10, 100, 1000
ඵ / 10ສճͷݺͼग़͠ 9 10.5 12 13.5 15 1 2
3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 link_to
Object Allocations
GC.stat()
߹ܭͷׂΓͯ GC.stat(:total_allocated_object)
۩ମతͳྫɿ Views
Request Benchmark task :allocated_objects do app = Ko1TestApp::Application.instance app.app do_test_task(app)
env = rackenv "/books/new" do_test_task(app, env.dup) before = GC.stat :total_allocated_object TEST_CNT.times { do_test_task(app, env.dup) } after = GC.stat :total_allocated_object puts (after - before) / TEST_CNT end "/books/new"
Request Benchmark task :allocated_objects do app = Ko1TestApp::Application.instance app.app do_test_task(app)
env = rackenv "/books/new" do_test_task(app, env.dup) before = GC.stat :total_allocated_object TEST_CNT.times { do_test_task(app, env.dup) } after = GC.stat :total_allocated_object puts (after - before) / TEST_CNT end
Request Benchmark task :allocated_objects do app = Ko1TestApp::Application.instance app.app do_test_task(app)
env = rackenv "/books/new" do_test_task(app, env.dup) before = GC.stat :total_allocated_object TEST_CNT.times { do_test_task(app, env.dup) } after = GC.stat :total_allocated_object puts (after - before) / TEST_CNT end
ςετͷ݁Ռ Request ͷΦϒδΣΫτஔ 2000 2150 2300 2450 2600 4-0-stable 4-1-stable
master 2000
Ͳ͏ͬͯ$ ӕΛ͔ͭ͘
ςετͷ݁Ռ Request ͷΦϒδΣΫτஔ 0 650 1300 1950 2600 4-0-stable 4-1-stable
master
4-0-stable ͔Β ~19%ݮΓ·ͨ͠
4-1-stable ͔Β ~14%ݮΓ·ͨ͠
allocation_tracer https://github.com/ko1/allocation_tracer
ྫ ObjectSpace::AllocationTracer.trace do 1000.times { ["foo", {}] } end $
ObjectSpace::AllocationTracer.allocated_count_table
Output {:T_NONE=>0, :T_OBJECT=>0, :T_CLASS=>0, :T_MODULE=>0, :T_FLOAT=>0, :T_STRING=>1000, :T_REGEXP=>0, :T_ARRAY=>1000, :T_HASH=>1000,
:T_ZOMBIE=>0}
Speeding up Helpers
Profile Request / Response
TOTAL (pct) SAMPLES (pct) FRAME 813 (9.5%) 813 (9.5%) ActiveSupport::SafeBuffer#initialize
699 (8.1%) 350 (4.1%) block in ActiveRecord::Read#read_attribute 486 (5.7%) 298 (3.5%) ActionController::UrlFor#url_options 670 (7.8%) 274 (3.2%) ActionDispatch::Journey::Format#evaluate 773 (9.0%) 253 (2.9%) ActionDispatch#parameterize_args 1172 (13.6%) 220 (2.6%) ActiveRecord::Persistence#instantiate 213 (2.5%) 213 (2.5%) block in SQLite3::Statement#each 208 (2.4%) 208 (2.4%) ActiveSupport::SafeBuffer#html_safe? 204 (2.4%) 204 (2.4%) ActionDispatch::UrlFor#routes_generation? 245 (2.9%) 191 (2.2%) block (2 levels) in Class#class_attribute
ActiveSupport::SafeBuffer #initialize
Ͳ͜Ͱ࡞ͬͨͷʁ
Tag Options def tag_option(key, value, escape) if value.is_a?(Array) value =
escape ? safe_join(value, " ") : value.join(" ") else value = escape ? ERB::Util.h(value) : value end %(#{key}="#{value}") end
HTML Sanitization in Rails
Ordinary String >> x = "foo" => "foo" >> x.class
=> String >> x.html_safe? => false
SafeBuffer >> x = "foo" => "foo" >> y =
x.html_safe => "foo" >> y.class => ActiveSupport::SafeBuffer >> y.html_safe? => true
ERB::Utils.h
ERB::Utils.h def html_escape(s) s = s.to_s if s.html_safe? s else
s.gsub(HTML_ESCAPE_REGEXP, HTML_ESCAPE).html_safe end end
Creates 2 Objects.
Tag Options def tag_option(key, value, escape) if value.is_a?(Array) value =
escape ? safe_join(value, " ") : value.join(" ") else value = escape ? ERB::Util.h(value) : value end %(#{key}="#{value}") end
String SafeBuffer String
Extract Method def unwrapped_html_escape(s) # :nodoc: s = s.to_s if
s.html_safe? s else s.gsub(HTML_ESCAPE_REGEXP, HTML_ESCAPE) end end $ def html_escape(s) unwrapped_html_escape(s).html_safe end
Update Callers def tag_option(key, value, escape) if value.is_a?(Array) value =
escape ? safe_join(value, " ") : value.join(" ") else value = escape ? ERB::Util.unwrapped_html_escape(value) : value end %(#{key}="#{value}") end
String String
~200 Allocations Per Request for /books/new
YMMV (Your Mileage (kilometers?) May Vary)
Speeding up Output
ERB Template <% books.each do |book| %> <tr><td> <%= book.name
%> </tr></td> <% end %>
Compiled Template @output_buffer = output_buffer || ActionView::OutputBuffer.new;@output_buffer.safe_append='<h1>Listing books</h1> $ <table>
<thead> <tr> <th>Name</th> <th colspan="3"></th> </tr> </thead> $ <tbody> '.freeze; @books.each do |book| @output_buffer.safe_append=' <tr> <td>'.freeze;@output_buffer.append=( book.name );@output_buffer.safe_append='</td> <td>'.freeze;@output_buffer.append=( link_to 'Show', book );@output_buffer.safe_append='</ td> </tr> '.freeze; end @output_buffer.safe_append=' </tbody> </table> $ <br>
Compiled Template @output_buffer = ActionView::OutputBuffer.new @output_buffer.safe_append=' <tr> <td>'.freeze @output_buffer.append=( book.name
) HTML Literal
safe_append= class OutputBuffer def safe_append=(value) return self if value.nil? super(value.to_s)
end end W hy?
Don’t accept nil
safe_append= class OutputBuffer def safe_append=(value) super(value.to_s) end end
safe_append= class OutputBuffer def safe_append=(value) super(value) end end
safe_append= class OutputBuffer def safe_append=(value) super end end
safe_append= class OutputBuffer end ߴͳίʔυʂ
Results
Allocations Per Request 0 275 550 825 1100 T_STRING T_ARRAY
T_HASH T_NODE T_DATA OTHER 4-0-stable 4-1-stable master
~19% reduction since 4-0-stable
~14% reduction since 4-1-stable
·ͱΊɻ
Eliminate Objects
Ұ൪͍ίʔυ ଘࡏ͠ͳ͍ίʔυ
Limit Types
Fewer Types = Less Code
Less Code = Faster Code
Measure, measure measure measure
MEASURE!
Rails 4.2 will be the fastest ever!
͋Γ͕ͱ͏ʂ