WWLLC
What Would
Lucky Luke Code?

Create Drupal sites
with good
performance
Henrik
Developer
Mostly backend
@FrontHenrik
Frank
Web designer
Mostly front-end
@fragje
The frontkom family
Per André Rønsen

Marco Fernandes

CIO/Chief Innovation Officer

Senior Web developer

Fredrik Paus

Élio Cró

Jan-Helge Hansen

COO/Project Manager

Web Developer

Infrastructure / support

Thor André Gretland

Roberto Ornelas

Support & Training

CTO Senior developer

Fábio Neves

Geir Gulland

Hélder Mendes

Bruno Campos

CEO / Web strategist

Web Designer

Web developer

Frank Gjertsen

Elisabeth Gulland

Wilma

Web Designer

Accountant

QA Engineer ;)

Henrik Akselsen
JS/Mobile UX

Web developer
Fredrikstad | Madeira
Agenda
●
●
●
●
●
●

Why performance?
Analysis
Frontend
Server configuration
Backend
Your inputs
SHOWTIME
Why performance now?
● We got fast internet connections
● Powerful computers
● Shiny large screens
…but wait, we got mobile.
…and bad mobile connections.
…and emerging markets which are mobile only.
Web pages are getting

FAT

1.5MB
Expect to increase by 21% the next year

● Today the average page is
●

● Oakley released their new site.

80MB
When to start?
● Post-optimization is the root of all evil
● Lack of performance = Lack of planning
● Bad performance is bad business
●
●
●
●

We need our clients interest in performance
Show visually how a page loads
Make a performance budget
Plan performance from the beginning
We need to analyze this
“Yeah, it’s slow, but it’s probably just
[insert wild speculation here]”
Hold your assumptions
● A lot of the time your assumption will be
wrong and cause a lot of wasted effort
● Let the data guide the optimizing process
● Use the 80/20 rule => find low hanging fruit
Tools
●
●
●
●

Web developer tools in your browsers
PageSpeed (Google)
Yslow (Yahoo)
Quicksprout
http://www.quicksprout.com/
● WebPageTest
http://www.webpagetest.org/
Indepth analysis
Chrome Dev Tools

XHProf (Backend)

Frontend
Introduction to dev tools
http://bit.ly/discover-devtools

Find out which functions
that are using memory and
processor time

“The Breakpoint”
Paul Irish / Addy Osmani
Mobile first
Mobile first
● Start small. Add style and content as you get
more space, without limiting the user
experience.
http://bradfrostweb.com/demo/mobile-first
● Build systems instead of individual pages
● Write reusable code
Mobile first
●
●
●
●

Download as few MB as possible
Reduce requested files. Images, css, js.
Concatenate and minify css and js
Make sprites
○ Compass does this in a smart way…

● Or use icon fonts
○ http://iconmoon.io
○ or even better http://fontastic.me
HTML
● Take control over your markup
● Customize markup in your tpl.php
● Find design patterns and add classes to
similar elements.
● In views it can be customized directly, on
other output use template.php
<section class="panel-pane paneviews-panes pane-commons-featuredpanel-pane-1 block">...</section>
<section class="panel-pane paneviews-panes pane-commons-activitystreams-activity-panel-pane-1
block">...</section>
function theme_preprocess_panels_pane(&$vars) {
switch ($vars['pane']->pid) {
case '14':
$vars['classes_array'][] = 'box-default';
break;
case '8':
$vars['classes_array'] = array('box-default');
break;
}
}
<section class="panel-pane paneviews-panes pane-commons-featuredpanel-pane-1 block box-default">
... </section>
<section class="box-default"> ...
</section>
Useful gh-repo

http://bit.ly/template-php
by Jesper Wøldiche Rahkonen
Clean markup
● Modules
○ Clean Markup - Blocks, Panel panes, Panel regions,
Panel layouts
https://drupal.org/project/clean_markup
○ Fences - clean fields markup globaly.
https://drupal.org/project/fences
Default fields markup

<div class="field field-name-field-test
field-type-text field-label-above">
<div class="field-label">Foobar field:
&nbsp;</div>
<div class="field-items">
<div class="field-item even">Drupal
default fields markup.</div>
</div>
</div>
After fences config

<h3 class="field-label">Foobar
field</h3>
<div class="field-foobar">Leaner markup
means better front-end performance.
</div>
Clean markup
● Modules
○ Clean Markup - Blocks, Panel panes, Panel regions,
Panel layouts
https://drupal.org/project/clean_markup
○ Fences - clean fields markup globaly.
https://drupal.org/project/fences

