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/slowqueries.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 querying
MATCH(description) AGAINST ('dogs')
more resources
- Explain Syntax (http://dev.mysql.com/doc/refman/5.0/en/explain.html)
- Optimizing queries with EXPLAIN
- Performance tuning best practices
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
- APC Documentation
- WebGrind
- WinCacheGrind
- PHP performance tips, by Google
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>
<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
- 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
- Browser Plugins
- Real-Time Monitoring
- New Relic
-
Device speed simulation
Minify your assets, please!
- YUI Compressor (command line), Google Closure Tool, PageSpeed Insights, minify-maven-plugin
- Execution time libraries: make sure you will cache the generated output.
- For CCS, best practice: using along with SASS compilers.
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[...]
}
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
- FITC Web Performance and Optimization presentations
- Paul Irish
- Steve Sounders
- Marakana TechTV (Youtube Channel)
- Steve Sounders speaking about cache (Cache is King)
web-app-performance
By Gustavo Simon
web-app-performance
- 1,981