Web performance and optimization


by Gustavo S.



Toronto, 28th May 2013

Why are they important?



  • Slower
    • Unpleasant 
    • Unknown 
    • Boring
  • Fast
    • Responsive 
    • Progressed
    • Informed


bandwidth has a cost

1kb is not much. Now multiple by Millions/daily


mobile changes everything

  • Latency
  • Smaller CPU and battery-driven
  • Data usage


database

Profile

  • Use mysql> DESCRIBE
    • Find out about indexes
    • Check if joins are in the optimal order
DESCRIBE SELECT `package__packages_pickup`.*, `package__unit_manager_units`.`title` as unit_title, `package__profiler`.`display_name`, `package__packages_pickup_courier`.`name` as courier_name
FROM (`package__packages_pickup`)
JOIN `package__profiler` ON `package__profiler`.`id_user` = `package__packages_pickup`.`id_user`
LEFT JOIN `package__unit_manager_units` ON `package__unit_manager_units`.`id` = `package__packages_pickup`.`id_unit`

JOIN `package__packages_pickup_courier` ON `package__packages_pickup_courier`.`id` = `package__packages_pickup`.`id_courier`
WHERE `id_status` = 2
ORDER BY `date_created` desc

LOG SLOW QUERIES

 log_slow_queries=/var/lib/mysql/slow­queries.log
 long_query_time=2

use sub-selects wisely


use fulltext search (avoid Like='%Cats%')

ALTER TABLE yourtable ADD FULLTEXT ft_index_name (description);//When queryingMATCH(description) AGAINST ('dogs')

more resources



php optimization

CACHING in php


  • File cache
    • Don't overhelm the server with I/O
  • Database cache
    • Suitable for data which barely changes. 
  • APC (Alternative PHP Cache)
    • Do not use for user information
    • Fast, opcode
    • Download APC.php and monitor it!
  • MEMCache
    • Faster
    • Suitable for distributed servers

Profiling with xdebug



profiling with xdebug


php_value xdebug.remote_enable 1
php_flag xdebug.profiler_enable 
php_value xdebug.remote_host 192.168.1.117 #your ip
php_value xdebug.idekey "netbeans-xdebug"
php_value xdebug.profiler_output_dir /mnt/user_homes/Gustavo.Simon/httpdocs/cp/logs/profiler

use webgrind or wincachegrind for measuring

  • Execution time
  • Memory Usage (especially for image manipulation)
  • Detect useless recursion
  • Code analysis

tips


  • Use output buffering when possible 
  • AVOID SQL Queries in a loop
foreach ($userList as $user) { //evil
$query = 'INSERT INTO users (first_name,last_name) VALUES("' . $user['first_name'] . '", "' . $user['last_name'] . '")'; mysql_query($query); }
$userData = array();
foreach ($userList as $user) { //good
    $userData[] = '("' . $user['first_name'] . '", "' . $user['last_name'] . '")';
 }
$query = 'INSERT INTO users (first_name,last_name) VALUES' . implode(',', $userData);
mysql_query($query);


  • Don't copy/allocate variables for any reason
$description = strip_tags($_POST['description']);
echo $description;
  • Profile your application again
  • Remember premature optimization is the root of all evil.
    • Before change your code, determine what is slowing down.

 

resources


Networking and hacking the .htaccess



cache-control


Implement and changes headers when necessary
$path = "img/yourasset.pgn";
header("Cache-Control: private, max-age=86400, pre-check=86400");
header("Pragma: private");
header("Expires: " . date(DATE_RFC822,strtotime("+40 week")));
    
if (isset($_SERVER['HTTP_IF_MODIFIED_SINCE']) && (strtotime($_SERVER['HTTP_IF_MODIFIED_SINCE']) == filemtime($path))) {
        // send the last mod time of the file back
        header('Last-Modified: '.gmdate('D, d M Y H:i:s', filemtime($path)).' GMT', true, 304);
        exit;
    }
    
    header("Content-type: image/png");
    header('Last-Modified: ' . gmdate('D, d M Y H:i:s', filemtime($path)) . ' GMT');
    echo file_get_contents($path);