● Themes
○ Mothership
https://drupal.org/project/mothership
○ Aurora
https://drupal.org/project/aurora
CSS
● Write as little as possible
● Use classes instad of tags
○ ul li a {}
○ .nav-main .nav-item {}
○ http://bit.ly/quick-selectors

● Css can get out of control and hard to
manage when a page scales
.btn-default, .btn-cta {
text-align: center;
display: inline-block;
background-color: gray;
padding: 5px 10px;
color: white;
}
.btn-cta {
background-color: dodgerblue;
}
SMACSS
● A must read for all
working with css
● Part of the book is
available online for free
http://smacss.com
http://pattern-lab.info
by Brad Frost
Preprocess that CSS
● LESS
● Stylus
● Sass
○
○
○
○

WARNING!

Compass - Sass mixins library and much more
Breakpoint - Really Simple Media Queries with Sass
Toolkit - swiss army knife for PE and RWD
Singularity - Grids withoutyour output
Always check limits
.btn-default {
text-align: center;
display: inline-block;
background-color: gray;
padding: 5px 10px;
color: white;
}
.btn-cta {
@extend .btn-default;
background-color: dodgerblue;
}
.btn-default, .btn-cta {
text-align: center;
display: inline-block;
background-color: gray;
padding: 5px 10px;
color: white;
}
.btn-cta {
background-color: dodgerblue;
}
Javascript
● Don’t load js before css
● Don’t load libraries you don’t need, and if
possible make custom builds to your needs.
E.g. Modernizr.
● Try to move most of your js at the bottom of
your page, just before </body>. There is a
special Drupal module for this.
● Avoid unnecessary dom manipulations
MAGIC

https://drupal.org/project/magic
Avoid calculations in loops
var div = document.getElementById("to-measure"),
lis = document.getElementsByTagName('li'),
i, len;
for (i = 0, len = lis.length; i < len; i++) {
lis[i].style.width = div.offsetWidth + 'px';
}
Improve Perceived performance
● Edge side includes
● Image lazy loading
Configuration
Tweak it up
Hosting
● Geography - Closer is better.
○ (Sorry New Zealand)

● SSD is awesome
● Quick and good support
○ (Sorry New Zealand)

● Consider dedicated Drupal hosting
○ Fx Pantheon (has great workflow)
PHP & MySQL
PHP version: newer is better
InnoDB > Myisam
APC
- Opcode cache
- Easy setup, huge performance win
- See https://drupal.org/node/1777090 for
configuration tips for Drupal
- Remember to assign enough memory, or the
cache will not have any effect
Memcache(d)
Improves editor experience + faster site
building
Memcache module not needed, just include in
settings.php
Alternative: Redis
// the path to the core cache file
include_once('./includes/cache.inc');
// the path to the memcache cache file
include_once
('./sites/all/modules/contrib/memcache/memcache.inc');
// make MemCacheDrupal the default cache class
$conf['cache_default_class'] = 'MemCacheDrupal';
$conf['memcache_servers'] = array('127.0.0.1:11211' =>
'default');
$conf['memcache_bins'] = array('cache' => 'default');
$conf['memcache_key_prefix'] = 'mysite';
First time using memcache
Varnish

Boost
(poor man’s
Varnish)

Gzip
High performance with cloud
● CDN
● Amazon AWS for static files and images
● Web Application Streaming
○ new tech, possible “CDN killer”)
○ from InstartLogic
Drupal
Good places to hang out
● high performance group on d.o
● Contrib modules
Module strategy
● As few modules as possible
○ Avoid the buffet syndrome

● Check which hooks are used.
○ hook_init() is more important to watch than
hook_openid_normalization_method_info_alter()

● Preferred: Measure before/after install
○ Dive into xhprof
○ Disable suspected performance hogs
Module strategy
● Check that page cache is not being disabled
○
○
○
○
○

drupal_page_is_cacheable(FALSE);
$GLOBALS['conf']['cache'] = 0;
$GLOBALS['conf']['cache'] = CACHE_DISABLED;
$conf['cache'] = FALSE;
flags module, captcha module

(This may have to be necessary, but at least
know that it is happening)
Watch the Logs

● Keep an eye on the dblogs
● May slow down disk if constantly logging
errors
● May point to underlying errors
● Bad Karma
● Tip: Get sent an email on each log error
Cache
●
●
●
●

Views Cache!
PHP blocks breaks cache
D7: contrib provides a lot
D8: Much more flexible out of the box
○ pluggable CSS and JavaScript optimization
○ personalize through JavaScript
○ Entity Cache
Be kind to the theme layer
● Avoid logic in the theme layer
○ hurts page cache

