Slide 1

Slide 1 text

Hello!

Slide 2

Slide 2 text

doES iT sCaLe?

Slide 3

Slide 3 text

Jubilee Year

Slide 4

Slide 4 text

Look at all the things I’m NOT doing!

Slide 5

Slide 5 text

Prologue

Slide 6

Slide 6 text

No content

Slide 7

Slide 7 text

Ruby Script

Slide 8

Slide 8 text

No content

Slide 9

Slide 9 text

But At What Cost?

Slide 10

Slide 10 text

Aaron Patterson

Slide 11

Slide 11 text

Live From Here

Slide 12

Slide 12 text

No content

Slide 13

Slide 13 text

No content

Slide 14

Slide 14 text

No content

Slide 15

Slide 15 text

No content

Slide 16

Slide 16 text

No content

Slide 17

Slide 17 text

No content

Slide 18

Slide 18 text

No content

Slide 19

Slide 19 text

I have stickers of my cat! (please say "hello")

Slide 20

Slide 20 text

@tenderlove

Slide 21

Slide 21 text

No content

Slide 22

Slide 22 text

No content

Slide 23

Slide 23 text

Other == Puns?

Slide 24

Slide 24 text

Speaking of Twitter…

Slide 25

Slide 25 text

"

Slide 26

Slide 26 text

No content

Slide 27

Slide 27 text

No content

Slide 28

Slide 28 text

No content

Slide 29

Slide 29 text

No content

Slide 30

Slide 30 text

@buritica

Slide 31

Slide 31 text

~54% useless

Slide 32

Slide 32 text

March 14, 2019

Slide 33

Slide 33 text

No content

Slide 34

Slide 34 text

No content

Slide 35

Slide 35 text

"But At What Cost?" Bot

Slide 36

Slide 36 text

Twitter: 100% Useless

Slide 37

Slide 37 text

Facepalm-er

Slide 38

Slide 38 text

Facepalm-ee

Slide 39

Slide 39 text

Response Algorithm Is it a pun? "Aaron" "But At What Cost?" Yes No

Slide 40

Slide 40 text

Let’s Practice

Slide 41

Slide 41 text

G GitHub

Slide 42

Slide 42 text

Active Job

Slide 43

Slide 43 text

No content

Slide 44

Slide 44 text

G GitHub We’re Hiring!!!!

Slide 45

Slide 45 text

No content

Slide 46

Slide 46 text

No content

Slide 47

Slide 47 text

http://git.io/sparkles

Slide 48

Slide 48 text

Ruby Core Team

Slide 49

Slide 49 text

10 Years On Ruby Core! W ow !!!

Slide 50

Slide 50 text

Rails Core Team

Slide 51

Slide 51 text

No content

Slide 52

Slide 52 text

I ❤ Ruby

Slide 53

Slide 53 text

No content

Slide 54

Slide 54 text

Just Worked™

Slide 55

Slide 55 text

No Boilerplate

Slide 56

Slide 56 text

Java (1.3?) vs Ruby List list = new ArrayList(); list.add("1"); list.add("2"); list.add("3"); Iterator iter = list.iterator(); List intList = new ArrayList(); while (iter.hasNext()) { String str = (String)iter.next(); intList.add(Integer.parseInt(str)); } list = %w{ 1 2 3 } intList = list.map { |l| l.to_i } Java Ruby

Slide 57

Slide 57 text

My First Ruby Program Serious ^

Slide 58

Slide 58 text

Never Write Infinite Loops

Slide 59

Slide 59 text

I ❤ Rails

Slide 60

Slide 60 text

No content

Slide 61

Slide 61 text

Just Worked™

Slide 62

Slide 62 text

No Boilerplate

Slide 63

Slide 63 text

Community Values

Slide 64

Slide 64 text

"I MUST WRITE RAILS!"

Slide 65

Slide 65 text

BUT AT WHAT COST?

