Slide 1

Slide 1 text

( ͡ ° ͜ ʖ ͡ °) .oO(Hi)

Slide 2

Slide 2 text

ຖ೥߃ྫ$ ͷ$ ೔ຊޠೳྗࢼݧ

Slide 3

Slide 3 text

Thanks!!!

Slide 4

Slide 4 text

Aaron Patterson

Slide 5

Slide 5 text

Ϩου ϋτ

Slide 6

Slide 6 text

No content

Slide 7

Slide 7 text

No content

Slide 8

Slide 8 text

Ruby Core Rails Core

Slide 9

Slide 9 text

ί ϛ ο τ ͠ ͯ! ϙ Π ϯ τ ΋ Β ͓ ͏ ʂ

Slide 10

Slide 10 text

Revert Commits Count Too!

Slide 11

Slide 11 text

More mistakes == more points!!!!

Slide 12

Slide 12 text

ΦΨϫ͞Μ

Slide 13

Slide 13 text

ΰϒͪΌΜ

Slide 14

Slide 14 text

νϡʔνϡʔ

Slide 15

Slide 15 text

No content

Slide 16

Slide 16 text

Ϗοάσʔλ

Slide 17

Slide 17 text

ϝλϧʹ$ ۙ͘ͳΔͨΊʹ

Slide 18

Slide 18 text

Node.JS

Slide 19

Slide 19 text

No content

Slide 20

Slide 20 text

Speeding up Rails 4.2

Slide 21

Slide 21 text

ߟ͑ࣄ

Slide 22

Slide 22 text

Rack

Slide 23

Slide 23 text

΋͏ऴΘΓ

Slide 24

Slide 24 text

Rack ͸ ָ͡Όͳ͍

Slide 25

Slide 25 text

Rack 2.0 ͸ൃද͠ͳ͍* * Rack 2.0 ͸ൃද͠·͢ɻ

Slide 26

Slide 26 text

the_metal http://github.com/tenderlove/the_metal

Slide 27

Slide 27 text

def call(env) end άϩʔόϧม਺ R ack 1.x

Slide 28

Slide 28 text

ετϦʔϛϯά class Stream def each loop { yield "hello world\n" } end end $ def call(env) [200, {}, Stream.new] end R ack 1.x

Slide 29

Slide 29 text

def call(request, response) end IO IO the_m etal

Slide 30

Slide 30 text

request ͸IOͱ ϦΩΣετͷ৘ใ! Λ͍࣋ͬͯ·͢ɻ

Slide 31

Slide 31 text

response͸IOͱ Ϩεϙϯεͷ৘ใ! Λ͍࣋ͬͯ·͢ɻ

Slide 32

Slide 32 text

׬શ࣮ྫ 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'

Slide 33

Slide 33 text

Great for HTTP/1.1 Extendable to HTTP/ 2.0

Slide 34

Slide 34 text

RackΛ࢖ͬͯ ָΛ͠·͠ΐ͏

Slide 35

Slide 35 text

ߟ͑ࣄ͚ͩɻ

Slide 36

Slide 36 text

ಡΜͰԼ͍͞ʂ http://github.com/tenderlove/the_metal

Slide 37

Slide 37 text

Speeding up Rails 4.2

Slide 38

Slide 38 text

Adequate$ Record

Slide 39

Slide 39 text

Performance$ Tools

Slide 40

Slide 40 text

benchmark/ips

Slide 41

Slide 41 text

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

Slide 42

Slide 42 text

ग़ྗ 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

Slide 43

Slide 43 text

Set Include: 3047175.3 / sec

Slide 44

Slide 44 text

Array Include: 3899.2 / sec

Slide 45

Slide 45 text

IPS: Higher Is Better

Slide 46

Slide 46 text

Blackbox Testing

Slide 47

Slide 47 text

Ωϟογϡͷςετ 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

Slide 48

Slide 48 text

࣮ߦͷάϥϑ 10,000 ܁Γฦ࣌ؒ͢ (seconds) 0.01 0.1 1 10 100 ΩϟογϡɹαΠζ 10 elements 100 elements 1000 elements 100000 elements Ωϟογϡ 1 Ωϟογϡ 2

Slide 49

Slide 49 text

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 ఆ਺ ઢܗ

Slide 50

Slide 50 text

۩ମతͳྫ Routes

Slide 51

Slide 51 text

Route දͷେ͖͞͸ link_to ʹؔ܎͸͋Δʁ

Slide 52

Slide 52 text

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

Slide 53

Slide 53 text

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

Slide 54

Slide 54 text

URL ͷ௕͞͸ ࣮ߦ଎౓ʹ ؔ܎͸͋Γ·͔͢ʁ

Slide 55

Slide 55 text

௕͞ΛมԽ 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

Slide 56

Slide 56 text

ඵ / 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

Slide 57

Slide 57 text

Object Allocations

Slide 58

Slide 58 text

GC.stat()

Slide 59

Slide 59 text

߹ܭͷׂΓ౰ͯ GC.stat(:total_allocated_object)

Slide 60

