SlideShare a Scribd company logo
1 of 52
Download to read offline
BEYOND PAGE LEVEL METRICS
Buddy Brewer 
@bbrewer 
Philip Tellis 
@bluesmoon
GITHUB 
git clone <clone url> 
https://github.com/lognormal/ 
beyond-page-metrics 
https://github.com/lognormal/ 
boomerang
WHAT DOES A PAGE LOOK LIKE ON 
THE NETWORK?
HOW DO DIFFERENT BROWSERS 
HANDLE PARALLELIZATION?
WHICH PAGE COMPONENTS 
AFFECT PERCEIVED LATENCY?
ARE ANY OF THEM SPOFS? 
• Static JavaScript files, external CSS files 
• Anything that blocks onload if you have scripts that 
run on onload
CAN’T WE GET THIS 
ALREADY? 
WHY DO WE 
NEED RUM?
San Francisco 
London 
Paris 
Gilroy 
Tellisford 
Eze
Fast 
Connections 
Slow 
Connections
Common Browsers 
Uncommon Browsers
≠
PERFORMANCE TIMING 
NAVIGATION TIMING
NAVIGATION TIMING 
AVAI LABI L ITY 
• IE >= 9 
• FF >= 7 
• Chrome >= 6 
• Opera >= 15 
• Latest Android, Blackberry, 
Opera Mobile, Chrome for 
Android, Firefox for 
Android, IE Mobile
NAVIGATION TIMING EXAMPLE 
var loadEventDuration = performance.timing.loadEventEnd - ! 
performance.timing.loadEventStart;
PERFORMANCE TIMELINE 
RESOURCE TIMING
RESOURCE TIMING AVAILABILITY 
• IE >= 10 
• Chrome 
• Opera >= 16 
• Latest Opera Mobile, Chrome for Android, IE Mobile
RESOURCE TIMING GETS US 
INTERESTING THINGS 
• Generate a complete waterfall 
https://github.com/andydavies/waterfall 
• Calculate a cache-hit-ratio per resource 
• Identify problem resources
CORS: CROSS-ORIGIN RESOURCE 
SHARING 
• Cross-domain resources only tell you start & end time 
• Timing-Allow-Origin: *
LIMITATIONS OF RESOURCE TIMING 
• Does not report resources that error out, which is one 
of the things we care about 
• Doesn’t tell you if a response is a 304 or 200
CAVEAT ABOUT TESTING 
WINDOW.PERFORMANCE 
• On Firefox 31, checking window.performance in an 
anonymous iframe throws an exception 
• So we tried: 
if (“performance” in window) {}
CAVEAT ABOUT TESTING 
WINDOW.PERFORMANCE 
• But jslint complains about that 
• So we switched to: 
if (window.hasOwnProperty(“performance")) { 
// I know right? 
}
CAVEAT ABOUT TESTING 
WINDOW.PERFORMANCE 
• Which does not work on Internet Explorer 10+!# 
• So we ended up with: 
try { 
if ("performance" in window && window.performance) 
... 
} 
catch(e) { 
// WTF 
}
MEASURING XHRS 
!! 
function instrumentXHR()! 
{! 
! var proxy_XMLHttpRequest,! 
! orig_XMLHttpRequest = window.XMLHttpRequest,! 
! readyStateMap;! if (!orig_XMLHttpRequest) {! 
! ! // Nothing to instrument! 
! ! return;! 
!! }! 
! readyStateMap = [ "uninitialized", "open", "responseStart", "domInteractive", "responseEnd" ];! !! 
// We could also inherit from window.XMLHttpRequest, but for this implementation,! 
! // we'll use composition! 
! proxy_XMLHttpRequest = function() {! 
!! ! var req, perf = { timing: {}, resource: {} }, orig_open, orig_send;! 
!! ! req = new orig_XMLHttpRequest;! 
! ! orig_open = req.open;! 
!! ! orig_send = req.send;! 
! ! req.open = function(method, url, async) {! 
! ! ! if (async) {! 
! ! ! ! req.addEventListener('readystatechange', function() {! 
! ! ! ! ! perf.timing[readyStateMap[req.readyState]] = new Date().getTime();! 
! ! ! ! }, false);! 
!! ! ! }! 
! ! ! req.addEventListener('load', function() {! 
! ! ! ! perf.timing["loadEventEnd"] = new Date().getTime();! 
! ! ! ! perf.resource.status = req.status;! 
! ! ! }, false);! 
! ! ! req.addEventListener('timeout', function() { perf.timing["timeout"] = new Date().getTime(); }, false);! 
! ! ! req.addEventListener('error', function() { perf.timing["error"] = new Date().getTime(); }, false);! 
!! ! ! req.addEventListener('abort', function() { perf.timing["abort"] = new Date().getTime(); }, false);! 
! ! ! perf.resource.name = url;! 
!! ! ! perf.resource.method = method;! 
! ! ! // call the original open method! 
! ! ! return orig_open.apply(req, arguments);! 
!! ! };! 
! ! req.send = function() {! 
!! ! ! perf.timing["requestStart"] = new Date().getTime();! 
! ! ! // call the original send method! 
! ! ! return orig_send.apply(req, arguments);! 
!! ! };! 
!! ! req.performance = perf;! 
! ! return req;! 
!! };! 
! window.XMLHttpRequest = proxy_XMLHttpRequest;! 
}
MEASURING XHRS 
!! 
function instrumentXHR 
{! 
! var proxy_XMLHttpRequest 
! orig_XMLHttpRequest 
! readyStateMap if (!orig_XMLHttpRequest 
! ! // Nothing to instrument 
! ! return 
!! }! 
! readyStateMap !! 
// We could also inherit from window.XMLHttpRequest, but for this implementation, 
! // we'll use composition 
! proxy_XMLHttpRequest 
In Short: 
Proxy XMLHttpRequest 
Capture open(),send() 
and events 
! var ! 
!! ! req 
! ! orig_open 
!! ! orig_send 
! ! req 
! ! ! 
! ! ! ! req 
! ! ! ! ! perf 
! ! ! ! 
!! ! ! 
! ! ! req 
! ! ! ! perf 
! ! ! ! perf 
! ! ! 
! ! ! req 
! ! ! req 
!! ! ! req 
! ! ! perf 
!! ! ! perf 
! ! ! 
! ! ! 
!! ! }; 
! ! req 
!! ! ! perf 
! ! ! 
! ! ! 
!! ! }; 
!! ! req 
! ! return 
!! };! 
! window.XMLHttpRequest 
}
MEASURING A SINGLE OBJECT 
var url = 'http://www.buddybrewer.com/images/buddy.png';! 
var me = performance.getEntriesByName(url)[0];! 
var timings = { ! 
loadTime: me.duration, ! 
dns: me.domainLookupEnd - me.domainLookupStart, ! 
tcp: me.connectEnd - me.connectStart, ! 
waiting: me.responseStart - me.requestStart, ! 
fetch: me.responseEnd - me.responseStart! 
}
MEASURING A COLLECTION OF 
OBJECTS 
var i, first, last, entries = performance.getEntries();! 
for (i=0; i<entries.length; i++) {! 
if (entries[i].name.indexOf('platform.twitter.com') != -1) {! 
if (first === undefined) ! 
first = entries[i];! 
if (last === undefined) ! 
last = entries[i];! 
if (entries[i].startTime < first.startTime) ! 
first = entries[i];! 
if (entries[i].responseEnd > last.responseEnd) ! 
last = entries[i];! 
}! 
}! 
console.log('Took ' + (last.responseEnd - first.startTime) + ' ms');
TIME BY INITIATOR TYPE 
function timeByInitiatorType() {! 
var type, res = performance.getEntriesByType("resource"), o = {};! 
for (var i=0;i<res.length;i++) {! 
if (o[res[i].initiatorType]) {! 
o[res[i].initiatorType].duration += res[i].duration;! 
if (res[i].duration > o[res[i].initiatorType].max) o[res[i].initiatorType].max 
= res[i].duration;! 
if (res[i].duration < o[res[i].initiatorType].min) o[res[i].initiatorType].min 
= res[i].duration;! 
o[res[i].initiatorType].resources += 1;! 
o[res[i].initiatorType].avg = o[res[i].initiatorType].duration / 
o[res[i].initiatorType].resources;! 
} else {! 
o[res[i].initiatorType] = {"duration": res[i].duration, "resources": 1, "avg": 
res[i].duration, "max": res[i].duration, "min": res[i].duration};! 
}! 
}! 
return o;! 
}
FIND THE SLOWEST RESOURCES ON 
THE PAGE 
function findSlowResources(ms, num) {! 
var res = performance.getEntriesByType("resource"), arr = [], i;! 
for (i=0; i<res.length; i++) {! 
if (res[i].duration > ms) arr.push(res[i]);! 
}! 
arr.sort(function(a,b){ return b.duration - a.duration });! 
return arr.slice(0, num);! 
}
FIND POTENTIAL SPOFS 
function findPossibleSpofs(ms) {! 
var res = performance.getEntriesByType("resource"), spofs = [];! 
for (var i=0;i<res.length;i++) {! 
var isSpof = true;! 
for (var j=0;j<res.length;j++) {! 
if (res[i].name != res[j].name && ! 
(res[j].startTime > res[i].startTime && res[j].startTime < res[i].responseEnd) ||! 
(res[j].endTime > res[i].startTime && res[j].endTime < res[i].responseEnd) ||! 
(res[j].startTime < res[i].startTime && res[j].endTime > res[i].responseEnd)) {! 
isSpof = false;! 
}! 
}! 
if (isSpof && res[i].duration > ms) spofs.push(res[i]);! 
}! 
return spofs;! 
} 
This code is just an example, however it has O(n2) complexity, which might be very slow 
running in production.
FIND SLOW HOSTS 
function findPerfByHost() {! 
var res = performance.getEntriesByType("resource"), obj={};! 
for (var i=0;i<res.length;i++) {! 
var start = res[i].name.indexOf("://")+3,! 
host = res[i].name.substring(start),! 
end = host.indexOf("/");! 
host = host.substring(0,end);! 
if (obj[host]) {! 
obj[host].resources += 1;! 
obj[host].duration += res[i].duration;! 
if (res[i].duration < obj[host].min) obj[host].min = res[i].duration;! 
if (res[i].duration > obj[host].max) obj[host].max = res[i].duration;! 
obj[host].avg = obj[host].duration / obj[host].resources;! 
}! 
else {! 
obj[host] = {"duration": res[i].duration, "min": res[i].duration, "max": res[i].duration, 
"avg": res[i].duration, "resources": 1};! 
}! 
}! 
return obj;! 
}
PERFORMANCE TIMING 
USER TIMING
USER TIMING 
AVAI LABI L ITY 
• IE >= 10 
• Chrome >= 25 
• Opera >= 15 
• Latest Opera Mobile, 
Chrome for Android, IE 
Mobile
USER TIMING EXAMPLE 
performance.mark(‘event_start');! 
! 
setTimeout(function() {! 
performance.mark('event_end');! 
performance.measure(‘time_to_event’);! 
performance.measure('event_duration','event_start',‘event_end');! 
console.log('Event took ' + ! 
performance.getEntriesByName(‘event_duration')[0].duration + ! 
' ms');! 
}, 1000);
PERFORMANCE MANAGEMENT IN 
THREE STEPS 
How Fast Am I? How Fast Should I Be? How Do I Get There?
HOW FAST SHOULD I BE?
WHAT IS A CONVERSION? 
TRACKING CONVERSIONS 
Orders 
Shares, Likes, Comments 
Page Views 
Subscriptions 
Signups 
Card Additions 
Video Plays
SPEED STRONGLY CORRELATES TO CONVERSIONS 
MEASURING THE IMPACT OF SPEED
THIS MEANS WE 
CAN MEASURE 
PATIENCE
EXAMPLE 
Time Range: 1 Month 
Median Load Time: 4.12 
Visits: 25M 
Conversion Rate: 2.71% 
Average Order: $100
SPEED INCREASES DRIVE BUSINESS IMPROVEMENTS 
CAN WE DO BETTER? 
Median Load Time: 4.12 
Total Conversion Rate: 2.71% 
Conversion Rate @ 3.0s: 4.88%
WHAT ARE WE PLAYING FOR? 
Total Conversion Rate: 2.71% 
Best Case Conversion Rate: 4.88% 
Conversion Gap: 2.32% 
Visits: 25M 
AOV: $100
(4.88% - 2.71%) * 25M * $100 = $54.25M
1 second = $54M
BUT
POTENTIAL VS REALISTIC GOALS 
100TH PERCENTILE? 
Median Load Time: 4.12 
Total Conversion Rate: 2.71% 
Conversion Rate @ 3.0s: 4.88%
REALISTIC, ITERATIVE GOALS 
Target Load Time: 4 seconds (vs 3 seconds) 
Percentile at 4 sec: 49th 
Target Percentile: 60th (vs 100th percentile) 
Percentile Gap: 11%
(4.88% - 2.71%) * (11% * 25M) * $100 = $6M
Improving from 
4.12 sec @ 50th percentile 
to 
4.0 sec @ 60th percentile 
= 
$6M / month
Thank You
ATTRIBUTIONS 
https://secure.flickr.com/photos/torkildr/3462607995 (servers) 
https://secure.flickr.com/photos/hackny/8038587477 (real users) 
https://secure.flickr.com/photos/isherwoodchris/3096255994 (NYC) 
https://secure.flickr.com/photos/motoxgirl/11972577704 (Countryside) 
https://secure.flickr.com/photos/98640399@N08/9287370881 (Fiber Optic) 
https://secure.flickr.com/photos/secretlondon/2592690167 (Acoustic Coupler) 
https://secure.flickr.com/photos/jenny-pics/2904201123 (Rum Bottle) 
https://secure.flickr.com/photos/bekathwia/2415018504 (Privacy Sweater) 
https://secure.flickr.com/photos/zigzaglens/3566054676 (Star Field)

More Related Content

What's hot

[1C1]Service Workers
[1C1]Service Workers[1C1]Service Workers
[1C1]Service WorkersNAVER D2
 
You do not need automation engineer - Sqa Days - 2015 - EN
You do not need automation engineer  - Sqa Days - 2015 - ENYou do not need automation engineer  - Sqa Days - 2015 - EN
You do not need automation engineer - Sqa Days - 2015 - ENIakiv Kramarenko
 
Service Workers for Performance
Service Workers for PerformanceService Workers for Performance
Service Workers for PerformancePatrick Meenan
 
PWA 與 Service Worker
PWA 與 Service WorkerPWA 與 Service Worker
PWA 與 Service WorkerAnna Su
 
Packaging Software, Puppet Labs Style - PuppetConf 2014
Packaging Software, Puppet Labs Style - PuppetConf 2014Packaging Software, Puppet Labs Style - PuppetConf 2014
Packaging Software, Puppet Labs Style - PuppetConf 2014Puppet
 
Making the most of your Test Suite
Making the most of your Test SuiteMaking the most of your Test Suite
Making the most of your Test Suiteericholscher
 
Real Time Event Dispatcher
Real Time Event DispatcherReal Time Event Dispatcher
Real Time Event DispatcherPeter Dietrich
 
Deploying on the cutting edge
Deploying on the cutting edgeDeploying on the cutting edge
Deploying on the cutting edgeericholscher
 
Selenide alternative in Python - Introducing Selene [SeleniumCamp 2016]
Selenide alternative in Python - Introducing Selene [SeleniumCamp 2016]Selenide alternative in Python - Introducing Selene [SeleniumCamp 2016]
Selenide alternative in Python - Introducing Selene [SeleniumCamp 2016]Iakiv Kramarenko
 
Testing Javascript with Jasmine
Testing Javascript with JasmineTesting Javascript with Jasmine
Testing Javascript with JasmineTim Tyrrell
 
Background Jobs with Resque
Background Jobs with ResqueBackground Jobs with Resque
Background Jobs with Resquehomanj
 
Trying Continuous Delivery - pyconjp 2012
Trying Continuous Delivery - pyconjp 2012Trying Continuous Delivery - pyconjp 2012
Trying Continuous Delivery - pyconjp 2012Toru Furukawa
 
Get Grulping with JavaScript Task Runners
Get Grulping with JavaScript Task RunnersGet Grulping with JavaScript Task Runners
Get Grulping with JavaScript Task RunnersMatt Gifford
 
Jasmine - why JS tests don't smell fishy
Jasmine - why JS tests don't smell fishyJasmine - why JS tests don't smell fishy
Jasmine - why JS tests don't smell fishyIgor Napierala
 
DC |> Elixir Meetup - Going off the Rails into Elixir - Dan Ivovich
DC |> Elixir Meetup - Going off the Rails into Elixir - Dan IvovichDC |> Elixir Meetup - Going off the Rails into Elixir - Dan Ivovich
DC |> Elixir Meetup - Going off the Rails into Elixir - Dan IvovichSmartLogic
 

What's hot (20)

[1C1]Service Workers
[1C1]Service Workers[1C1]Service Workers
[1C1]Service Workers
 
Palestra VCR
Palestra VCRPalestra VCR
Palestra VCR
 
You do not need automation engineer - Sqa Days - 2015 - EN
You do not need automation engineer  - Sqa Days - 2015 - ENYou do not need automation engineer  - Sqa Days - 2015 - EN
You do not need automation engineer - Sqa Days - 2015 - EN
 
Service Workers for Performance
Service Workers for PerformanceService Workers for Performance
Service Workers for Performance
 
PWA 與 Service Worker
PWA 與 Service WorkerPWA 與 Service Worker
PWA 與 Service Worker
 
Packaging Software, Puppet Labs Style - PuppetConf 2014
Packaging Software, Puppet Labs Style - PuppetConf 2014Packaging Software, Puppet Labs Style - PuppetConf 2014
Packaging Software, Puppet Labs Style - PuppetConf 2014
 
Making the most of your Test Suite
Making the most of your Test SuiteMaking the most of your Test Suite
Making the most of your Test Suite
 
Real Time Event Dispatcher
Real Time Event DispatcherReal Time Event Dispatcher
Real Time Event Dispatcher
 
Deploying on the cutting edge
Deploying on the cutting edgeDeploying on the cutting edge
Deploying on the cutting edge
 
Selenide alternative in Python - Introducing Selene [SeleniumCamp 2016]
Selenide alternative in Python - Introducing Selene [SeleniumCamp 2016]Selenide alternative in Python - Introducing Selene [SeleniumCamp 2016]
Selenide alternative in Python - Introducing Selene [SeleniumCamp 2016]
 
Php resque
Php resquePhp resque
Php resque
 
Webscraping with asyncio
Webscraping with asyncioWebscraping with asyncio
Webscraping with asyncio
 
Testing Javascript with Jasmine
Testing Javascript with JasmineTesting Javascript with Jasmine
Testing Javascript with Jasmine
 
Background Jobs with Resque
Background Jobs with ResqueBackground Jobs with Resque
Background Jobs with Resque
 
Designing net-aws-glacier
Designing net-aws-glacierDesigning net-aws-glacier
Designing net-aws-glacier
 
Trying Continuous Delivery - pyconjp 2012
Trying Continuous Delivery - pyconjp 2012Trying Continuous Delivery - pyconjp 2012
Trying Continuous Delivery - pyconjp 2012
 
Domains!
Domains!Domains!
Domains!
 
Get Grulping with JavaScript Task Runners
Get Grulping with JavaScript Task RunnersGet Grulping with JavaScript Task Runners
Get Grulping with JavaScript Task Runners
 
Jasmine - why JS tests don't smell fishy
Jasmine - why JS tests don't smell fishyJasmine - why JS tests don't smell fishy
Jasmine - why JS tests don't smell fishy
 
DC |> Elixir Meetup - Going off the Rails into Elixir - Dan Ivovich
DC |> Elixir Meetup - Going off the Rails into Elixir - Dan IvovichDC |> Elixir Meetup - Going off the Rails into Elixir - Dan Ivovich
DC |> Elixir Meetup - Going off the Rails into Elixir - Dan Ivovich
 

Similar to Beyond Page Level Metrics

FrontInBahia 2014: 10 dicas de desempenho para apps mobile híbridas
FrontInBahia 2014: 10 dicas de desempenho para apps mobile híbridasFrontInBahia 2014: 10 dicas de desempenho para apps mobile híbridas
FrontInBahia 2014: 10 dicas de desempenho para apps mobile híbridasLoiane Groner
 
Stackup New Languages Talk: Ember is for Everybody
Stackup New Languages Talk: Ember is for EverybodyStackup New Languages Talk: Ember is for Everybody
Stackup New Languages Talk: Ember is for EverybodyCory Forsyth
 
Velocity EU 2014 — Offline-first web apps
Velocity EU 2014 — Offline-first web appsVelocity EU 2014 — Offline-first web apps
Velocity EU 2014 — Offline-first web appsandrewsmatt
 
Unit Testing JavaScript Applications
Unit Testing JavaScript ApplicationsUnit Testing JavaScript Applications
Unit Testing JavaScript ApplicationsYnon Perek
 
Make BDD great again
Make BDD great againMake BDD great again
Make BDD great againYana Gusti
 
Go Concurrency
Go ConcurrencyGo Concurrency
Go Concurrencyjgrahamc
 
Callbacks, Promises, and Coroutines (oh my!): Asynchronous Programming Patter...
Callbacks, Promises, and Coroutines (oh my!): Asynchronous Programming Patter...Callbacks, Promises, and Coroutines (oh my!): Asynchronous Programming Patter...
Callbacks, Promises, and Coroutines (oh my!): Asynchronous Programming Patter...Domenic Denicola
 
Unit Testing Express Middleware
Unit Testing Express MiddlewareUnit Testing Express Middleware
Unit Testing Express MiddlewareMorris Singer
 
How to test complex SaaS applications - The family july 2014
How to test complex SaaS applications - The family july 2014How to test complex SaaS applications - The family july 2014
How to test complex SaaS applications - The family july 2014Guillaume POTIER
 
Build web application by express
Build web application by expressBuild web application by express
Build web application by expressShawn Meng
 
Functional Reactive Programming / Compositional Event Systems
Functional Reactive Programming / Compositional Event SystemsFunctional Reactive Programming / Compositional Event Systems
Functional Reactive Programming / Compositional Event SystemsLeonardo Borges
 
Future of Web Apps: Google Gears
Future of Web Apps: Google GearsFuture of Web Apps: Google Gears
Future of Web Apps: Google Gearsdion
 
An Introduction to Go
An Introduction to GoAn Introduction to Go
An Introduction to GoCloudflare
 
Matthew Eernisse, NodeJs, .toster {webdev}
Matthew Eernisse, NodeJs, .toster {webdev}Matthew Eernisse, NodeJs, .toster {webdev}
Matthew Eernisse, NodeJs, .toster {webdev}.toster
 
Load Testing with RedLine13: Or getting paid to DoS your own systems
Load Testing with RedLine13: Or getting paid to DoS your own systemsLoad Testing with RedLine13: Or getting paid to DoS your own systems
Load Testing with RedLine13: Or getting paid to DoS your own systemsJason Lotito
 

Similar to Beyond Page Level Metrics (20)

JavaScript Promise
JavaScript PromiseJavaScript Promise
JavaScript Promise
 
FrontInBahia 2014: 10 dicas de desempenho para apps mobile híbridas
FrontInBahia 2014: 10 dicas de desempenho para apps mobile híbridasFrontInBahia 2014: 10 dicas de desempenho para apps mobile híbridas
FrontInBahia 2014: 10 dicas de desempenho para apps mobile híbridas
 
Stackup New Languages Talk: Ember is for Everybody
Stackup New Languages Talk: Ember is for EverybodyStackup New Languages Talk: Ember is for Everybody
Stackup New Languages Talk: Ember is for Everybody
 
Velocity EU 2014 — Offline-first web apps
Velocity EU 2014 — Offline-first web appsVelocity EU 2014 — Offline-first web apps
Velocity EU 2014 — Offline-first web apps
 
Unit Testing JavaScript Applications
Unit Testing JavaScript ApplicationsUnit Testing JavaScript Applications
Unit Testing JavaScript Applications
 
Make BDD great again
Make BDD great againMake BDD great again
Make BDD great again
 
Go Concurrency
Go ConcurrencyGo Concurrency
Go Concurrency
 
Node.js
Node.jsNode.js
Node.js
 
Callbacks, Promises, and Coroutines (oh my!): Asynchronous Programming Patter...
Callbacks, Promises, and Coroutines (oh my!): Asynchronous Programming Patter...Callbacks, Promises, and Coroutines (oh my!): Asynchronous Programming Patter...
Callbacks, Promises, and Coroutines (oh my!): Asynchronous Programming Patter...
 
Unit Testing Express Middleware
Unit Testing Express MiddlewareUnit Testing Express Middleware
Unit Testing Express Middleware
 
How to test complex SaaS applications - The family july 2014
How to test complex SaaS applications - The family july 2014How to test complex SaaS applications - The family july 2014
How to test complex SaaS applications - The family july 2014
 
Performance patterns
Performance patternsPerformance patterns
Performance patterns
 
Build web application by express
Build web application by expressBuild web application by express
Build web application by express
 
Monitoring for the masses
Monitoring for the massesMonitoring for the masses
Monitoring for the masses
 
Functional Reactive Programming / Compositional Event Systems
Functional Reactive Programming / Compositional Event SystemsFunctional Reactive Programming / Compositional Event Systems
Functional Reactive Programming / Compositional Event Systems
 
Future of Web Apps: Google Gears
Future of Web Apps: Google GearsFuture of Web Apps: Google Gears
Future of Web Apps: Google Gears
 
NodeJS
NodeJSNodeJS
NodeJS
 
An Introduction to Go
An Introduction to GoAn Introduction to Go
An Introduction to Go
 
Matthew Eernisse, NodeJs, .toster {webdev}
Matthew Eernisse, NodeJs, .toster {webdev}Matthew Eernisse, NodeJs, .toster {webdev}
Matthew Eernisse, NodeJs, .toster {webdev}
 
Load Testing with RedLine13: Or getting paid to DoS your own systems
Load Testing with RedLine13: Or getting paid to DoS your own systemsLoad Testing with RedLine13: Or getting paid to DoS your own systems
Load Testing with RedLine13: Or getting paid to DoS your own systems
 

More from Philip Tellis

Improving D3 Performance with CANVAS and other Hacks
Improving D3 Performance with CANVAS and other HacksImproving D3 Performance with CANVAS and other Hacks
Improving D3 Performance with CANVAS and other HacksPhilip Tellis
 
Frontend Performance: Beginner to Expert to Crazy Person
Frontend Performance: Beginner to Expert to Crazy PersonFrontend Performance: Beginner to Expert to Crazy Person
Frontend Performance: Beginner to Expert to Crazy PersonPhilip Tellis
 
Frontend Performance: De débutant à Expert à Fou Furieux
Frontend Performance: De débutant à Expert à Fou FurieuxFrontend Performance: De débutant à Expert à Fou Furieux
Frontend Performance: De débutant à Expert à Fou FurieuxPhilip Tellis
 
Frontend Performance: Expert to Crazy Person
Frontend Performance: Expert to Crazy PersonFrontend Performance: Expert to Crazy Person
Frontend Performance: Expert to Crazy PersonPhilip Tellis
 
Frontend Performance: Beginner to Expert to Crazy Person (San Diego Web Perf ...
Frontend Performance: Beginner to Expert to Crazy Person (San Diego Web Perf ...Frontend Performance: Beginner to Expert to Crazy Person (San Diego Web Perf ...
Frontend Performance: Beginner to Expert to Crazy Person (San Diego Web Perf ...Philip Tellis
 
Frontend Performance: Beginner to Expert to Crazy Person
Frontend Performance: Beginner to Expert to Crazy PersonFrontend Performance: Beginner to Expert to Crazy Person
Frontend Performance: Beginner to Expert to Crazy PersonPhilip Tellis
 
Frontend Performance: Beginner to Expert to Crazy Person
Frontend Performance: Beginner to Expert to Crazy PersonFrontend Performance: Beginner to Expert to Crazy Person
Frontend Performance: Beginner to Expert to Crazy PersonPhilip Tellis
 
Frontend Performance: Beginner to Expert to Crazy Person
Frontend Performance: Beginner to Expert to Crazy PersonFrontend Performance: Beginner to Expert to Crazy Person
Frontend Performance: Beginner to Expert to Crazy PersonPhilip Tellis
 
RUM Distillation 101 -- Part I
RUM Distillation 101 -- Part IRUM Distillation 101 -- Part I
RUM Distillation 101 -- Part IPhilip Tellis
 
Improving 3rd Party Script Performance With IFrames
Improving 3rd Party Script Performance With IFramesImproving 3rd Party Script Performance With IFrames
Improving 3rd Party Script Performance With IFramesPhilip Tellis
 
Abusing JavaScript to measure Web Performance, or, "how does boomerang work?"
Abusing JavaScript to measure Web Performance, or, "how does boomerang work?"Abusing JavaScript to measure Web Performance, or, "how does boomerang work?"
Abusing JavaScript to measure Web Performance, or, "how does boomerang work?"Philip Tellis
 
The Statistics of Web Performance Analysis
The Statistics of Web Performance AnalysisThe Statistics of Web Performance Analysis
The Statistics of Web Performance AnalysisPhilip Tellis
 
Abusing JavaScript to Measure Web Performance
Abusing JavaScript to Measure Web PerformanceAbusing JavaScript to Measure Web Performance
Abusing JavaScript to Measure Web PerformancePhilip Tellis
 
Analysing network characteristics with JavaScript
Analysing network characteristics with JavaScriptAnalysing network characteristics with JavaScript
Analysing network characteristics with JavaScriptPhilip Tellis
 
A Node.JS bag of goodies for analyzing Web Traffic
A Node.JS bag of goodies for analyzing Web TrafficA Node.JS bag of goodies for analyzing Web Traffic
A Node.JS bag of goodies for analyzing Web TrafficPhilip Tellis
 
Messing with JavaScript and the DOM to measure network characteristics
Messing with JavaScript and the DOM to measure network characteristicsMessing with JavaScript and the DOM to measure network characteristics
Messing with JavaScript and the DOM to measure network characteristicsPhilip Tellis
 

More from Philip Tellis (20)

Improving D3 Performance with CANVAS and other Hacks
Improving D3 Performance with CANVAS and other HacksImproving D3 Performance with CANVAS and other Hacks
Improving D3 Performance with CANVAS and other Hacks
 
Frontend Performance: Beginner to Expert to Crazy Person
Frontend Performance: Beginner to Expert to Crazy PersonFrontend Performance: Beginner to Expert to Crazy Person
Frontend Performance: Beginner to Expert to Crazy Person
 
Frontend Performance: De débutant à Expert à Fou Furieux
Frontend Performance: De débutant à Expert à Fou FurieuxFrontend Performance: De débutant à Expert à Fou Furieux
Frontend Performance: De débutant à Expert à Fou Furieux
 
Frontend Performance: Expert to Crazy Person
Frontend Performance: Expert to Crazy PersonFrontend Performance: Expert to Crazy Person
Frontend Performance: Expert to Crazy Person
 
Frontend Performance: Beginner to Expert to Crazy Person (San Diego Web Perf ...
Frontend Performance: Beginner to Expert to Crazy Person (San Diego Web Perf ...Frontend Performance: Beginner to Expert to Crazy Person (San Diego Web Perf ...
Frontend Performance: Beginner to Expert to Crazy Person (San Diego Web Perf ...
 
Frontend Performance: Beginner to Expert to Crazy Person
Frontend Performance: Beginner to Expert to Crazy PersonFrontend Performance: Beginner to Expert to Crazy Person
Frontend Performance: Beginner to Expert to Crazy Person
 
Frontend Performance: Beginner to Expert to Crazy Person
Frontend Performance: Beginner to Expert to Crazy PersonFrontend Performance: Beginner to Expert to Crazy Person
Frontend Performance: Beginner to Expert to Crazy Person
 
Frontend Performance: Beginner to Expert to Crazy Person
Frontend Performance: Beginner to Expert to Crazy PersonFrontend Performance: Beginner to Expert to Crazy Person
Frontend Performance: Beginner to Expert to Crazy Person
 
mmm... beacons
mmm... beaconsmmm... beacons
mmm... beacons
 
RUM Distillation 101 -- Part I
RUM Distillation 101 -- Part IRUM Distillation 101 -- Part I
RUM Distillation 101 -- Part I
 
Improving 3rd Party Script Performance With IFrames
Improving 3rd Party Script Performance With IFramesImproving 3rd Party Script Performance With IFrames
Improving 3rd Party Script Performance With IFrames
 
Extending Boomerang
Extending BoomerangExtending Boomerang
Extending Boomerang
 
Abusing JavaScript to measure Web Performance, or, "how does boomerang work?"
Abusing JavaScript to measure Web Performance, or, "how does boomerang work?"Abusing JavaScript to measure Web Performance, or, "how does boomerang work?"
Abusing JavaScript to measure Web Performance, or, "how does boomerang work?"
 
The Statistics of Web Performance Analysis
The Statistics of Web Performance AnalysisThe Statistics of Web Performance Analysis
The Statistics of Web Performance Analysis
 
Abusing JavaScript to Measure Web Performance
Abusing JavaScript to Measure Web PerformanceAbusing JavaScript to Measure Web Performance
Abusing JavaScript to Measure Web Performance
 
Rum for Breakfast
Rum for BreakfastRum for Breakfast
Rum for Breakfast
 
Analysing network characteristics with JavaScript
Analysing network characteristics with JavaScriptAnalysing network characteristics with JavaScript
Analysing network characteristics with JavaScript
 
A Node.JS bag of goodies for analyzing Web Traffic
A Node.JS bag of goodies for analyzing Web TrafficA Node.JS bag of goodies for analyzing Web Traffic
A Node.JS bag of goodies for analyzing Web Traffic
 
Input sanitization
Input sanitizationInput sanitization
Input sanitization
 
Messing with JavaScript and the DOM to measure network characteristics
Messing with JavaScript and the DOM to measure network characteristicsMessing with JavaScript and the DOM to measure network characteristics
Messing with JavaScript and the DOM to measure network characteristics
 

Recently uploaded

Easier, Faster, and More Powerful – Notes Document Properties Reimagined
Easier, Faster, and More Powerful – Notes Document Properties ReimaginedEasier, Faster, and More Powerful – Notes Document Properties Reimagined
Easier, Faster, and More Powerful – Notes Document Properties Reimaginedpanagenda
 
Extensible Python: Robustness through Addition - PyCon 2024
Extensible Python: Robustness through Addition - PyCon 2024Extensible Python: Robustness through Addition - PyCon 2024
Extensible Python: Robustness through Addition - PyCon 2024Patrick Viafore
 
Tales from a Passkey Provider Progress from Awareness to Implementation.pptx
Tales from a Passkey Provider  Progress from Awareness to Implementation.pptxTales from a Passkey Provider  Progress from Awareness to Implementation.pptx
Tales from a Passkey Provider Progress from Awareness to Implementation.pptxFIDO Alliance
 
Linux Foundation Edge _ Overview of FDO Software Components _ Randy at Intel.pdf
Linux Foundation Edge _ Overview of FDO Software Components _ Randy at Intel.pdfLinux Foundation Edge _ Overview of FDO Software Components _ Randy at Intel.pdf
Linux Foundation Edge _ Overview of FDO Software Components _ Randy at Intel.pdfFIDO Alliance
 
WebAssembly is Key to Better LLM Performance
WebAssembly is Key to Better LLM PerformanceWebAssembly is Key to Better LLM Performance
WebAssembly is Key to Better LLM PerformanceSamy Fodil
 
Design Guidelines for Passkeys 2024.pptx
Design Guidelines for Passkeys 2024.pptxDesign Guidelines for Passkeys 2024.pptx
Design Guidelines for Passkeys 2024.pptxFIDO Alliance
 
Harnessing Passkeys in the Battle Against AI-Powered Cyber Threats.pptx
Harnessing Passkeys in the Battle Against AI-Powered Cyber Threats.pptxHarnessing Passkeys in the Battle Against AI-Powered Cyber Threats.pptx
Harnessing Passkeys in the Battle Against AI-Powered Cyber Threats.pptxFIDO Alliance
 
Portal Kombat : extension du réseau de propagande russe
Portal Kombat : extension du réseau de propagande russePortal Kombat : extension du réseau de propagande russe
Portal Kombat : extension du réseau de propagande russe中 央社
 
How Red Hat Uses FDO in Device Lifecycle _ Costin and Vitaliy at Red Hat.pdf
How Red Hat Uses FDO in Device Lifecycle _ Costin and Vitaliy at Red Hat.pdfHow Red Hat Uses FDO in Device Lifecycle _ Costin and Vitaliy at Red Hat.pdf
How Red Hat Uses FDO in Device Lifecycle _ Costin and Vitaliy at Red Hat.pdfFIDO Alliance
 
WebRTC and SIP not just audio and video @ OpenSIPS 2024
WebRTC and SIP not just audio and video @ OpenSIPS 2024WebRTC and SIP not just audio and video @ OpenSIPS 2024
WebRTC and SIP not just audio and video @ OpenSIPS 2024Lorenzo Miniero
 
ADP Passwordless Journey Case Study.pptx
ADP Passwordless Journey Case Study.pptxADP Passwordless Journey Case Study.pptx
ADP Passwordless Journey Case Study.pptxFIDO Alliance
 
Where to Learn More About FDO _ Richard at FIDO Alliance.pdf
Where to Learn More About FDO _ Richard at FIDO Alliance.pdfWhere to Learn More About FDO _ Richard at FIDO Alliance.pdf
Where to Learn More About FDO _ Richard at FIDO Alliance.pdfFIDO Alliance
 
Secure Zero Touch enabled Edge compute with Dell NativeEdge via FDO _ Brad at...
Secure Zero Touch enabled Edge compute with Dell NativeEdge via FDO _ Brad at...Secure Zero Touch enabled Edge compute with Dell NativeEdge via FDO _ Brad at...
Secure Zero Touch enabled Edge compute with Dell NativeEdge via FDO _ Brad at...FIDO Alliance
 
ASRock Industrial FDO Solutions in Action for Industrial Edge AI _ Kenny at A...
ASRock Industrial FDO Solutions in Action for Industrial Edge AI _ Kenny at A...ASRock Industrial FDO Solutions in Action for Industrial Edge AI _ Kenny at A...
ASRock Industrial FDO Solutions in Action for Industrial Edge AI _ Kenny at A...FIDO Alliance
 
Event-Driven Architecture Masterclass: Engineering a Robust, High-performance...
Event-Driven Architecture Masterclass: Engineering a Robust, High-performance...Event-Driven Architecture Masterclass: Engineering a Robust, High-performance...
Event-Driven Architecture Masterclass: Engineering a Robust, High-performance...ScyllaDB
 
Google I/O Extended 2024 Warsaw
Google I/O Extended 2024 WarsawGoogle I/O Extended 2024 Warsaw
Google I/O Extended 2024 WarsawGDSC PJATK
 
Your enemies use GenAI too - staying ahead of fraud with Neo4j
Your enemies use GenAI too - staying ahead of fraud with Neo4jYour enemies use GenAI too - staying ahead of fraud with Neo4j
Your enemies use GenAI too - staying ahead of fraud with Neo4jNeo4j
 
The Metaverse: Are We There Yet?
The  Metaverse:    Are   We  There  Yet?The  Metaverse:    Are   We  There  Yet?
The Metaverse: Are We There Yet?Mark Billinghurst
 
The Value of Certifying Products for FDO _ Paul at FIDO Alliance.pdf
The Value of Certifying Products for FDO _ Paul at FIDO Alliance.pdfThe Value of Certifying Products for FDO _ Paul at FIDO Alliance.pdf
The Value of Certifying Products for FDO _ Paul at FIDO Alliance.pdfFIDO Alliance
 
Working together SRE & Platform Engineering
Working together SRE & Platform EngineeringWorking together SRE & Platform Engineering
Working together SRE & Platform EngineeringMarcus Vechiato
 

Recently uploaded (20)

Easier, Faster, and More Powerful – Notes Document Properties Reimagined
Easier, Faster, and More Powerful – Notes Document Properties ReimaginedEasier, Faster, and More Powerful – Notes Document Properties Reimagined
Easier, Faster, and More Powerful – Notes Document Properties Reimagined
 
Extensible Python: Robustness through Addition - PyCon 2024
Extensible Python: Robustness through Addition - PyCon 2024Extensible Python: Robustness through Addition - PyCon 2024
Extensible Python: Robustness through Addition - PyCon 2024
 
Tales from a Passkey Provider Progress from Awareness to Implementation.pptx
Tales from a Passkey Provider  Progress from Awareness to Implementation.pptxTales from a Passkey Provider  Progress from Awareness to Implementation.pptx
Tales from a Passkey Provider Progress from Awareness to Implementation.pptx
 
Linux Foundation Edge _ Overview of FDO Software Components _ Randy at Intel.pdf
Linux Foundation Edge _ Overview of FDO Software Components _ Randy at Intel.pdfLinux Foundation Edge _ Overview of FDO Software Components _ Randy at Intel.pdf
Linux Foundation Edge _ Overview of FDO Software Components _ Randy at Intel.pdf
 
WebAssembly is Key to Better LLM Performance
WebAssembly is Key to Better LLM PerformanceWebAssembly is Key to Better LLM Performance
WebAssembly is Key to Better LLM Performance
 
Design Guidelines for Passkeys 2024.pptx
Design Guidelines for Passkeys 2024.pptxDesign Guidelines for Passkeys 2024.pptx
Design Guidelines for Passkeys 2024.pptx
 
Harnessing Passkeys in the Battle Against AI-Powered Cyber Threats.pptx
Harnessing Passkeys in the Battle Against AI-Powered Cyber Threats.pptxHarnessing Passkeys in the Battle Against AI-Powered Cyber Threats.pptx
Harnessing Passkeys in the Battle Against AI-Powered Cyber Threats.pptx
 
Portal Kombat : extension du réseau de propagande russe
Portal Kombat : extension du réseau de propagande russePortal Kombat : extension du réseau de propagande russe
Portal Kombat : extension du réseau de propagande russe
 
How Red Hat Uses FDO in Device Lifecycle _ Costin and Vitaliy at Red Hat.pdf
How Red Hat Uses FDO in Device Lifecycle _ Costin and Vitaliy at Red Hat.pdfHow Red Hat Uses FDO in Device Lifecycle _ Costin and Vitaliy at Red Hat.pdf
How Red Hat Uses FDO in Device Lifecycle _ Costin and Vitaliy at Red Hat.pdf
 
WebRTC and SIP not just audio and video @ OpenSIPS 2024
WebRTC and SIP not just audio and video @ OpenSIPS 2024WebRTC and SIP not just audio and video @ OpenSIPS 2024
WebRTC and SIP not just audio and video @ OpenSIPS 2024
 
ADP Passwordless Journey Case Study.pptx
ADP Passwordless Journey Case Study.pptxADP Passwordless Journey Case Study.pptx
ADP Passwordless Journey Case Study.pptx
 
Where to Learn More About FDO _ Richard at FIDO Alliance.pdf
Where to Learn More About FDO _ Richard at FIDO Alliance.pdfWhere to Learn More About FDO _ Richard at FIDO Alliance.pdf
Where to Learn More About FDO _ Richard at FIDO Alliance.pdf
 
Secure Zero Touch enabled Edge compute with Dell NativeEdge via FDO _ Brad at...
Secure Zero Touch enabled Edge compute with Dell NativeEdge via FDO _ Brad at...Secure Zero Touch enabled Edge compute with Dell NativeEdge via FDO _ Brad at...
Secure Zero Touch enabled Edge compute with Dell NativeEdge via FDO _ Brad at...
 
ASRock Industrial FDO Solutions in Action for Industrial Edge AI _ Kenny at A...
ASRock Industrial FDO Solutions in Action for Industrial Edge AI _ Kenny at A...ASRock Industrial FDO Solutions in Action for Industrial Edge AI _ Kenny at A...
ASRock Industrial FDO Solutions in Action for Industrial Edge AI _ Kenny at A...
 
Event-Driven Architecture Masterclass: Engineering a Robust, High-performance...
Event-Driven Architecture Masterclass: Engineering a Robust, High-performance...Event-Driven Architecture Masterclass: Engineering a Robust, High-performance...
Event-Driven Architecture Masterclass: Engineering a Robust, High-performance...
 
Google I/O Extended 2024 Warsaw
Google I/O Extended 2024 WarsawGoogle I/O Extended 2024 Warsaw
Google I/O Extended 2024 Warsaw
 
Your enemies use GenAI too - staying ahead of fraud with Neo4j
Your enemies use GenAI too - staying ahead of fraud with Neo4jYour enemies use GenAI too - staying ahead of fraud with Neo4j
Your enemies use GenAI too - staying ahead of fraud with Neo4j
 
The Metaverse: Are We There Yet?
The  Metaverse:    Are   We  There  Yet?The  Metaverse:    Are   We  There  Yet?
The Metaverse: Are We There Yet?
 
The Value of Certifying Products for FDO _ Paul at FIDO Alliance.pdf
The Value of Certifying Products for FDO _ Paul at FIDO Alliance.pdfThe Value of Certifying Products for FDO _ Paul at FIDO Alliance.pdf
The Value of Certifying Products for FDO _ Paul at FIDO Alliance.pdf
 
Working together SRE & Platform Engineering
Working together SRE & Platform EngineeringWorking together SRE & Platform Engineering
Working together SRE & Platform Engineering
 

Beyond Page Level Metrics

  • 2. Buddy Brewer @bbrewer Philip Tellis @bluesmoon
  • 3. GITHUB git clone <clone url> https://github.com/lognormal/ beyond-page-metrics https://github.com/lognormal/ boomerang
  • 4. WHAT DOES A PAGE LOOK LIKE ON THE NETWORK?
  • 5. HOW DO DIFFERENT BROWSERS HANDLE PARALLELIZATION?
  • 6. WHICH PAGE COMPONENTS AFFECT PERCEIVED LATENCY?
  • 7. ARE ANY OF THEM SPOFS? • Static JavaScript files, external CSS files • Anything that blocks onload if you have scripts that run on onload
  • 8. CAN’T WE GET THIS ALREADY? WHY DO WE NEED RUM?
  • 9. San Francisco London Paris Gilroy Tellisford Eze
  • 10. Fast Connections Slow Connections
  • 12.
  • 14. NAVIGATION TIMING AVAI LABI L ITY • IE >= 9 • FF >= 7 • Chrome >= 6 • Opera >= 15 • Latest Android, Blackberry, Opera Mobile, Chrome for Android, Firefox for Android, IE Mobile
  • 15. NAVIGATION TIMING EXAMPLE var loadEventDuration = performance.timing.loadEventEnd - ! performance.timing.loadEventStart;
  • 17. RESOURCE TIMING AVAILABILITY • IE >= 10 • Chrome • Opera >= 16 • Latest Opera Mobile, Chrome for Android, IE Mobile
  • 18. RESOURCE TIMING GETS US INTERESTING THINGS • Generate a complete waterfall https://github.com/andydavies/waterfall • Calculate a cache-hit-ratio per resource • Identify problem resources
  • 19. CORS: CROSS-ORIGIN RESOURCE SHARING • Cross-domain resources only tell you start & end time • Timing-Allow-Origin: *
  • 20. LIMITATIONS OF RESOURCE TIMING • Does not report resources that error out, which is one of the things we care about • Doesn’t tell you if a response is a 304 or 200
  • 21. CAVEAT ABOUT TESTING WINDOW.PERFORMANCE • On Firefox 31, checking window.performance in an anonymous iframe throws an exception • So we tried: if (“performance” in window) {}
  • 22. CAVEAT ABOUT TESTING WINDOW.PERFORMANCE • But jslint complains about that • So we switched to: if (window.hasOwnProperty(“performance")) { // I know right? }
  • 23. CAVEAT ABOUT TESTING WINDOW.PERFORMANCE • Which does not work on Internet Explorer 10+!# • So we ended up with: try { if ("performance" in window && window.performance) ... } catch(e) { // WTF }
  • 24. MEASURING XHRS !! function instrumentXHR()! {! ! var proxy_XMLHttpRequest,! ! orig_XMLHttpRequest = window.XMLHttpRequest,! ! readyStateMap;! if (!orig_XMLHttpRequest) {! ! ! // Nothing to instrument! ! ! return;! !! }! ! readyStateMap = [ "uninitialized", "open", "responseStart", "domInteractive", "responseEnd" ];! !! // We could also inherit from window.XMLHttpRequest, but for this implementation,! ! // we'll use composition! ! proxy_XMLHttpRequest = function() {! !! ! var req, perf = { timing: {}, resource: {} }, orig_open, orig_send;! !! ! req = new orig_XMLHttpRequest;! ! ! orig_open = req.open;! !! ! orig_send = req.send;! ! ! req.open = function(method, url, async) {! ! ! ! if (async) {! ! ! ! ! req.addEventListener('readystatechange', function() {! ! ! ! ! ! perf.timing[readyStateMap[req.readyState]] = new Date().getTime();! ! ! ! ! }, false);! !! ! ! }! ! ! ! req.addEventListener('load', function() {! ! ! ! ! perf.timing["loadEventEnd"] = new Date().getTime();! ! ! ! ! perf.resource.status = req.status;! ! ! ! }, false);! ! ! ! req.addEventListener('timeout', function() { perf.timing["timeout"] = new Date().getTime(); }, false);! ! ! ! req.addEventListener('error', function() { perf.timing["error"] = new Date().getTime(); }, false);! !! ! ! req.addEventListener('abort', function() { perf.timing["abort"] = new Date().getTime(); }, false);! ! ! ! perf.resource.name = url;! !! ! ! perf.resource.method = method;! ! ! ! // call the original open method! ! ! ! return orig_open.apply(req, arguments);! !! ! };! ! ! req.send = function() {! !! ! ! perf.timing["requestStart"] = new Date().getTime();! ! ! ! // call the original send method! ! ! ! return orig_send.apply(req, arguments);! !! ! };! !! ! req.performance = perf;! ! ! return req;! !! };! ! window.XMLHttpRequest = proxy_XMLHttpRequest;! }
  • 25. MEASURING XHRS !! function instrumentXHR {! ! var proxy_XMLHttpRequest ! orig_XMLHttpRequest ! readyStateMap if (!orig_XMLHttpRequest ! ! // Nothing to instrument ! ! return !! }! ! readyStateMap !! // We could also inherit from window.XMLHttpRequest, but for this implementation, ! // we'll use composition ! proxy_XMLHttpRequest In Short: Proxy XMLHttpRequest Capture open(),send() and events ! var ! !! ! req ! ! orig_open !! ! orig_send ! ! req ! ! ! ! ! ! ! req ! ! ! ! ! perf ! ! ! ! !! ! ! ! ! ! req ! ! ! ! perf ! ! ! ! perf ! ! ! ! ! ! req ! ! ! req !! ! ! req ! ! ! perf !! ! ! perf ! ! ! ! ! ! !! ! }; ! ! req !! ! ! perf ! ! ! ! ! ! !! ! }; !! ! req ! ! return !! };! ! window.XMLHttpRequest }
  • 26. MEASURING A SINGLE OBJECT var url = 'http://www.buddybrewer.com/images/buddy.png';! var me = performance.getEntriesByName(url)[0];! var timings = { ! loadTime: me.duration, ! dns: me.domainLookupEnd - me.domainLookupStart, ! tcp: me.connectEnd - me.connectStart, ! waiting: me.responseStart - me.requestStart, ! fetch: me.responseEnd - me.responseStart! }
  • 27. MEASURING A COLLECTION OF OBJECTS var i, first, last, entries = performance.getEntries();! for (i=0; i<entries.length; i++) {! if (entries[i].name.indexOf('platform.twitter.com') != -1) {! if (first === undefined) ! first = entries[i];! if (last === undefined) ! last = entries[i];! if (entries[i].startTime < first.startTime) ! first = entries[i];! if (entries[i].responseEnd > last.responseEnd) ! last = entries[i];! }! }! console.log('Took ' + (last.responseEnd - first.startTime) + ' ms');
  • 28. TIME BY INITIATOR TYPE function timeByInitiatorType() {! var type, res = performance.getEntriesByType("resource"), o = {};! for (var i=0;i<res.length;i++) {! if (o[res[i].initiatorType]) {! o[res[i].initiatorType].duration += res[i].duration;! if (res[i].duration > o[res[i].initiatorType].max) o[res[i].initiatorType].max = res[i].duration;! if (res[i].duration < o[res[i].initiatorType].min) o[res[i].initiatorType].min = res[i].duration;! o[res[i].initiatorType].resources += 1;! o[res[i].initiatorType].avg = o[res[i].initiatorType].duration / o[res[i].initiatorType].resources;! } else {! o[res[i].initiatorType] = {"duration": res[i].duration, "resources": 1, "avg": res[i].duration, "max": res[i].duration, "min": res[i].duration};! }! }! return o;! }
  • 29. FIND THE SLOWEST RESOURCES ON THE PAGE function findSlowResources(ms, num) {! var res = performance.getEntriesByType("resource"), arr = [], i;! for (i=0; i<res.length; i++) {! if (res[i].duration > ms) arr.push(res[i]);! }! arr.sort(function(a,b){ return b.duration - a.duration });! return arr.slice(0, num);! }
  • 30. FIND POTENTIAL SPOFS function findPossibleSpofs(ms) {! var res = performance.getEntriesByType("resource"), spofs = [];! for (var i=0;i<res.length;i++) {! var isSpof = true;! for (var j=0;j<res.length;j++) {! if (res[i].name != res[j].name && ! (res[j].startTime > res[i].startTime && res[j].startTime < res[i].responseEnd) ||! (res[j].endTime > res[i].startTime && res[j].endTime < res[i].responseEnd) ||! (res[j].startTime < res[i].startTime && res[j].endTime > res[i].responseEnd)) {! isSpof = false;! }! }! if (isSpof && res[i].duration > ms) spofs.push(res[i]);! }! return spofs;! } This code is just an example, however it has O(n2) complexity, which might be very slow running in production.
  • 31. FIND SLOW HOSTS function findPerfByHost() {! var res = performance.getEntriesByType("resource"), obj={};! for (var i=0;i<res.length;i++) {! var start = res[i].name.indexOf("://")+3,! host = res[i].name.substring(start),! end = host.indexOf("/");! host = host.substring(0,end);! if (obj[host]) {! obj[host].resources += 1;! obj[host].duration += res[i].duration;! if (res[i].duration < obj[host].min) obj[host].min = res[i].duration;! if (res[i].duration > obj[host].max) obj[host].max = res[i].duration;! obj[host].avg = obj[host].duration / obj[host].resources;! }! else {! obj[host] = {"duration": res[i].duration, "min": res[i].duration, "max": res[i].duration, "avg": res[i].duration, "resources": 1};! }! }! return obj;! }
  • 33. USER TIMING AVAI LABI L ITY • IE >= 10 • Chrome >= 25 • Opera >= 15 • Latest Opera Mobile, Chrome for Android, IE Mobile
  • 34. USER TIMING EXAMPLE performance.mark(‘event_start');! ! setTimeout(function() {! performance.mark('event_end');! performance.measure(‘time_to_event’);! performance.measure('event_duration','event_start',‘event_end');! console.log('Event took ' + ! performance.getEntriesByName(‘event_duration')[0].duration + ! ' ms');! }, 1000);
  • 35. PERFORMANCE MANAGEMENT IN THREE STEPS How Fast Am I? How Fast Should I Be? How Do I Get There?
  • 37. WHAT IS A CONVERSION? TRACKING CONVERSIONS Orders Shares, Likes, Comments Page Views Subscriptions Signups Card Additions Video Plays
  • 38. SPEED STRONGLY CORRELATES TO CONVERSIONS MEASURING THE IMPACT OF SPEED
  • 39. THIS MEANS WE CAN MEASURE PATIENCE
  • 40. EXAMPLE Time Range: 1 Month Median Load Time: 4.12 Visits: 25M Conversion Rate: 2.71% Average Order: $100
  • 41. SPEED INCREASES DRIVE BUSINESS IMPROVEMENTS CAN WE DO BETTER? Median Load Time: 4.12 Total Conversion Rate: 2.71% Conversion Rate @ 3.0s: 4.88%
  • 42. WHAT ARE WE PLAYING FOR? Total Conversion Rate: 2.71% Best Case Conversion Rate: 4.88% Conversion Gap: 2.32% Visits: 25M AOV: $100
  • 43. (4.88% - 2.71%) * 25M * $100 = $54.25M
  • 44. 1 second = $54M
  • 45. BUT
  • 46. POTENTIAL VS REALISTIC GOALS 100TH PERCENTILE? Median Load Time: 4.12 Total Conversion Rate: 2.71% Conversion Rate @ 3.0s: 4.88%
  • 47. REALISTIC, ITERATIVE GOALS Target Load Time: 4 seconds (vs 3 seconds) Percentile at 4 sec: 49th Target Percentile: 60th (vs 100th percentile) Percentile Gap: 11%
  • 48. (4.88% - 2.71%) * (11% * 25M) * $100 = $6M
  • 49. Improving from 4.12 sec @ 50th percentile to 4.0 sec @ 60th percentile = $6M / month
  • 50.
  • 52. ATTRIBUTIONS https://secure.flickr.com/photos/torkildr/3462607995 (servers) https://secure.flickr.com/photos/hackny/8038587477 (real users) https://secure.flickr.com/photos/isherwoodchris/3096255994 (NYC) https://secure.flickr.com/photos/motoxgirl/11972577704 (Countryside) https://secure.flickr.com/photos/98640399@N08/9287370881 (Fiber Optic) https://secure.flickr.com/photos/secretlondon/2592690167 (Acoustic Coupler) https://secure.flickr.com/photos/jenny-pics/2904201123 (Rum Bottle) https://secure.flickr.com/photos/bekathwia/2415018504 (Privacy Sweater) https://secure.flickr.com/photos/zigzaglens/3566054676 (Star Field)