Slide 66

Slide 66 text

-25% $114k ➡ $85k (in 2006)

Slide 67

Slide 67 text

More Companies

Slide 68

Slide 68 text

More People

Slide 69

Slide 69 text

Thank You!

Slide 70

Slide 70 text

#ENDGAME

Slide 71

Slide 71 text

No content

Slide 72

Slide 72 text

BUT AT WHAT COST?

Slide 73

Slide 73 text

No content

Slide 74

Slide 74 text

Game of Thrones

Slide 75

Slide 75 text

Dumbledore Dies

Slide 76

Slide 76 text

No content

Slide 77

Slide 77 text

Cool Performance Tips

Slide 78

Slide 78 text

No Parenthesis is Faster

Slide 79

Slide 79 text

Parens vs No Parens def foo1(bar, baz) end def foo2(bar, baz) end def foo3(bar, baz) end def foo1 bar, baz end def foo2 bar, baz end def foo3 bar, baz end Parens No Parens

Slide 80

Slide 80 text

"No code is faster than no code"

Slide 81

Slide 81 text

ruby -y

Slide 82

Slide 82 text

Parse States $ ruby --disable-gems -y with-parens.rb | wc -l 805 $ ruby --disable-gems -y without-parens.rb | wc -l 778

Slide 83

Slide 83 text

Single Quotes Are 2x Faster Than Double Quotes

Slide 84

Slide 84 text

You Have To Hit The Shift Key To Type "

Slide 85

Slide 85 text

Actual Performance Tip Rails 6!

Slide 86

Slide 86 text

Allocation Count Started GET "/users/new" for ::1 at 2019-04-30 16:45:49 -0500 Processing by UsersController#new as */* Rendering users/new.html.erb within layouts/application Rendered users/_form.html.erb (Duration: 1.4ms | Allocations: 552) Rendered users/new.html.erb within layouts/application (Duration: 1.7ms | Allocations: 640) Completed 200 OK in 6ms (Views: 5.4ms | ActiveRecord: 0.0ms | Allocations: 4140) Started GET "/users/new" for ::1 at 2019-04-30 16:47:02 -0500 Processing by UsersController#new as */* Rendering users/new.html.erb within layouts/application Rendered users/_form.html.erb (Duration: 1.4ms | Allocations: 827) Rendered users/_expensive.html.erb (Duration: 1.6ms | Allocations: 10098) Rendered users/new.html.erb within layouts/application (Duration: 4.3ms | Allocations: 11553) Completed 200 OK in 9ms (Views: 8.5ms | ActiveRecord: 0.0ms | Allocations: 15981)

Slide 87

Slide 87 text

Allocation Count Started GET "/users/new" for ::1 at 2019-04-30 16:45:49 -0500 Processing by UsersController#new as */* Rendering users/new.html.erb within layouts/application Rendered users/_form.html.erb (Duration: 1.4ms | Allocations: 552) Rendered users/new.html.erb within layouts/application (Duration: 1.7ms | Allocations: 640) Completed 200 OK in 6ms (Views: 5.4ms | ActiveRecord: 0.0ms | Allocations: 4140) Started GET "/users/new" for ::1 at 2019-04-30 16:47:02 -0500 Processing by UsersController#new as */* Rendering users/new.html.erb within layouts/application Rendered users/_form.html.erb (Duration: 1.4ms | Allocations: 827) Rendered users/_expensive.html.erb (Duration: 1.6ms | Allocations: 10098) Rendered users/new.html.erb within layouts/application (Duration: 4.3ms | Allocations: 11553) Completed 200 OK in 9ms (Views: 8.5ms | ActiveRecord: 0.0ms | Allocations: 15981)

Slide 88

Slide 88 text

Rails at GitHub

Slide 89

Slide 89 text

Template Pre-Compilation Method Name Generation

Slide 90

Slide 90 text

Template Pre- Compilation