Slide 60 text

۩ମతͳྫɿ Views

Slide 61

Slide 61 text

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"

Slide 62

Slide 62 text

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

Slide 63

Slide 63 text

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

Slide 64

Slide 64 text

ςετͷ݁Ռ Request ͷΦϒδΣΫτ഑ஔ 2000 2150 2300 2450 2600 4-0-stable 4-1-stable master 2000

Slide 65

Slide 65 text

Ͳ͏΍ͬͯ$ ӕΛ͔ͭ͘

Slide 66

Slide 66 text

ςετͷ݁Ռ Request ͷΦϒδΣΫτ഑ஔ 0 650 1300 1950 2600 4-0-stable 4-1-stable master

Slide 67

Slide 67 text

4-0-stable ͔Β ~19%ݮΓ·ͨ͠

Slide 68

Slide 68 text

4-1-stable ͔Β ~14%ݮΓ·ͨ͠

Slide 69

Slide 69 text

allocation_tracer https://github.com/ko1/allocation_tracer

Slide 70

Slide 70 text

ྫ ObjectSpace::AllocationTracer.trace do 1000.times { ["foo", {}] } end $ ObjectSpace::AllocationTracer.allocated_count_table

Slide 71

Slide 71 text

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}

Slide 72

Slide 72 text

Speeding up Helpers

Slide 73

Slide 73 text

Profile Request / Response

Slide 74

Slide 74 text

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

Slide 75

Slide 75 text

ActiveSupport::SafeBuffer #initialize

Slide 76

Slide 76 text

Ͳ͜Ͱ࡞ͬͨͷʁ

Slide 77

Slide 77 text

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

Slide 78

Slide 78 text

HTML Sanitization in Rails

Slide 79

Slide 79 text

Ordinary String >> x = "foo" => "foo" >> x.class => String >> x.html_safe? => false

Slide 80

Slide 80 text

SafeBuffer >> x = "foo" => "foo" >> y = x.html_safe => "foo" >> y.class => ActiveSupport::SafeBuffer >> y.html_safe? => true

Slide 81

Slide 81 text

ERB::Utils.h

Slide 82

Slide 82 text

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

Slide 83

Slide 83 text

Creates 2 Objects.

Slide 84

Slide 84 text

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

Slide 85

Slide 85 text

String SafeBuffer String

Slide 86

Slide 86 text

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

Slide 87

Slide 87 text

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

Slide 88

Slide 88 text

String String

Slide 89

Slide 89 text

~200 Allocations Per Request for /books/new

Slide 90

Slide 90 text

YMMV (Your Mileage (kilometers?) May Vary)

Slide 91

Slide 91 text

Speeding up Output

Slide 92

Slide 92 text

ERB Template <% books.each do |book| %> <%= book.name %> <% end %>

Slide 93

Slide 93 text

Compiled Template @output_buffer = output_buffer || ActionView::OutputBuffer.new;@output_buffer.safe_append='

Listing books

$ Name $ '.freeze; @books.each do |book| @output_buffer.safe_append=' '.freeze;@output_buffer.append=( book.name );@output_buffer.safe_append=' '.freeze;@output_buffer.append=( link_to 'Show', book );@output_buffer.safe_append=' td> '.freeze; end @output_buffer.safe_append=' $

Slide 94

Slide 94 text

Compiled Template @output_buffer = ActionView::OutputBuffer.new @output_buffer.safe_append=' '.freeze @output_buffer.append=( book.name ) HTML Literal

Slide 95

Slide 95 text

safe_append= class OutputBuffer def safe_append=(value) return self if value.nil? super(value.to_s) end end W hy?

Slide 96

Slide 96 text

Don’t accept nil

Slide 97

Slide 97 text

safe_append= class OutputBuffer def safe_append=(value) super(value.to_s) end end

Slide 98

Slide 98 text

safe_append= class OutputBuffer def safe_append=(value) super(value) end end

Slide 99

Slide 99 text

safe_append= class OutputBuffer def safe_append=(value) super end end

Slide 100

Slide 100 text

safe_append= class OutputBuffer end ߴ౓ͳίʔυʂ

Slide 101

Slide 101 text

Results

Slide 102

Slide 102 text

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

Slide 103

Slide 103 text

~19% reduction since 4-0-stable

Slide 104

Slide 104 text

~14% reduction since 4-1-stable

Slide 105

Slide 105 text

·ͱΊɻ

Slide 106

Slide 106 text

Eliminate Objects

Slide 107

Slide 107 text

Ұ൪଎͍ίʔυ͸ ଘࡏ͠ͳ͍ίʔυ

Slide 108

Slide 108 text

Limit Types

Slide 109

Slide 109 text

Fewer Types = Less Code

Slide 110

Slide 110 text

Less Code = Faster Code

Slide 111

Slide 111 text

Measure, measure measure measure

Slide 112

Slide 112 text

MEASURE!

Slide 113

Slide 113 text

Rails 4.2 will be the fastest ever!

Slide 114

Slide 114 text

͋Γ͕ͱ͏ʂ