Slide 1

Slide 1 text

Boomerang: Measuring Web Performance with JavaScript Philip Tellis / [email protected] Stockholm #WebPerf Meetup / 2014-10-30 Stockholm #WebPerf Meetup / 2014-10-30 Boomerang: Measuring Web Performance with JavaScript 1

Slide 2

Slide 2 text

• Philip Tellis • @bluesmoon • [email protected] • SOASTA • boomerang Stockholm #WebPerf Meetup / 2014-10-30 Boomerang: Measuring Web Performance with JavaScript 2

Slide 3

Slide 3 text

I <3 JavaScript Stockholm #WebPerf Meetup / 2014-10-30 Boomerang: Measuring Web Performance with JavaScript 3

Slide 4

Slide 4 text

I’m a Speedfreak (the network kind) Stockholm #WebPerf Meetup / 2014-10-30 Boomerang: Measuring Web Performance with JavaScript 4

Slide 5

Slide 5 text

SOASTA mPulse & boomerang We measure real user website performance Stockholm #WebPerf Meetup / 2014-10-30 Boomerang: Measuring Web Performance with JavaScript 5

Slide 6

Slide 6 text

This talk is (mostly) about how we abuse JavaScript to do it Stockholm #WebPerf Meetup / 2014-10-30 Boomerang: Measuring Web Performance with JavaScript 6

Slide 7

Slide 7 text

First, a note about the code Note that in the code that follows, + new Date is equivalent to new Date().getTime() Stockholm #WebPerf Meetup / 2014-10-30 Boomerang: Measuring Web Performance with JavaScript 7

Slide 8

Slide 8 text

1 Latency Stockholm #WebPerf Meetup / 2014-10-30 Boomerang: Measuring Web Performance with JavaScript 8

Slide 9

Slide 9 text

Sort in ascending order of signal latency • Electrons through copper • Light through fibre • Pulsars • Station Wagons • Smoke Signals Stockholm #WebPerf Meetup / 2014-10-30 Boomerang: Measuring Web Performance with JavaScript 9

Slide 10

Slide 10 text

Sort in ascending order of signal latency 1 Pulsars (light through vacuum) 2 Smoke Signals (light through air) 3 Electrons through copper / Light through fibre 4 Station Wagons (possibly highest bandwidth) Stockholm #WebPerf Meetup / 2014-10-30 Boomerang: Measuring Web Performance with JavaScript 10

Slide 11

Slide 11 text

1 Blinking Lights It takes about 16ms for light to get from SF to NYC (24ms through fibre) . . . Stockholm #WebPerf Meetup / 2014-10-30 Boomerang: Measuring Web Performance with JavaScript 11

Slide 12

Slide 12 text

1 Blinking Lights It takes about 16ms for light to get from SF to NYC (24ms through fibre) Though it takes about 100ms to ping... why? Stockholm #WebPerf Meetup / 2014-10-30 Boomerang: Measuring Web Performance with JavaScript 11

Slide 13

Slide 13 text

1 HTTP Stockholm #WebPerf Meetup / 2014-10-30 Boomerang: Measuring Web Performance with JavaScript 12

Slide 14

Slide 14 text

So to measure latency, we need to send 1 packet each way, and time it Stockholm #WebPerf Meetup / 2014-10-30 Boomerang: Measuring Web Performance with JavaScript 13

Slide 15

Slide 15 text

1 Network latency in JavaScript var ts, rtt, img = new Image; img.onload=function() { rtt=(+new Date - ts) }; ts = +new Date; img.src="/1x1.gif"; Stockholm #WebPerf Meetup / 2014-10-30 Boomerang: Measuring Web Performance with JavaScript 14

Slide 16

Slide 16 text

1 Notes • 1x1 gif is 35 bytes • including HTTP headers, this is smaller than a TCP packet • Fires onload on all browsers • 0 byte image fires onerror • which is indistinguishable from network error Stockholm #WebPerf Meetup / 2014-10-30 Boomerang: Measuring Web Performance with JavaScript 15