Slide 91

Slide 91 text

Method Name Generation

Slide 92

Slide 92 text

Build a Template Renderer!

Slide 93

Slide 93 text

Rails is MVC

Slide 94

Slide 94 text

MVC Model View Controller Request

Slide 95

Slide 95 text

Modal View Controller

Slide 96

Slide 96 text

MVC Model View Controller Request Action Controller Action View Active Record

Slide 97

Slide 97 text

Action View

Slide 98

Slide 98 text

Action View Finds Templates Compiles Templates Executes Views

Slide 99

Slide 99 text

View Templates

Slide 100

Slide 100 text

ERB

Slide 101

Slide 101 text

Developed by @m_seki

Slide 102

Slide 102 text

ERB Template

New User

<%= render_form %> <%= link_to 'Back' %> new.html.erb

Slide 103

Slide 103 text

ERB Compiler require "erb" # Compile the template template = ERB.new File.read "test.html.erb" # Print the template source puts template.src # Evaluate the template puts template.result(binding) compile.rb

Slide 104

Slide 104 text

Compiled Template _erbout = +"" _erbout << "

New User

\n\n".freeze _erbout << render_form.to_s _erbout << "\n\n".freeze _erbout << link_to("Back").to_s _erbout << "\n".freeze _erbout

Slide 105

Slide 105 text

Modified Compile Script require "erb" def render_form "" end def link_to(text) "#{text}" end # Compile the template template = ERB.new File.read "test.html.erb" # Evaluate the template puts template.result(binding)

Slide 106

Slide 106 text

Compiler Output $ ruby compiler.rb

New User

Back

Slide 107

Slide 107 text

ERB Translations ERB Source Translated Ruby <%= something %> _erbout << something.to_s <% something_else %> something_else

Slide 108

Slide 108 text

Capturing Blocks
<%= capture do %> Hello! <% end %>
require "erb" def capture yield end # Compile the template template = ERB.new File.read "test.html.erb" puts template.result(binding)

Slide 109

Slide 109 text

What is the output? Hello!
Hello!
ERROR!

Slide 110

Slide 110 text

Compiled Source _erbout = +'' _erbout << "
\n ".freeze _erbout << ( capture do ).to_s _erbout << "\n Hello!\n ".freeze end _erbout << "\n
\n".freeze _erbout
<%= capture do %> Hello! <% end %>

Slide 111

Slide 111 text

Compiled Source _erbout = +'' _erbout << "
\n ".freeze _erbout << ( capture do ).to_s _erbout << "\n Hello!\n ".freeze end _erbout << "\n
\n".freeze _erbout
<%= capture do %> Hello! <% end %>

Slide 112

Slide 112 text

How does this work in Rails?

Slide 113

Slide 113 text

ERB Compiler BLOCK_EXPR = /\s*((\s+|\))do|\{)(\s*\|[^|]*\|)?\s*\Z/ def add_expression(indicator, code) flush_newline_if_pending(src) if (indicator == "==") || @escape src << "@output_buffer.safe_expr_append=" else src << "@output_buffer.append=" end if BLOCK_EXPR.match?(code) src << " " << code else src << "(" << code << ");" end end

Slide 114

Slide 114 text

ERB in Rails

Slide 115

Slide 115 text

Different ERB Flavors Original ERB ERubis ERubi

Slide 116

Slide 116 text

ERB Performance

Slide 117

Slide 117 text

Rendering Speed require "erb" require "benchmark/ips" class AaronView TEMPLATES = { } TEMPLATES["index"] = <<-eerb

Hello <%= name %>

eerb def name; "Aaron"; end def render(template) ERB.new(TEMPLATES[template]).result(binding) end end view = AaronView.new Benchmark.ips do |x| x.report("render") { view.render("index") } end

Slide 118

Slide 118 text