● Avoid heavy processes in the theme layer
○ node_load
○ sql queries

● Tip: Switch to another theme and do
performance tests again
Views queries
Find candidates for optimizing
[mysqld]
log_slow_queries=/Applications/MAMP/logs/mys
ql_sql_slow.log
long_query_time=0.5
LOTS OF JOINS
SELECT * FROM mother_of_all_huge_tables
Keep an eye on

PAGERS DISTINCT COUNT JOINS
Optimize Views Queries
Battle plan: Find JOINS
and see if you can do
the same within SELECT
Tip: use EXPLAIN on
views sql
How many evaluations
No JOIN
select nid FROM node;
200005 rows in set (0.08 sec)

Data from astonishdesign.com
1 JOIN
select n.nid, s.
field_school_name_format
FROM node n
LEFT JOIN
field_data_field_school_name s ON
n.nid = s.entity_id;
200005 rows in set (1.09 sec)
2 JOINS
select n.nid, s.field_school_name_format,
si.field_school_id_value
FROM node n
LEFT JOIN field_data_field_school_name s ON
n.nid = s.entity_id
LEFT JOIN field_data_field_school_id si on
n.nid = si.entity_id;
200005 rows in set (2.03 sec)
3 JOINS
select n.nid, s.field_school_name_format, si.
field_school_id_value,
sp.field_school_phone_value
FROM node n
LEFT JOIN field_data_field_school_name s ON n.nid = s.
entity_id
LEFT JOIN field_data_field_school_id si on n.nid = si.
entity_id
LEFT JOIN field_data_field_school_phone sp on n.nid = sp.
entity_id;
200005 rows in set (

5.03 sec)
Optimize Views Queries
● Optimize in hook_views_query_alter() and
hook_view_query_substitutions()

● Consider making views into a module
○ Easier to optimize + easier version control
Specific use cases
● Defer heavy tasks
○ Push heavy tasks to cron
○ Batch API

● Fast 404
Good PHP habits
http://www.phpbench.com/
Stats
Performance module
New Relic
Load testing with jMeter (+Blazemeter)
Bring out the big guns

● Ditch the theme
layer
● Example: NewsFront
Now it’s your turn ;-)