Slide 17

Slide 17 text

2 TCP handshake Stockholm #WebPerf Meetup / 2014-10-30 Boomerang: Measuring Web Performance with JavaScript 16

Slide 18

Slide 18 text

2 ACK-ACK-ACK Stockholm #WebPerf Meetup / 2014-10-30 Boomerang: Measuring Web Performance with JavaScript 17

Slide 19

Slide 19 text

2 Connection: keep-alive Stockholm #WebPerf Meetup / 2014-10-30 Boomerang: Measuring Web Performance with JavaScript 18

Slide 20

Slide 20 text

2 Network latency & TCP handshake in JavaScript var t=[], tcp, rtt; var ld = function() { t.push(+new Date); if(t.length > 2) // run 2 times done(); else { var img = new Image; img.onload = ld; img.src="/1x1.gif?" + Math.random() + ’=’ + new Date; } }; var done = function() { rtt=t[2]-t[1]; tcp=t[1]-t[0]-rtt; }; ld(); Stockholm #WebPerf Meetup / 2014-10-30 Boomerang: Measuring Web Performance with JavaScript 19

Slide 21

Slide 21 text

Notice that we’ve ignored DNS lookup time here... how would you measure it? Stockholm #WebPerf Meetup / 2014-10-30 Boomerang: Measuring Web Performance with JavaScript 20

Slide 22

Slide 22 text

3 Network Throughput Stockholm #WebPerf Meetup / 2014-10-30 Boomerang: Measuring Web Performance with JavaScript 21

Slide 23

Slide 23 text

3 Measuring Network Throughput data_length download_time Stockholm #WebPerf Meetup / 2014-10-30 Boomerang: Measuring Web Performance with JavaScript 22

Slide 24

Slide 24 text

3 Network Throughput in JavaScript // Assume global object // image={ url: ..., size: ... } var ts, rtt, bw, img = new Image; img.onload=function() { rtt=(+new Date - ts); bw = image.size*1000/rtt; // rtt is in ms }; ts = +new Date; img.src=image.url; Stockholm #WebPerf Meetup / 2014-10-30 Boomerang: Measuring Web Performance with JavaScript 23

Slide 25

Slide 25 text

3 Measuring Network Throughput If it were that simple, I wouldn’t be doing this talk. Stockholm #WebPerf Meetup / 2014-10-30 Boomerang: Measuring Web Performance with JavaScript 24

Slide 26

Slide 26 text

3 TCP Slow Start Stockholm #WebPerf Meetup / 2014-10-30 Boomerang: Measuring Web Performance with JavaScript 25

Slide 27

Slide 27 text

3 Measuring Network Throughput So to make the best use of bandwidth, we need resources that fit in a TCP window Stockholm #WebPerf Meetup / 2014-10-30 Boomerang: Measuring Web Performance with JavaScript 26

Slide 28

Slide 28 text

3 There is no single size that will tax all available networks http://www.yuiblog.com/blog/2010/04/08/analyzing-bandwidth-and-latency/ Stockholm #WebPerf Meetup / 2014-10-30 Boomerang: Measuring Web Performance with JavaScript 27

Slide 29

Slide 29 text

3 Network Throughput in JavaScript – Take 2 // image object is now an array of multiple images var i=0; var ld = function() { if(i>0) image[i-1].end = +new Date; if(i >= image.length) done(); else { var img = new Image; img.onload = ld; image[i].start = +new Date; img.src=image[i].url; } i++; }; Stockholm #WebPerf Meetup / 2014-10-30 Boomerang: Measuring Web Performance with JavaScript 28

Slide 30

Slide 30 text

3 Measuring Network Throughput Slow network connection, meet really huge image Stockholm #WebPerf Meetup / 2014-10-30 Boomerang: Measuring Web Performance with JavaScript 29

Slide 31

Slide 31 text

3 Network Throughput in JavaScript – Take 3 var img = new Image; img.onload = ld; image[i].start = +new Date; image[i].timer = setTimeout(function() { image[i].expired=true }, image[i].timeout); img.src=image[i].url; Stockholm #WebPerf Meetup / 2014-10-30 Boomerang: Measuring Web Performance with JavaScript 30

Slide 32

Slide 32 text

3 Network Throughput in JavaScript – Take 3 if(i>0) { image[i-1].end = +new Date; clearTimeout(image[i-1].timer); } Stockholm #WebPerf Meetup / 2014-10-30 Boomerang: Measuring Web Performance with JavaScript 31

Slide 33

Slide 33 text

3 Network Throughput in JavaScript – Take 3 if(i >= image.length || (i > 0 && image[i-1].expired)) { done(); } Stockholm #WebPerf Meetup / 2014-10-30 Boomerang: Measuring Web Performance with JavaScript 32

Slide 34

Slide 34 text

3 Measuring Network Throughput Are we done yet? Stockholm #WebPerf Meetup / 2014-10-30 Boomerang: Measuring Web Performance with JavaScript 33

Slide 35

Slide 35 text

3 Measuring Network Throughput Are we done yet? sure... Stockholm #WebPerf Meetup / 2014-10-30 Boomerang: Measuring Web Performance with JavaScript 33

Slide 36

Slide 36 text

3 Measuring Network Throughput Except network throughput is different every time you test it Stockholm #WebPerf Meetup / 2014-10-30 Boomerang: Measuring Web Performance with JavaScript 34

Slide 37

Slide 37 text

3 Measuring Network Throughput The code for that is NOT gonna fit on a slide Stockholm #WebPerf Meetup / 2014-10-30 Boomerang: Measuring Web Performance with JavaScript 35

Slide 38

Slide 38 text

3 Bandwidth is different around the world Stockholm #WebPerf Meetup / 2014-10-30 Boomerang: Measuring Web Performance with JavaScript 36

Slide 39

Slide 39 text

4 Page Load Time Stockholm #WebPerf Meetup / 2014-10-30 Boomerang: Measuring Web Performance with JavaScript 37

Slide 40

Slide 40 text

4 Page Load Time is Simple 1 Get a timestamp when user initiates page request 2 Get a timestamp when page completes loading 3 Pass it through advanced Mathematics engine: t_done = t_end − t_start Stockholm #WebPerf Meetup / 2014-10-30 Boomerang: Measuring Web Performance with JavaScript 38

Slide 41

Slide 41 text

4 Page Load Time This is easy with Navigation Timing enabled browsers (Except for all the versions with bugs) Stockholm #WebPerf Meetup / 2014-10-30 Boomerang: Measuring Web Performance with JavaScript 39

Slide 42

Slide 42 text

4 Page Load Time But what about legacy browsers? Stockholm #WebPerf Meetup / 2014-10-30 Boomerang: Measuring Web Performance with JavaScript 40

Slide 43

Slide 43 text

4 Page Load Time End time is measured in the onload or pageshow events Stockholm #WebPerf Meetup / 2014-10-30 Boomerang: Measuring Web Performance with JavaScript 41

Slide 44

Slide 44 text

4 Page Load Time Start time is measured in the onbeforeunload event Stockholm #WebPerf Meetup / 2014-10-30 Boomerang: Measuring Web Performance with JavaScript 42

Slide 45

Slide 45 text

But what if the user opens a link in a new tab? Stockholm #WebPerf Meetup / 2014-10-30 Boomerang: Measuring Web Performance with JavaScript 43

Slide 46

Slide 46 text

4 Page Load Time Start time is measured in the onbeforeunload or onclick or onsubmit events Stockholm #WebPerf Meetup / 2014-10-30 Boomerang: Measuring Web Performance with JavaScript 44

Slide 47

Slide 47 text

But not if the click happened on a FLASH object Stockholm #WebPerf Meetup / 2014-10-30 Boomerang: Measuring Web Performance with JavaScript 45

Slide 48

Slide 48 text

4 Page Load Time We also measure the onunload or pagehide events... This gives us first byte time Stockholm #WebPerf Meetup / 2014-10-30 Boomerang: Measuring Web Performance with JavaScript 46

Slide 49

Slide 49 text

4 Page Load Time We cannot attach events for first page loads, but with enough data we can estimate using statistical analysis Stockholm #WebPerf Meetup / 2014-10-30 Boomerang: Measuring Web Performance with JavaScript 47

Slide 50

Slide 50 text

But... it’s not over yet Stockholm #WebPerf Meetup / 2014-10-30 Boomerang: Measuring Web Performance with JavaScript 48

Slide 51

Slide 51 text

4 Page Load Time A pre-rendered page’s onload event can fire before the user even clicks on the link Stockholm #WebPerf Meetup / 2014-10-30 Boomerang: Measuring Web Performance with JavaScript 49

Slide 52

Slide 52 text

boomerang takes care of this by measuring "click to visible", "request to load", "request to visible", and "load to visible" Stockholm #WebPerf Meetup / 2014-10-30 Boomerang: Measuring Web Performance with JavaScript 50

Slide 53

Slide 53 text

5 Resource Timing Stockholm #WebPerf Meetup / 2014-10-30 Boomerang: Measuring Web Performance with JavaScript 51

Slide 54

Slide 54 text

Using the Resource Timing API, get timing information for all resources on the page Stockholm #WebPerf Meetup / 2014-10-30 Boomerang: Measuring Web Performance with JavaScript 52

Slide 55

Slide 55 text

Yes, this results in very large beacons, so we use POST, and we will soon merge in a patch to compress the data Stockholm #WebPerf Meetup / 2014-10-30 Boomerang: Measuring Web Performance with JavaScript 53

Slide 56

Slide 56 text

And some hackery to capture XHR requests Create a wrapper around window.XMLHttpRequest and set timers on all its events Stockholm #WebPerf Meetup / 2014-10-30 Boomerang: Measuring Web Performance with JavaScript 54

Slide 57

Slide 57 text

Full code is at github.com/lognormal/beyond-page-metrics/ Stockholm #WebPerf Meetup / 2014-10-30 Boomerang: Measuring Web Performance with JavaScript 55

Slide 58

Slide 58 text

6 Other Stuff Stockholm #WebPerf Meetup / 2014-10-30 Boomerang: Measuring Web Performance with JavaScript 56

Slide 59

Slide 59 text

6 Other Stuff We Measure • NavTiming, SPDY, FirstPaint – navtiming.js • navigation.connection.* – mobile.js • window.performance.memory – memory.js – Chrome 22+ reporting now. • Number of DOM nodes, images, scripts and byte size of HTML – memory.js Stockholm #WebPerf Meetup / 2014-10-30 Boomerang: Measuring Web Performance with JavaScript 57

Slide 60

Slide 60 text

And we try to do it fast Stockholm #WebPerf Meetup / 2014-10-30 Boomerang: Measuring Web Performance with JavaScript 58

Slide 61

Slide 61 text

7 Keep it Clean Stockholm #WebPerf Meetup / 2014-10-30 Boomerang: Measuring Web Performance with JavaScript 59

Slide 62

Slide 62 text

We recently started capturing all JavaScript errors that happen inside boomerang, and beaconing them back Stockholm #WebPerf Meetup / 2014-10-30 Boomerang: Measuring Web Performance with JavaScript 60

Slide 63

Slide 63 text

So now we can find bugs as soon as it affects an end user Stockholm #WebPerf Meetup / 2014-10-30 Boomerang: Measuring Web Performance with JavaScript 61

Slide 64

Slide 64 text

We found that Firefox 31 started throwing exceptions on direct dereferences of window.performance inside anonymous iframes https://bugzilla.mozilla.org/show_bug.cgi?id=1045096 Stockholm #WebPerf Meetup / 2014-10-30 Boomerang: Measuring Web Performance with JavaScript 62

Slide 65

Slide 65 text

We tried to use if (window.hasOwnProperty("performance")) but that doesn’t work in IE10 because window is a host object Stockholm #WebPerf Meetup / 2014-10-30 Boomerang: Measuring Web Performance with JavaScript 63

Slide 66

Slide 66 text

You have to use if ("performance" in window) which JSLint doesn’t like... Stockholm #WebPerf Meetup / 2014-10-30 Boomerang: Measuring Web Performance with JavaScript 64

Slide 67

Slide 67 text

You have to use if ("performance" in window) which JSLint doesn’t like... But no one likes JSLint so it’s okay Stockholm #WebPerf Meetup / 2014-10-30 Boomerang: Measuring Web Performance with JavaScript 64

Slide 68

Slide 68 text

And speaking of IE, did you know that "TypeError: Permission Denied" is localized, so you have to capture every single language to detect it? Stockholm #WebPerf Meetup / 2014-10-30 Boomerang: Measuring Web Performance with JavaScript 65

Slide 69

Slide 69 text

On a more interesting note, IE11 running in compatibility mode can make it seem like IE7 has magically received Navigation Timing support Stockholm #WebPerf Meetup / 2014-10-30 Boomerang: Measuring Web Performance with JavaScript 66

Slide 70

Slide 70 text

We found that Chrome 38 started reporting 0 for firstPaintTime, and that helped the Chrome team realise, "This code (in Chrome)... we don’t know how it ever worked" https://code.google.com/p/chromium/issues/detail?id=422913 Stockholm #WebPerf Meetup / 2014-10-30 Boomerang: Measuring Web Performance with JavaScript 67

Slide 71

Slide 71 text

We also found a much older Chrome bug where cached content was reported as having a negative load time in Resource Timing Stockholm #WebPerf Meetup / 2014-10-30 Boomerang: Measuring Web Performance with JavaScript 68

Slide 72

Slide 72 text

We found that Mobile Safari’s NavigationTiming implementation had weird bugs, but could not find a good pattern Stockholm #WebPerf Meetup / 2014-10-30 Boomerang: Measuring Web Performance with JavaScript 69

Slide 73

Slide 73 text

And Android 2.3’s browser has a document.createEvent method that exists, but always throws, so capability detection doesn’t work nicely Stockholm #WebPerf Meetup / 2014-10-30 Boomerang: Measuring Web Performance with JavaScript 70

Slide 74

Slide 74 text

As we found that users have different bugs too ;) Stockholm #WebPerf Meetup / 2014-10-30 Boomerang: Measuring Web Performance with JavaScript 71

Slide 75

Slide 75 text

ni! din tur nu Stockholm #WebPerf Meetup / 2014-10-30 Boomerang: Measuring Web Performance with JavaScript 72

Slide 76

Slide 76 text

– .done() Stockholm #WebPerf Meetup / 2014-10-30 Boomerang: Measuring Web Performance with JavaScript 73

Slide 77

Slide 77 text

Tack! Frågor? Stockholm #WebPerf Meetup / 2014-10-30 Boomerang: Measuring Web Performance with JavaScript 74

Slide 78

Slide 78 text

Code/References • http://lognormal.github.com/boomerang/doc/ (BSD Licensed) • www.lognormal.com Stockholm #WebPerf Meetup / 2014-10-30 Boomerang: Measuring Web Performance with JavaScript 75

Slide 79

Slide 79 text

• Philip Tellis • @bluesmoon • [email protected] • www.SOASTA.com • boomerang • LogNormal Blog Stockholm #WebPerf Meetup / 2014-10-30 Boomerang: Measuring Web Performance with JavaScript 76