Rendering Speed $ ruby rendering_speed.rb Warming up -------------------------------------- render 2.696k i/100ms Calculating ------------------------------------- render 27.117k (± 5.9%) i/s - 137.496k in 5.092633s

Slide 119

Slide 119 text

Cache Compilation class AaronView TEMPLATES = { } TEMPLATES["index"] = <<-eerb

Hello <%= name %>

eerb def name; "Aaron"; end def render(template) ERB.new(TEMPLATES[template]).result(binding) end COMPILED_TEMPLATES = { } def render_compiled(template) erb = COMPILED_TEMPLATES[template] ||= ERB.new(TEMPLATES[template]) erb.result(binding) end end view = AaronView.new Benchmark.ips do |x| x.report("render") { view.render("index") } x.report("render compiled") { view.render_compiled("index") } x.compare! end

Slide 120

Slide 120 text

Cache Compilation $ ruby rendering_speed.rb Warming up -------------------------------------- render 2.709k i/100ms render compiled 6.293k i/100ms Calculating ------------------------------------- render 27.115k (± 2.6%) i/s - 138.159k in 5.098881s render compiled 63.645k (± 3.9%) i/s - 320.943k in 5.050544s Comparison: render compiled: 63645.5 i/s render: 27114.8 i/s - 2.35x slower

Slide 121

Slide 121 text

Define a Method class AaronView TEMPLATES = { } TEMPLATES["index"] = <<-eerb

Hello <%= name %>

eerb def name; "Aaron"; end def render(template) ERB.new(TEMPLATES[template]).result(binding) end COMPILED_TEMPLATES = { } def render_compiled(template) erb = COMPILED_TEMPLATES[template] ||= ERB.new(TEMPLATES[template]) erb.result(binding) end METHODS_DEFINED = { } def render_with_method(template) unless METHODS_DEFINED.key? template erb = ERB.new(TEMPLATES[template]) self.class.class_eval "def render_#{template}; #{erb.src}; end" METHODS_DEFINED[template] = true end send "render_#{template}" end end

Slide 122

Slide 122 text

Define a Method $ ruby rendering_speed.rb Warming up -------------------------------------- render 2.750k i/100ms render compiled 6.462k i/100ms render method 114.420k i/100ms Calculating ------------------------------------- render 28.389k (± 2.7%) i/s - 143.000k in 5.041158s render compiled 65.860k (± 2.4%) i/s - 329.562k in 5.006962s render method 1.477M (± 1.7%) i/s - 7.437M in 5.038304s Comparison: render method: 1476591.3 i/s render compiled: 65860.1 i/s - 22.42x slower render: 28388.6 i/s - 52.01x slower

Slide 123

Slide 123 text

Method Generation require "erb" erb_source = <<-erb

Hello <%= name %>

erb erb = ERB.new erb_source template = "index" self.class.class_eval "def render_#{template}; #{erb.src}; end" send "render_#{template}" Template Source Compile Source Define a m ethod Render the Template

Slide 124

Slide 124 text

Method Generation def render_index _erbout = +'' _erbout << "\n \n

Hello ".freeze _erbout << name.to_s _erbout << "

\n\n".freeze _erbout end Compiled Source

Slide 125

Slide 125 text

Templates Are Translated to Methods

Slide 126

Slide 126 text

Rails Template Methods

This is an inner template <% puts methods.grep(/_app/) %>

Template in Rails

Slide 127

Slide 127 text

Rails Template Methods Console Output _app_views_users_index_html_erb___4485674087862414886_70282093274980 _app_views_users__first_ja_html_erb__657974686689484881_70282053324000 _app_views_users__second_html_erb___3508242123539422948_70282053523460

Slide 128

Slide 128 text

Memory Size def render_index _erbout = +'' _erbout << "\n \n

Hello ".freeze _erbout << name.to_s _erbout << "

\n\n".freeze _erbout end require "objspace" iseq = RubyVM::InstructionSequence.of( method(:render_index)) p ObjectSpace.memsize_of iseq $ ruby test.rb 1264

