Hands on Web
Performance Workshop
Andy Davies
@andydavies

Tobias Baldauf
@tbaldauf
#VelocityConf London 2013
We’re planning to cover
● Tools
● Techniques
● Live Analysis

But…
…this session is about

YOU
so feel free to jump in with questions
What sites should we test?
http://man.gl/londonworkshop
Do you use WebPageTest?
PhantomJS

http://github.com/ariya/phantomjs/
Phantomas
http://github.com/macbre/phantomas

{
"url":"http://tobias.is",
"metrics":{
"requests":11,
"gzipRequests":2,
"postRequests":0,
"redirects":0,
"notFound":0,
"timeToFirstByte":107,
"timeToLastByte":120,
"bodySize":151897,
"contentLength":206417,
[...]
All together now!
#!/usr/bin/env bash
URL_to_measure="$1"

#!/usr/bin/env bats
@test "Time to first byte" {
[ "$timeToFirstByte" -lt 200 ]
}

Metrics_to_analyze=('timeToFirstByte' 'requests' 'cssSize')
Phantomas_JSON_output=$(phantomas --format=json --url "${URL_to_measure}")
for((i=0;i<${#Metrics_to_analyze[@]};i++)) ; do
eval ${Metrics_to_analyze[$i]}=$(echo "$Phantomas_JSON_output" | jq ".metrics."${Metrics_to_analyze[$i]})
export ${Metrics_to_analyze[$i]}
done
bats --tap performance-tests.bats

#1..3
ok 1 Time to first byte
ok 2 Number of HTTP requests
not ok 3 CSS size
# (in test file /test/webperf/performance-tests.bats, line 23)

@test "Number of HTTP requests" {
[ "$requests" -lt 30 ]
}
@test "CSS size" {
[ "$cssSize" -lt 15360 ]
}

http://github.com/technopagan/simple-website-speed-test
WebPagetest API

http://github.com/marcelduran/webpagetest-api
Run WPT Run!
webpagetest test http://velocityconf.com --server wpt.yourdomain.tld --location Local-SGS2 --wait

{
"statusCode": 200,
"statusText": "Ok",
"data": {
"testId": "131019_VF_1",
"ownerKey": "b5cf1cb86be59d94f3ee714f15da3efe5cf05b7z",
"jsonUrl": "http://wpt.yourdomain.tld/jsonResult.php?test=131019_VF_1",
"xmlUrl": "http://wpt.yourdomain.tld/xmlResult.php?test=131019_VF_1",
"userUrl": "http://wpt.yourdomain.tld/results.php?test=131019_VF_1",
"summaryCSV": "http://wpt.yourdomain.tld/csv.php?test=131019_VF_1",
"detailCSV": "http://wpt.yourdomain.tld/csv.php?test=131019_VF_1&amp;req=1"
}
SwissArmyKnife Results
"response": {
"statusCode": 200,
"statusText": "Ok",
"data": {
"testId": "131019_VF_1",
"summary": "http://wpt.yourdomain.tld/results.php?test=131019_VF_1",
"from": "Samsung Galaxy SII - Native",
"runs": 1,
"successfulFVRuns": 1,
"successfulRVRuns": 1,
"average": {
"firstView": {
"loadTime": 6285,
"TTFB": 2852,
[...]
TAP & Jenkins Integration
What if we want
to test more
than one page?
./sitespeed.io -u http://news.bbc.co.uk
Setup your own HTTP Archive…
Barbara Bermes - http://man.gl/1eHoyqB
Lots of data!
Import data into R
library(RMySQL)
drv = dbDriver('MySQL')
con = dbConnect(drv, user='user', password='password', dbname='dbname', host='127.0.0.1')
results = dbGetQuery(con,statement='select * from pages;')

Plot histogram of requests / page
hist(results$reqTotal,
xlim=c(0,200),
ylim=c(0,375),
breaks=seq(0,200,by=5),
main="",
xlab="Number of Requests",
col="steelblue",
border="white", axes=FALSE)
axis(1, at = seq(0, 225, by = 25))
axis(2, at = seq(0, 400, by = 25))
Sometimes bi-modal distributions
Commercial tools available too…
Let’s look at some live sites
Performance isn’t just about load time

http://www.flickr.com/photos/jaxport/8554780980
Painting every 20ms!
Logo is actually made of four
images that fade from one to
another.
CPU load varies between 7 - 20%
Has detrimental impact on mobile
battery life
A Tale of CSS Checkbox Hacks
<input type="checkbox" id="toggle" />
<label for="toggle" class="toggle" onclick></label>
<ul class="menu">
<li><a href="#">Sictransit</a></li>
<li><a href="#">Gloriamundi</a></li>
</ul>

#toggle:checked ~ .menu {
display: block;
}
http://css-tricks.com/the-checkbox-hack/
http://thenittygritty.co/toggle-navigation-with-purecss

body {
-webkit-animation: bugfix infinite 1s; /* here be dragons */
}
@-webkit-keyframes bugfix {
from {
white-space: default;
}
to {
white-space: normal;
}
}

http://bugs.webkit.org/show_bug.cgi?id=45168
Be neighborly
Adjacent sibling selector trumps general sibling selector
<input type="checkbox" id="toggle" />
<nav>
<label for="toggle" class="toggle" onclick></label>
<ul class="menu">
<li><a href="#">Sictransit</a></li>
<li><a href="#">Gloriamundi</a></li>
</ul>
</nav>

#toggle:checked + nav .menu {
display: block;
}
Lessons learned
Working in web performance is as much
about educating as optimizing.

Choose your battles

http://sapdesignguild.org

http://josefbrandenburg.com
Thank You (we’re around all week)
Andy:

@andydavies
hello@andydavies.me

Tobias:

@tbaldauf
kontakt@tobias-baldauf.de

Office Hours: 12:30 Thursday

Web Performance Workshop - Velocity London 2013

  • 1.
    Hands on Web PerformanceWorkshop Andy Davies @andydavies Tobias Baldauf @tbaldauf #VelocityConf London 2013
  • 2.
    We’re planning tocover ● Tools ● Techniques ● Live Analysis But…
  • 3.
    …this session isabout YOU so feel free to jump in with questions
  • 4.
    What sites shouldwe test? http://man.gl/londonworkshop
  • 5.
    Do you useWebPageTest?
  • 6.
  • 7.
  • 8.
    All together now! #!/usr/bin/envbash URL_to_measure="$1" #!/usr/bin/env bats @test "Time to first byte" { [ "$timeToFirstByte" -lt 200 ] } Metrics_to_analyze=('timeToFirstByte' 'requests' 'cssSize') Phantomas_JSON_output=$(phantomas --format=json --url "${URL_to_measure}") for((i=0;i<${#Metrics_to_analyze[@]};i++)) ; do eval ${Metrics_to_analyze[$i]}=$(echo "$Phantomas_JSON_output" | jq ".metrics."${Metrics_to_analyze[$i]}) export ${Metrics_to_analyze[$i]} done bats --tap performance-tests.bats #1..3 ok 1 Time to first byte ok 2 Number of HTTP requests not ok 3 CSS size # (in test file /test/webperf/performance-tests.bats, line 23) @test "Number of HTTP requests" { [ "$requests" -lt 30 ] } @test "CSS size" { [ "$cssSize" -lt 15360 ] } http://github.com/technopagan/simple-website-speed-test
  • 9.
  • 10.
    Run WPT Run! webpagetesttest http://velocityconf.com --server wpt.yourdomain.tld --location Local-SGS2 --wait { "statusCode": 200, "statusText": "Ok", "data": { "testId": "131019_VF_1", "ownerKey": "b5cf1cb86be59d94f3ee714f15da3efe5cf05b7z", "jsonUrl": "http://wpt.yourdomain.tld/jsonResult.php?test=131019_VF_1", "xmlUrl": "http://wpt.yourdomain.tld/xmlResult.php?test=131019_VF_1", "userUrl": "http://wpt.yourdomain.tld/results.php?test=131019_VF_1", "summaryCSV": "http://wpt.yourdomain.tld/csv.php?test=131019_VF_1", "detailCSV": "http://wpt.yourdomain.tld/csv.php?test=131019_VF_1&amp;req=1" }
  • 11.
    SwissArmyKnife Results "response": { "statusCode":200, "statusText": "Ok", "data": { "testId": "131019_VF_1", "summary": "http://wpt.yourdomain.tld/results.php?test=131019_VF_1", "from": "Samsung Galaxy SII - Native", "runs": 1, "successfulFVRuns": 1, "successfulRVRuns": 1, "average": { "firstView": { "loadTime": 6285, "TTFB": 2852, [...]
  • 12.
    TAP & JenkinsIntegration
  • 13.
    What if wewant to test more than one page?
  • 14.
  • 20.
    Setup your ownHTTP Archive… Barbara Bermes - http://man.gl/1eHoyqB
  • 21.
  • 22.
    Import data intoR library(RMySQL) drv = dbDriver('MySQL') con = dbConnect(drv, user='user', password='password', dbname='dbname', host='127.0.0.1') results = dbGetQuery(con,statement='select * from pages;') Plot histogram of requests / page hist(results$reqTotal, xlim=c(0,200), ylim=c(0,375), breaks=seq(0,200,by=5), main="", xlab="Number of Requests", col="steelblue", border="white", axes=FALSE) axis(1, at = seq(0, 225, by = 25)) axis(2, at = seq(0, 400, by = 25))
  • 24.
  • 28.
  • 30.
    Let’s look atsome live sites
  • 31.
    Performance isn’t justabout load time http://www.flickr.com/photos/jaxport/8554780980
  • 33.
  • 36.
    Logo is actuallymade of four images that fade from one to another. CPU load varies between 7 - 20% Has detrimental impact on mobile battery life
  • 37.
    A Tale ofCSS Checkbox Hacks <input type="checkbox" id="toggle" /> <label for="toggle" class="toggle" onclick></label> <ul class="menu"> <li><a href="#">Sictransit</a></li> <li><a href="#">Gloriamundi</a></li> </ul> #toggle:checked ~ .menu { display: block; } http://css-tricks.com/the-checkbox-hack/ http://thenittygritty.co/toggle-navigation-with-purecss body { -webkit-animation: bugfix infinite 1s; /* here be dragons */ } @-webkit-keyframes bugfix { from { white-space: default; } to { white-space: normal; } } http://bugs.webkit.org/show_bug.cgi?id=45168
  • 39.
    Be neighborly Adjacent siblingselector trumps general sibling selector <input type="checkbox" id="toggle" /> <nav> <label for="toggle" class="toggle" onclick></label> <ul class="menu"> <li><a href="#">Sictransit</a></li> <li><a href="#">Gloriamundi</a></li> </ul> </nav> #toggle:checked + nav .menu { display: block; }
  • 40.
    Lessons learned Working inweb performance is as much about educating as optimizing. Choose your battles http://sapdesignguild.org http://josefbrandenburg.com
  • 41.
    Thank You (we’rearound all week) Andy: @andydavies hello@andydavies.me Tobias: @tbaldauf kontakt@tobias-baldauf.de Office Hours: 12:30 Thursday