Drupalcamp performance

  • 1.
    WWLLC What Would Lucky LukeCode? Create Drupal sites with good performance
  • 2.
  • 3.
  • 4.
    The frontkom family PerAndré Rønsen Marco Fernandes CIO/Chief Innovation Officer Senior Web developer Fredrik Paus Élio Cró Jan-Helge Hansen COO/Project Manager Web Developer Infrastructure / support Thor André Gretland Roberto Ornelas Support & Training CTO Senior developer Fábio Neves Geir Gulland Hélder Mendes Bruno Campos CEO / Web strategist Web Designer Web developer Frank Gjertsen Elisabeth Gulland Wilma Web Designer Accountant QA Engineer ;) Henrik Akselsen JS/Mobile UX Web developer
  • 5.
  • 6.
  • 7.
  • 8.
    Why performance now? ●We got fast internet connections ● Powerful computers ● Shiny large screens …but wait, we got mobile. …and bad mobile connections. …and emerging markets which are mobile only.
  • 9.
    Web pages aregetting FAT 1.5MB Expect to increase by 21% the next year ● Today the average page is ● ● Oakley released their new site. 80MB
  • 10.
    When to start? ●Post-optimization is the root of all evil ● Lack of performance = Lack of planning ● Bad performance is bad business ● ● ● ● We need our clients interest in performance Show visually how a page loads Make a performance budget Plan performance from the beginning
  • 11.
    We need toanalyze this
  • 12.
    “Yeah, it’s slow,but it’s probably just [insert wild speculation here]”
  • 13.
    Hold your assumptions ●A lot of the time your assumption will be wrong and cause a lot of wasted effort ● Let the data guide the optimizing process ● Use the 80/20 rule => find low hanging fruit
  • 14.
    Tools ● ● ● ● Web developer toolsin your browsers PageSpeed (Google) Yslow (Yahoo) Quicksprout http://www.quicksprout.com/ ● WebPageTest http://www.webpagetest.org/
  • 17.
    Indepth analysis Chrome DevTools XHProf (Backend) Frontend Introduction to dev tools http://bit.ly/discover-devtools Find out which functions that are using memory and processor time “The Breakpoint” Paul Irish / Addy Osmani
  • 18.
  • 19.
    Mobile first ● Startsmall. Add style and content as you get more space, without limiting the user experience. http://bradfrostweb.com/demo/mobile-first ● Build systems instead of individual pages ● Write reusable code
  • 20.
    Mobile first ● ● ● ● Download asfew MB as possible Reduce requested files. Images, css, js. Concatenate and minify css and js Make sprites ○ Compass does this in a smart way… ● Or use icon fonts ○ http://iconmoon.io ○ or even better http://fontastic.me
  • 21.
    HTML ● Take controlover your markup ● Customize markup in your tpl.php ● Find design patterns and add classes to similar elements. ● In views it can be customized directly, on other output use template.php
  • 22.
    <section class="panel-pane paneviews-panespane-commons-featuredpanel-pane-1 block">...</section> <section class="panel-pane paneviews-panes pane-commons-activitystreams-activity-panel-pane-1 block">...</section>
  • 23.
    function theme_preprocess_panels_pane(&$vars) { switch($vars['pane']->pid) { case '14': $vars['classes_array'][] = 'box-default'; break; case '8': $vars['classes_array'] = array('box-default'); break; } }
  • 24.
    <section class="panel-pane paneviews-panespane-commons-featuredpanel-pane-1 block box-default"> ... </section> <section class="box-default"> ... </section>
  • 25.
  • 26.
    Clean markup ● Modules ○Clean Markup - Blocks, Panel panes, Panel regions, Panel layouts https://drupal.org/project/clean_markup ○ Fences - clean fields markup globaly. https://drupal.org/project/fences
  • 27.
    Default fields markup <divclass="field field-name-field-test field-type-text field-label-above"> <div class="field-label">Foobar field: &nbsp;</div> <div class="field-items"> <div class="field-item even">Drupal default fields markup.</div> </div> </div>
  • 28.
    After fences config <h3class="field-label">Foobar field</h3> <div class="field-foobar">Leaner markup means better front-end performance. </div>
  • 29.
    Clean markup ● Modules ○Clean Markup - Blocks, Panel panes, Panel regions, Panel layouts https://drupal.org/project/clean_markup ○ Fences - clean fields markup globaly. https://drupal.org/project/fences ● Themes ○ Mothership https://drupal.org/project/mothership ○ Aurora https://drupal.org/project/aurora
  • 30.
    CSS ● Write aslittle as possible ● Use classes instad of tags ○ ul li a {} ○ .nav-main .nav-item {} ○ http://bit.ly/quick-selectors ● Css can get out of control and hard to manage when a page scales
  • 31.
    .btn-default, .btn-cta { text-align:center; display: inline-block; background-color: gray; padding: 5px 10px; color: white; } .btn-cta { background-color: dodgerblue; }
  • 32.
    SMACSS ● A mustread for all working with css ● Part of the book is available online for free http://smacss.com
  • 33.
  • 34.
    Preprocess that CSS ●LESS ● Stylus ● Sass ○ ○ ○ ○ WARNING! Compass - Sass mixins library and much more Breakpoint - Really Simple Media Queries with Sass Toolkit - swiss army knife for PE and RWD Singularity - Grids withoutyour output Always check limits
  • 35.
    .btn-default { text-align: center; display:inline-block; background-color: gray; padding: 5px 10px; color: white; } .btn-cta { @extend .btn-default; background-color: dodgerblue; }
  • 36.
    .btn-default, .btn-cta { text-align:center; display: inline-block; background-color: gray; padding: 5px 10px; color: white; } .btn-cta { background-color: dodgerblue; }
  • 37.
    Javascript ● Don’t loadjs before css ● Don’t load libraries you don’t need, and if possible make custom builds to your needs. E.g. Modernizr. ● Try to move most of your js at the bottom of your page, just before </body>. There is a special Drupal module for this. ● Avoid unnecessary dom manipulations
  • 38.
  • 39.
    Avoid calculations inloops var div = document.getElementById("to-measure"), lis = document.getElementsByTagName('li'), i, len; for (i = 0, len = lis.length; i < len; i++) { lis[i].style.width = div.offsetWidth + 'px'; }
  • 40.
    Improve Perceived performance ●Edge side includes ● Image lazy loading
  • 41.
  • 42.
    Hosting ● Geography -Closer is better. ○ (Sorry New Zealand) ● SSD is awesome ● Quick and good support ○ (Sorry New Zealand) ● Consider dedicated Drupal hosting ○ Fx Pantheon (has great workflow)
  • 43.
    PHP & MySQL PHPversion: newer is better InnoDB > Myisam
  • 44.
    APC - Opcode cache -Easy setup, huge performance win - See https://drupal.org/node/1777090 for configuration tips for Drupal - Remember to assign enough memory, or the cache will not have any effect
  • 45.
    Memcache(d) Improves editor experience+ faster site building Memcache module not needed, just include in settings.php Alternative: Redis
  • 46.
    // the pathto the core cache file include_once('./includes/cache.inc'); // the path to the memcache cache file include_once ('./sites/all/modules/contrib/memcache/memcache.inc'); // make MemCacheDrupal the default cache class $conf['cache_default_class'] = 'MemCacheDrupal'; $conf['memcache_servers'] = array('127.0.0.1:11211' => 'default'); $conf['memcache_bins'] = array('cache' => 'default'); $conf['memcache_key_prefix'] = 'mysite';
  • 47.
  • 48.
  • 49.
    High performance withcloud ● CDN ● Amazon AWS for static files and images ● Web Application Streaming ○ new tech, possible “CDN killer”) ○ from InstartLogic
  • 50.
  • 54.
    Good places tohang out ● high performance group on d.o ● Contrib modules
  • 55.
    Module strategy ● Asfew modules as possible ○ Avoid the buffet syndrome ● Check which hooks are used. ○ hook_init() is more important to watch than hook_openid_normalization_method_info_alter() ● Preferred: Measure before/after install ○ Dive into xhprof ○ Disable suspected performance hogs
  • 56.
    Module strategy ● Checkthat page cache is not being disabled ○ ○ ○ ○ ○ drupal_page_is_cacheable(FALSE); $GLOBALS['conf']['cache'] = 0; $GLOBALS['conf']['cache'] = CACHE_DISABLED; $conf['cache'] = FALSE; flags module, captcha module (This may have to be necessary, but at least know that it is happening)
  • 57.
    Watch the Logs ●Keep an eye on the dblogs ● May slow down disk if constantly logging errors ● May point to underlying errors ● Bad Karma ● Tip: Get sent an email on each log error
  • 58.
    Cache ● ● ● ● Views Cache! PHP blocksbreaks cache D7: contrib provides a lot D8: Much more flexible out of the box ○ pluggable CSS and JavaScript optimization ○ personalize through JavaScript ○ Entity Cache
  • 60.
    Be kind tothe theme layer ● Avoid logic in the theme layer ○ hurts page cache ● Avoid heavy processes in the theme layer ○ node_load ○ sql queries ● Tip: Switch to another theme and do performance tests again
  • 62.
  • 64.
    Find candidates foroptimizing [mysqld] log_slow_queries=/Applications/MAMP/logs/mys ql_sql_slow.log long_query_time=0.5 LOTS OF JOINS SELECT * FROM mother_of_all_huge_tables
  • 65.
    Keep an eyeon PAGERS DISTINCT COUNT JOINS
  • 66.
    Optimize Views Queries Battleplan: Find JOINS and see if you can do the same within SELECT Tip: use EXPLAIN on views sql How many evaluations
  • 67.
    No JOIN select nidFROM node; 200005 rows in set (0.08 sec) Data from astonishdesign.com
  • 68.
    1 JOIN select n.nid,s. field_school_name_format FROM node n LEFT JOIN field_data_field_school_name s ON n.nid = s.entity_id; 200005 rows in set (1.09 sec)
  • 69.
    2 JOINS select n.nid,s.field_school_name_format, si.field_school_id_value FROM node n LEFT JOIN field_data_field_school_name s ON n.nid = s.entity_id LEFT JOIN field_data_field_school_id si on n.nid = si.entity_id; 200005 rows in set (2.03 sec)
  • 70.
    3 JOINS select n.nid,s.field_school_name_format, si. field_school_id_value, sp.field_school_phone_value FROM node n LEFT JOIN field_data_field_school_name s ON n.nid = s. entity_id LEFT JOIN field_data_field_school_id si on n.nid = si. entity_id LEFT JOIN field_data_field_school_phone sp on n.nid = sp. entity_id; 200005 rows in set ( 5.03 sec)
  • 71.
    Optimize Views Queries ●Optimize in hook_views_query_alter() and hook_view_query_substitutions() ● Consider making views into a module ○ Easier to optimize + easier version control
  • 72.
    Specific use cases ●Defer heavy tasks ○ Push heavy tasks to cron ○ Batch API ● Fast 404
  • 73.
  • 74.
    Stats Performance module New Relic Loadtesting with jMeter (+Blazemeter)
  • 75.
    Bring out thebig guns ● Ditch the theme layer ● Example: NewsFront
  • 76.