Slide 129

Slide 129 text

Template Handling In Rails

Slide 130

Slide 130 text

Instance Variable Visibility

This is template Foo!

<%= @some_ivar %>

This is template Bar!

<%= @some_ivar %> _foo.html.erb _bar.html.erb

Slide 131

Slide 131 text

Compiled Templates class ActionView::Base def render_foo _erbout = +'' _erbout << "

This is template Foo!

\n".freeze _erbout << @some_ivar.to_s _erbout << "\n".freeze _erbout end def render_bar _erbout = +'' _erbout << "

This is template Barr!

\n".freeze _erbout << @some_ivar.to_s _erbout << "\n".freeze _erbout end end _foo.html.erb _bar.html.erb Same Instance Same Instance

Slide 132

Slide 132 text

Don’t use instance variables in your templates

Slide 133

Slide 133 text

"Don’t use instance variables in your templates" - Aaron

Slide 134

Slide 134 text

Instance Variable Visibility

This is template Foo!

<%= @some_ivar %>

This is template Bar!

<%= @some_ivar %> _foo.html.erb _bar.html.erb

Slide 135

Slide 135 text

Local Variables

Slide 136

Slide 136 text

Rendering With Locals <%= render "content", locals: { name: "Gorby" } %>

Slide 137

Slide 137 text

Compiling With Locals

Hello, <%= name %>

def render_content _erbout = +'' _erbout << "

\n Hello, ".freeze _erbout << name.to_s _erbout << "\n

\n".freeze _erbout end content.html.erb Compiled Method Method Call

Slide 138

Slide 138 text

Preamble With Locals

Slide 139

Slide 139 text

Compiling With Locals

Hello, <%= name %>

def render_content(locals) # Locals preamble name = locals[:name] _erbout = +'' _erbout << "

\n Hello, ".freeze _erbout << name.to_s _erbout << "\n

\n".freeze _erbout end content.html.erb Compiled Method

Slide 140

Slide 140 text

Templates Require Context <%= render "content", locals: { name: "Gorby" } %> <%= render "content" %>

Hello, <%= name %>

main.html.erb content.html.erb Method call or local variable? local variable method call

Slide 141

Slide 141 text

Templates Can’t Be Compiled In Advance* *(FORESHADOWING)

Slide 142

Slide 142 text

Compiled Too Many Times

Slide 143

Slide 143 text

Too Many Compilations <%= render "content", locals: { name: "Gorby" } %> <%= render "content", locals: { name: "Gorby", friend: "Aaron" } %> def render_content_1(locals) # Locals preamble name = locals[:name] _erbout = +'' _erbout << "

\n Hello, ".freeze _erbout << name.to_s _erbout << "\n

\n".freeze _erbout end def render_content_2(locals) # Locals preamble name = locals[:name] friend = locals[:friend] _erbout = +'' _erbout << "

\n Hello, ".freeze _erbout << name.to_s _erbout << "\n

\n".freeze _erbout end main.html.erb Compiled "content" Unique Preambles

Slide 144

Slide 144 text

"This is nice, but what should I do?"

Slide 145

Slide 145 text

Always pass the same locals to individual templates.

Slide 146

Slide 146 text

The render function

Slide 147

Slide 147 text

Finds a Template Compiles the Template Calculates a Method Name Calls the Method

Slide 148

Slide 148 text

Find a Template (from the cache) Compiled? Compile the Template Call the method Calculate a Method Name

Slide 149

Slide 149 text

Finding a Template

Slide 150

Slide 150 text

Template Rendering Depends on "Requested Format"

Slide 151

Slide 151 text

Users Controller class UsersController < ApplicationController # GET /users # GET /users.json def index @users = User.all render "index" end end $ tree app/views/users app/views/users !"" index.html.erb #"" index.xml.erb Controller app/views/users/*