CAche-control


  • max-age: when defined, it doesn't make a new request to the server
  • Cache-control: no-cache, must-revalidate, max-age:0
  • Be explicit, use max-age or no-cache!
  • no-store for confidential information

hacking


  • Manipulating headers using .htaccess
<ifmodule mod_headers.c="">
    <filesmatch "\.(jpg|jpeg|png|gif|swf)$"="">
        Header set Cache-Control "max-age=604800, public"
    </filesmatch>
    <filesmatch "\.(js|css|swf)$"="">
        Header set Cache-Control "max-age=604800"
    </filesmatch>
</ifmodule>
  • Set cookie none when domain is serving assets
  • <IfModule mod_headers.c>
    	Header unset Cookie
        Header unset Set-Cookie 
    </IfModule>

    HACKING .HTACCESS

    • Add expiration
    •  <IfModule mod_expires.c>	
      	ExpiresActive On
      	ExpiresByType image/png "access plus 1 month"
      	ExpiresByType image/gif "access plus 1 month"
      	ExpiresByType image/jpeg "access plus 1 month"
      	ExpiresByType application/x-javascript "access plus 1 month"
          ExpiresByType application/javascript "access plus 1 month"
      	ExpiresByType text/css "access plus 1 month"
      	<Files favicon.ico>
                      ExpiresDefault "access plus 12 months"
              </Files>
      </IfModule>
    • Make sure resources are DEFLATED and GZIPED
    • AddOutputFilterByType DEFLATE text/css application/javascript application/x-javascript text/plain text/html

    Client-side cache


    • API Server/ Mid-Tier should implement cache-control
    • However...
      • It is still a round trip to server to find out if the data is fine.
      • Sometimes we don't own the api

    localstorage

    sessionstorage

    cookies

    cookies


    • Use them for crucial data, API integration if necessary
    • Try to keep the entire REQUEST under 1.5kb, cookies included 
    • Always use path for limit scope

    tools for measuring


    Minify your assets, please!


    Minify YOUR ASSETS


    • Minify our images
      • Choose the best format.
      • Photoshop's "Save For Web". 
      • ImageOptin
      • PageSpeed Insights
    • Use image sprites

      frontend, javascript and tooling

      dom manipulation and REFLOWS


      • Manipulating elements causes reflow
      • Understand reflow
        • Reads DOM tree, style structure, render tree, paint
      • Get first, DOM actions perform at once
      • Optimization
        • display:none; your element, make all changes, restore
        • clone your element, make changes, swap back

      Data uri's


      • Prefer using it along with CSS. Not good experiences using it inline.
      body {background: url(data:image/png;base64,/9j/4AAQSkZJRgABAgAAZABkAD/2wAAY[...]}
    •  It saves a request!
    • It does not work on IE7 
    • IE8 limited to 32kb
    • Don't forget you can use fallbacks :)
    • Convert using base64_encode
    •  base64_encode(file_get_contents($path));

      tips

      • Moving Elements With Translate() Is Better Than Pos:abs Top/left (why)
      • Use CSS animations for visual and non-requirement effects
      • Use requestAnimationFrame()
      • DocumentFragment for holding changes

      .CSS {}


      • Leverage transitions and transforms
      • CSS code is always lighter than images
      • Use javascript fallbacks and leverage CSSPIE usage for old browsers
      • Don't use @import unless you are using SASS

      using CHROME inspector panel


      • Live edit 
      • Breakpoints
      • Watch Memory
      • Don't abuse the Garbage Collector
      • Pretty code for debugging and inspection
      • Under the hood
        • Keep lower than 60 FPS, especially for heavy animation apps
        • Rules
        • chrome://flags/


      more tools


      • Google Canary
      • JSPref
      • Chrome Inspector/Firebug
      • Weiner (Remote Debug)
      • Livereload.com



      questions?



      thanks!!

      other resources


      web-app-performance

      By Gustavo Simon

      web-app-performance

      • 1,875