Slide 152

Slide 152 text

Template Source

XML template

Users

index.xml.erb index.html.erb

Slide 153

Slide 153 text

Requests and Rendering Request Response Template Rendered curl -H 'Accept: application/xml' http:// localhost:3000/users

XML template

index.xml.erb curl http://localhost: 3000/users

Users

index.html.erb curl -H 'Accept: text/ html' http://localhost: 3000/users

Users

index.html.erb

Slide 154

Slide 154 text

Template Cache Keys • Local variables • Format • Locale • Variant (iPhone, etc)

Slide 155

Slide 155 text

Strange Render Behavior

Slide 156

Slide 156 text

Users Controller class UsersController < ApplicationController # GET /users # GET /users.json def index @users = User.all render "index" end end $ tree app/views/users app/views/users !"" _my_template.png.erb !"" _my_template.xml.erb #"" index.html.erb Controller app/views/users/*

Slide 157

Slide 157 text

Template Contents

Users

<%= render "my_template" %> I guess this is a png? index.html.erb _my_template.png.erb XML is cool! _my_template.xml.erb

Slide 158

Slide 158 text

Requests and Rendering Request Response Template Rendered curl -H 'Accept: application/xml' http://localhost:3000/users Missing XML template Error None curl -H 'Accept: text/html' http://localhost:3000/users Missing HTML partial Error None Browser Missing HTML partial Error None curl http://localhost:3000/users

Users

I guess this is a png? index.html.erb _my_template.png.erb

Slide 159

Slide 159 text

Error!!

Slide 160

Slide 160 text

Requests and Rendering Request Response Template Rendered curl -H 'Accept: application/xml' http://localhost:3000/users Missing XML template Error None curl -H 'Accept: text/html' http://localhost:3000/users Missing HTML partial Error None Browser Missing HTML partial Error None curl http://localhost: 3000/users

Users

I guess this is a png? index.html.erb _my_template.png.erb

Slide 161

Slide 161 text

We Can’t Predict

Users

<%= render "my_template" %>

Slide 162

Slide 162 text

respond_to Controller class UsersController < ApplicationController # GET /users # GET /users.json def index @users = User.all render "index" end end class UsersController < ApplicationController # GET /users # GET /users.json def index @users = User.all respond_to do |format| format.html do render "index" end end end end "Bare" render respond_to render

Slide 163

Slide 163 text

Requests and Rendering Request Response Template Rendered curl -H 'Accept: application/ xml' http://localhost:3000/ users Missing XML template Error None curl -H 'Accept: text/html' http://localhost:3000/users Missing HTML partial Error None Browser Missing HTML partial Error None curl http://localhost:3000/ users Missing HTML partial Error None

Slide 164

Slide 164 text

Context Dependent

Users

<%= render "my_template" %> class UsersController < ApplicationController # GET /users # GET /users.json def index @users = User.all render "index" end end class UsersController < ApplicationController # GET /users # GET /users.json def index @users = User.all respond_to do |format| format.html do render "index" end end end end index.html.erb

Slide 165

Slide 165 text

Templates are not "Context Free"

Slide 166

Slide 166 text

Prediction and Consistency

Slide 167

Slide 167 text

Find a Template (from the cache) Compiled? Compile the Template Call the method Calculate a Method Name Cheap! Cheap! Expensive!

Slide 168

Slide 168 text

What Method Will This Call?

Users

<%= render "my_template" %>

Users

<%= render_my_template_00011123abf %> index.html.erb translated template Calls a unique method. But what method?

Slide 169

Slide 169 text

Find a Template (from the cache) Compiled? Compile the Template Call the method Calculate a Method Name Cheap! Cheap! Expensive!

Slide 170

Slide 170 text

#SPOILER

Slide 171

Slide 171 text

Slower Production Boot (but could be eliminated by BootSnap)

Slide 172

Slide 172 text

Lower Memory

Slide 173

Slide 173 text

Faster Runtime No More "Cache Check" Penalty

Slide 174

Slide 174 text

DETOUR!

Slide 175

Slide 175 text

Three Templates
    <%= render partial: "customer", collection: customers %>
    <%= render partial: "customer", collection: customers, cached: true %>
_col.html.erb _cached_col.html.erb
  • Hello: <%= customer.name %>
  • _customer.html.erb

    Slide 176

    Slide 176 text

    Benchmark https://github.com/rails/rails/issues/35257

    Slide 177

    Slide 177 text

    Results $ be ruby render_benchmark.rb -- create_table(:customers, {:force=>true}) -> 0.0108s <#ActiveSupport::Cache::MemoryStore entries=1000, size=333893, options={}> Warming up -------------------------------------- collection render: no cache 6.000 i/100ms collection render: with cache 1.000 i/100ms Calculating ------------------------------------- collection render: no cache 65.319 (± 7.7%) i/s - 330.000 in 5.080651s collection render: with cache 11.504 (± 8.7%) i/s - 58.000 in 5.071030s Comparison: collection render: no cache: 65.3 i/s collection render: with cache: 11.5 i/s - 5.68x slower

    Slide 178

    Slide 178 text

    I was convinced the cache didn’t work

    Slide 179

    Slide 179 text

    I was convinced the cache didn’t work

    Slide 180

    Slide 180 text

    I was convinced the cache didn’t work

    Slide 181

    Slide 181 text

    I was convinced the cache didn’t work

    Slide 182

    Slide 182 text

    But, there were entries in the cache

    Slide 183

    Slide 183 text

    BUT AT WHAT COST?

    Slide 184

    Slide 184 text

    Profiled The Cache ================================== Mode: wall(1000) Samples: 4690 (0.00% miss rate) GC: 207 (4.41%) ================================== TOTAL (pct) SAMPLES (pct) FRAME 594 (12.7%) 594 (12.7%) ActiveModel::LazyAttributeHash#[] 387 (8.3%) 387 (8.3%) ActiveRecord::Transactions#update_attributes_from_transaction_state 1199 (25.6%) 246 (5.2%) ActiveSupport::Cache::Store#expanded_key 301 (6.4%) 218 (4.6%) AbstractController::Caching::Fragments#combined_fragment_cache_key 207 (4.4%) 207 (4.4%) (garbage collection) 932 (19.9%) 196 (4.2%) ActionView::CollectionCaching#collection_by_cache_keys 450 (9.6%) 181 (3.9%) ActiveSupport::Cache::Store#expanded_version

    Slide 185

    Slide 185 text

    Cache Key Calculation Was More Expensive Than Template Execution

    Slide 186

    Slide 186 text

    Cache Payoff
  • Hello: <%= customer.name %>
  • Hello: <%= customer.name %>
  • Hello: <%= customer.name %>
  • Hello: <%= customer.name %>
  • Hello: <%= customer.name %>
  • Hello: <%= customer.name %>
  • Hello: <%= customer.name %>
  • Hello: <%= customer.name %>
  • Hello: <%= customer.name %>
  • Hello: <%= customer.name %>
  • Hello: <%= customer.name %>
  • Hello: <%= customer.name %>
  • Hello: <%= customer.name %>
  • Hello: <%= customer.name %>
  • Hello: <%= customer.name %>
  • Hello: <%= customer.name %>
  • Hello: <%= customer.name %>
  • Hello: <%= customer.name %>
  • Hello: <%= customer.name %>
  • Hello: <%= customer.name %>
  • Hello: <%= customer.name %>
  • Hello: <%= customer.name %>
  • Hello: <%= customer.name %>
  • Old Template New Template

    Slide 187

    Slide 187 text

    Benchmark Results $ be ruby render_benchmark.rb -- create_table(:customers, {:force=>true}) -> 0.0075s <#ActiveSupport::Cache::MemoryStore entries=1000, size=900893, options={}> Warming up -------------------------------------- collection render: no cache 4.000 i/100ms collection render: with cache 4.000 i/100ms Calculating ------------------------------------- collection render: no cache 41.066 (± 2.4%) i/s - 208.000 in 5.070051s collection render: with cache 43.192 (± 4.6%) i/s - 216.000 in 5.012803s Comparison: collection render: with cache: 43.2 i/s collection render: no cache: 41.1 i/s - same-ish: difference falls within error

    Slide 188

    Slide 188 text

    "Cache" doesn’t mean "fast"

    Slide 189

    Slide 189 text

    Speeding Up Templates

    Slide 190

    Slide 190 text

    Template Static Analysis

    Slide 191

    Slide 191 text

    Pre-Compiling Templates https://github.com/jhawthorn/actionview_precompiler/

    Slide 192

    Slide 192 text

    ActionviewPrecompiler.precompile

    Slide 193

    Slide 193 text

    Static Analysis <%= render "no_locals" %> <%= render "static_locals", locals: { foo: bar } %> <%= render "dynamic_locals", locals: { foo: bar }.merge(baz) %> Can Precompile! Can Precompile! Nope!

    Slide 194

    Slide 194 text

    Predicting "Render" Methods

    Slide 195

    Slide 195 text

    "Same Format Assumption"

    Users

    <%= render "my_template" %> <%= render "my_template", format: :png %> $ tree app/views/users app/views/users !"" _my_template.html.erb !"" _my_template.png.erb !"" _my_template.xml.erb #"" index.html.erb index.html.erb templates

    Slide 196

    Slide 196 text

    Ambiguous Render Problem

    Users

    <%= render "my_template" %> <%= render "my_template", format: :html %> $ tree app/views/users app/views/users !"" _my_template.png.erb !"" _my_template.xml.erb #"" index.html.erb index.html.erb templates Sometimes an exception Sometimes a PNG Always an exception

    Slide 197

    Slide 197 text

    "Always Optimize"

    Users

    <%= render "my_template" %> <%= render "my_template", format: :html %>

    Users

    <%= render "my_template", format: :png %> <%= render "my_template", format: :html %> index.html.erb index.html.erb

    Slide 198

    Slide 198 text

    "Same Format Assumption"

    Users

    <%= render "my_template" %> <%= render "my_template", format: :png %> $ tree app/views/users app/views/users !"" _my_template.html.erb !"" _my_template.png.erb !"" _my_template.xml.erb #"" index.html.erb index.html.erb templates

    Slide 199

    Slide 199 text

    "Same Format Assumption"

    Users

    <%= render "my_template" %> <%= render "my_template", format: :png %>

    Users

    <%= render_my_template_html_00123abc %> <%= render_my_template_png_00123abc %> index.html.erb Optimized Template

    Slide 200

    Slide 200 text

    Ambiguous Render Problem

    Users

    <%= render "my_template" %> <%= render "my_template", format: :html %> $ tree app/views/users app/views/users !"" _my_template.png.erb !"" _my_template.xml.erb #"" index.html.erb index.html.erb templates

    Slide 201

    Slide 201 text

    Ambiguous Render Problem

    Users

    <%= render "my_template" %> <%= render "my_template", format: :html %>

    Users

    <%= render "my_template" %> <%= raise MissingTemplateError %> index.html.erb Optimized Template

    Slide 202

    Slide 202 text

    Wrap It Up

    Slide 203

    Slide 203 text

    Be "Context Free" Don’t depend on side effects

    Slide 204

    Slide 204 text

    Be Consistent

    Slide 205

    Slide 205 text

    Cache != Fast

    Slide 206

    Slide 206 text

    Benchmark First!

    Slide 207

    Slide 207 text

    Keep Building Apps!

    Slide 208

    Slide 208 text

    Thank You!!!