SYMFONY
  PERFORMANCE
           Paul Thrasher
@thrashr888 | github.com/thrashr888
  Sr. Software Engineer at Dogster

    SF Symfony Meetup October
            #sfsymfony
WHY WORRY ABOUT
                PERFORMANCE?
                                                yo u
                                                     an d
                                                   V
•   Google cares about user happiness, Google owns your
    search traffic

    ...so Google put page speed in PageRank (and crawl speed)

•   Your site is more trustworthy and less frustrating

•   Increase page views and ad impressions

•   Increase conversions and revenue! It pays for itself!

•   Bonus: run less app servers
DOGSTER, INC.

• Started   in 2004

• Catster.com   is the same codebase

• ~2MM      monthly uniques

• ~12MM      monthly page views

• Over    1 million dogs and cats on our sites

• Production   servers: 5 app, 3 master DBs, 8 slave DBs

• Spent   the summer redesigning and working on performance
Backend Performance

  Benchmark, PHP, Database, Caching

  Symfony 1.4.X Performance

     You and your team, Caching

     Frontend Performance

Benchmark, HTML, JS, CSS, Images, CDN

        Questions at End
Backend
BACKEND - OPPORTUNITIES

Benchmark before you do anything!

• The    servers

• PHP

• Apache

• Database

• Your   crappy code

• Caching
Use siege or ab (Apache Benchmark)
  http://www.joedog.org/index/siege-home
thrashr888@Pauls-MacBook-Pro-2 workspace$ siege http://www.dogster.com
** SIEGE 2.69
** Preparing 50 concurrent users for battle.
The server is now under siege...
 12: HTTP/1.1 200 0.65 secs: 11063 bytes ==> /
  5: HTTP/1.1 200 0.68 secs: 11062 bytes ==> /
 39: HTTP/1.1 200 0.70 secs: 11062 bytes ==> /
 28: HTTP/1.1 200 0.73 secs: 11031 bytes ==> /
  2: HTTP/1.1 200 0.74 secs: 11061 bytes ==> /
 31: HTTP/1.1 200 0.48 secs: 11032 bytes ==> /
 22: HTTP/1.1 200 0.48 secs: 11063 bytes ==> /
  2: HTTP/1.1 200 0.46 secs: 11062 bytes ==> /
  6: HTTP/1.1 200 0.46 secs: 11031 bytes ==> /
  5: HTTP/1.1 200 0.47 secs: 11063 bytes ==> /
^C
Lifting the server siege...   done.
Transactions:             224 hits
Availability:          100.00 %
Elapsed time:                5.11 secs
Data transferred:        2.36 MB
Response time:               0.55 secs
Transaction rate:            43.84 trans/sec
Throughput:              0.46 MB/sec
Concurrency:            24.24
Successful transactions:        224
Failed transactions:           0
Longest transaction:         1.58
Shortest transaction:        0.32
BACKEND - PHP 5.3
  Migrate to PHP 5.3 http://github.com/smalyshev/migrate/
thrashr888@MacBook workspace$ php migrate.php SymSters
WARNING: Function 'spliti' is deprecated, please use 'preg_split' instead in file SymSters/lib/vendor/symfony/lib/
plugins/sfDoctrinePlugin/lib/vendor/doctrine/Doctrine/Connection/Mssql.php line 173
WARNING: Function 'spliti' is deprecated, please use 'preg_split' instead in file SymSters/lib/vendor/symfony/lib/
plugins/sfDoctrinePlugin/lib/vendor/doctrine/Doctrine/Connection/Mssql.php line 192
WARNING: Function 'ereg' is deprecated, please use 'preg_match' instead in file SymSters/lib/vendor/symfony/lib/
plugins/sfPropelPlugin/lib/vendor/phing/lib/Zip.php line 1852
WARNING: Function 'ereg' is deprecated, please use 'preg_match' instead in file SymSters/lib/vendor/symfony/lib/
plugins/sfPropelPlugin/lib/vendor/phing/lib/Zip.php line 2735
WARNING: Function 'split' is deprecated, please use 'explode' or 'preg_split' instead in file SymSters/lib/vendor/
symfony/lib/plugins/sfPropelPlugin/lib/vendor/phing/tasks/ext/coverage/CoverageReportTask.php line 168
WARNING: Function 'set_magic_quotes_runtime' is deprecated, its use is no longer recommended in file SymSters/lib/
vendor/symfony/lib/vendor/swiftmailer/classes/Swift/ByteStream/FileByteStream.php line 82
WARNING: Function 'set_magic_quotes_runtime' is deprecated, its use is no longer recommended in file SymSters/lib/
vendor/symfony/lib/vendor/swiftmailer/classes/Swift/ByteStream/FileByteStream.php line 87
WARNING: Function 'set_magic_quotes_runtime' is deprecated, its use is no longer recommended in file SymSters/lib/
vendor/symfony/lib/vendor/swiftmailer/classes/Swift/KeyCache/DiskKeyCache.php line 174
WARNING: Function 'set_magic_quotes_runtime' is deprecated, its use is no longer recommended in file SymSters/lib/
vendor/symfony/lib/vendor/swiftmailer/classes/Swift/KeyCache/DiskKeyCache.php line 183
WARNING: Function 'set_magic_quotes_runtime' is deprecated, its use is no longer recommended in file SymSters/lib/
vendor/symfony/lib/vendor/swiftmailer/classes/Swift/KeyCache/DiskKeyCache.php line 202
WARNING: Function 'set_magic_quotes_runtime' is deprecated, its use is no longer recommended in file SymSters/lib/
vendor/symfony/lib/vendor/swiftmailer/classes/Swift/KeyCache/DiskKeyCache.php line 210
WARNING: Function 'ereg' is deprecated, please use 'preg_match' instead in file SymSters/plugins/sfPropel15Plugin/
lib/vendor/phing/lib/Zip.php line 1852
WARNING: Function 'ereg' is deprecated, please use 'preg_match' instead in file SymSters/plugins/sfPropel15Plugin/
lib/vendor/phing/lib/Zip.php line 2735
BACKEND - MYSQL SLOW QUERY LOG
Count      : 55 (5.46%)
Time       : 204.477485 s total, 3.717772 s avg, 1.007915 s to 20.940426 s max (9.81%)
95% of Time : 160.326234 s total, 3.083197 s avg, 1.007915 s to 9.951604 s max
Lock Time (s) : 2.507 ms total, 46  avg, 34   to 65   max (1.86%)
95% of Lock : 2.318 ms total, 45   avg, 34   to 61   max
Rows sent : 3 avg, 3 to 3 max (0.00%)
Rows examined : 14.69k avg, 311 to 112.50k max (0.12%)
Database      : starster
EXPLAIN        : 14369 produced, 2278976448465661 read
    id: 1
    select_type: SIMPLE
    table: p
    type: ref
    possible_keys: pub_index,user_id_idx,NI_PET_CODE
    key: user_id_idx
    key_len: 3
    ref: const
    rows: 1732
    Extra: Using where; Using filesort

Query abstract:
SET timestamp=N; SELECT p.post_id, p.body, p.pet_id, p.thread_id, p.main_topic_id FROM forums_post_new p
WHERE p.pub_status != 'S' AND p.user_id = 'S' AND p.pet_code = 'S' ORDER BY p.post_id DESC LIMIT N;

Query sample:
SET timestamp=1286803854;
SELECT p.post_id, p.body, p.pet_id, p.thread_id, p.main_topic_id FROM forums_post_new p WHERE p.pub_status !=
'n' AND p.user_id = '243549' AND p.pet_code = 'd' ORDER BY p.post_id DESC LIMIT 3;
BACKEND - OTHER METHODS

• Setup   timers, refactor and cache slow code

• Memcache, APC      cache, etc.

• Add   app and DB servers

• Use Twig   for layouts, it uses file-based caching
Don’t get too caught up here
unless there are major issues.
Symfony
The big secret to better
performance with Symfony is…
…you’re already doing it.
  (Symfony improves team performance!)
Symfony already does a few other things for you:

• caches   settings and config

• keeps   junk off production servers

• provides   caching framework to make your caching easier

• Core    Compilation (turns 30 files into 1 file)

• BUT    Symfony is for apps, not speedy scripts

• Symfony    performance mostly means caching…
SYMFONY - PROJECT:OPTIMIZE
thrashr888@MacBook workspace$ php symfony project:optimize api prod
>> sfPatternRouting Connect sfRoute "sf_guard_signin" (/login)
>> sfPatternRouting Connect sfRoute "sf_guard_signout" (/logout)
>> sfPatternRouting Connect sfRoute "sf_guard_password" (/request_password)
>> sfPatternRouting Connect sfPropelRoute "sf_guard_user" (/sf_guard_user.:sf_format)
>> sfPatternRouting Connect sfPropelRoute "sf_guard_user_new" (/sf_guard_user/new.:sf_format)
>> sfPatternRouting Connect sfPropelRoute "sf_guard_user_create" (/sf_guard_user.:sf_format)
>> sfPatternRouting Connect sfPropelRoute "sf_guard_user_edit" (/sf_guard_user/:id/edit.:sf_format)
>> sfPatternRouting Connect sfPropelRoute "sf_guard_user_update" (/sf_guard_user/:id.:sf_format)
>> sfPatternRouting Connect sfPropelRoute "sf_guard_user_delete" (/sf_guard_user/:id.:sf_format)
>> sfPatternRouting Connect sfPropelRoute "sf_guard_user_show" (/sf_guard_user/:id.:sf_format)
>> sfPatternRouting Connect sfPropelRoute "sf_guard_user_object" (/sf_guard_user/:id/:action.:sf_format)
>> sfPatternRouting Connect sfPropelRoute "sf_guard_user_collection" (/sf_guard_user/:action/action.:sf_format)
>> sfPatternRouting Connect sfRoute "sf_guard_signin" (/login)
>> sfPatternRouting Connect sfRoute "sf_guard_signout" (/logout)
>> sfPatternRouting Connect sfRoute "sf_guard_password" (/request_password)
>> sfPatternRouting Connect sfPropelRoute "sf_guard_user" (/sf_guard_user.:sf_format)
>> sfPatternRouting Connect sfPropelRoute "sf_guard_user_new" (/sf_guard_user/new.:sf_format)
>> sfPatternRouting Connect sfPropelRoute "sf_guard_user_create" (/sf_guard_user.:sf_format)
>> sfPatternRouting Connect sfPropelRoute "sf_guard_user_edit" (/sf_guard_user/:id/edit.:sf_format)
>> sfPatternRouting Connect sfPropelRoute "sf_guard_user_update" (/sf_guard_user/:id.:sf_format)
>> sfPatternRouting Connect sfPropelRoute "sf_guard_user_delete" (/sf_guard_user/:id.:sf_format)
>> sfPatternRouting Connect sfPropelRoute "sf_guard_user_show" (/sf_guard_user/:id.:sf_format)
>> sfPatternRouting Connect sfPropelRoute "sf_guard_user_object" (/sf_guard_user/:id/:action.:sf_format)
>> sfPatternRouting Connect sfPropelRoute "sf_guard_user_collection" (/sf_guard_user/:action/action.:sf_format)
>> dir+    /Users/thrashr888/workspace/SymSters/cache/api/prod/config
>> file+ /Users/thrashr888/workspace/SymSters/cache/api/prod/config/configuration.php
SYMFONY - VIEW CACHE

# apps/frontend/config/settings.yml
prod:
  .settings:
    cache:           true

# apps/frontend/config/cache.yml
default:
  enabled:     false
  with_layout: false
  lifetime:    86400

# apps/frontend/modules/homepage/config/cache.yml
index:
  enabled:     true
all:
  with_layout: true




  http://www.symfony-project.org/jobeet/1_4/Doctrine/en/21
SYMFONY - ACTION CACHE



Just cache the action, not the views:
 # apps/frontend/modules/homepage/config/cache.yml
 all:
   with_layout: false




  http://www.symfony-project.org/jobeet/1_4/Doctrine/en/21
SYMFONY - PARTIAL CACHE


Just give it the name of the partial file:
 # apps/frontend/modules/homepage/config/cache.yml
 index:
   enabled:     true

 _sidebar:
   enabled:     true

 all:
   with_layout: true




  http://www.symfony-project.org/jobeet/1_4/Doctrine/en/21
SYMFONY - FUNCTION CACHE


You can cache many function calls:
 <?php

 $dog = new Dog();

 $cache = new sfMemcacheCache();
 $func = new sfFunctionCache($cache);

 $func->call(array($dog, 'getFriends'), array('25'));
SYMFONY - TEMPLATE CACHE


Cache expensive bits of your template:
 <?php if (!cache('name')): ?>

   <div id="dogs">
     <?php foreach($dogs as $dog): ?>
       <div id="<?php echo $dog->id ?>" class="dog"><?php
 echo $dog->name ?></div>
     <?php endforeach; ?>
   </div>

   <?php cache_save() ?>
 <?php endif; ?>
Stop worrying so much about
speeding up your backend because…
Frontend
DOGSTER.COM
Uncached page load
URL            domain          timeline
      status            size
DOGSTER.COM




    GOOD      {
DOGSTER.COM




 Not so good
               {
FRONTEND - HOW DO WE FIX THIS?



   Less HTML, JS, CSS   Faster JS

   Less images          Faster CSS

   Less photoshop       Faster images
     (more HTML)
FRONTEND - LESS IS MORE
Less HTML, JS, CSS

• Remove    code you’re not using

• Concat   files together for lower HTTP requests

Less images

• Make    design decisions to remove images

• Use   sprites for less HTTP requests

Less Photoshop, more HTML

• Don’t   go crazy with Photoshop when you’re designing
FRONTEND - FASTER DOWNLOADS

Faster JavaScript

• Be   careful about where and how you place your JS

Faster CSS

• Minify   and gzip your files

Faster images

• Compress     your images before uploading
GUEST SPEAKER
  YUKO TAKAHASHI
DESIGNER AT DOGSTER
FRONT END
CSS SPRITES :: IMAGE OPTIMIZATION :: CSS3
actual image: 1271 pixels x 1230 pixels
via: http://kenmat.tumblr.com/post/121458457/buildingssheet7dv-png
WHAT IS A CSS SPRITE?

•Asingle image that
contains a series of smaller
images
CSS SPRITE - BUTTON EXAMPLES




digicliff




               webair
THE CSS IS EASY AS PIE

• CSScalls and positions the sprite with
 background-image and background-position properties

     .image {
         background-image:
            url(http://www.website.com/images/sprite-image.png);
         background-position: 0px 100px;
         width: 100px;
         height: 50px;
          }



• See?   Easy as pie!
WHY USE CSS SPRITES?

• Reduce   the number of HTTP Requests to server

• Improves   load time of your website

• Faster
       load time on your pages means better search engine
 page ranking
EXAMPLE

• Dogster global elements used 32 images that were
 “sprite-able”. We tiled all 32 images onto one image

• Combined   32 images = 170 KB
 Single sprite image = 70 KB
HOW TO CREATE CSS SPRITES

• Option      1: Create them manually

• Option      2: Use a Sprite generator

 • SpriteMe      – http://spriteme.org/

 • Project    Fondue CSS Sprite generator -
  http://spritegen.website-performance.org/


 • SmartSprites        - http://csssprites.org/
IMAGE OPTIMIZATION

Using image compression tools to make sure your files are as
small as they can be

 • OptiPNG      - http://optipng.sourceforge.net/

 • Image   Optimizer - http://www.imageoptimizer.net/Pages/Home.aspx

 • PNG   Crusher - http://www.amake.us/software/pngcrusher/
IMAGE OPTIMIZATION (CONT’D.)

Avoid using text images, i.e., images that just contain text.
Try to use a font service instead:

  • Typekit   - http://typekit.com/

  • Font-Squirrel      (free!) - http://www.fontsquirrel.com/

  • FontFont     - http://www.fontfont.com/

  • Google    Fonts - http://code.google.com/webfonts
POWER OF CSS3

Use cool CSS3 style effects - enables you to style WITHOUT
images

 • Rounded   corners, drop shadows, gradients




                                          #findAVetMain {
                                               -moz-border-radius:10px 10px 10px 10px;
                                               -moz-box-shadow:0 0 8px #666666;
                                               background-color:#FFFFFF;
                                               border:1px solid #999999;
                                               height:180px;
                                               margin:10px 0 20px;
                                          }
LESS PHOTOSHOP, MORE HTML

When designing mockups for your site, think of how it will get
built with html and css

  • E.g. Does  your nav bar really need an image for each item?
   style it with css using a UL

  • Think   of how you can build each element without an image

  • Build
        it with clean HTML - don’t stick everything in a div.
   Use your H1s, your Ps, ULs, etc...and it will perform better
THANKS EVERYONE!
CSS SPRITE RESOURCES

• http://www.alistapart.com/articles/sprites/

• http://css-tricks.com/holy-sprites/

• http://css-tricks.com/css-sprites/

• http://www.smashingmagazine.com/2009/04/27/the-mystery-
 of-css-sprites-techniques-tools-and-tutorials/
FRONTEND - IMPLEMENTATIONS

LABjs

• Download    your JS files in parallel

CDN: Amazon S3 and CloudFront

• Give   your assets a proper home

Quarantine Your Ads

• They   can be a pain, put them in a box
FRONTEND - LABJS
Use LABjs to download your JS in parallel
  <script type="text/javascript" src="http://remote.tld/jquery.js"></script>
  <script type="text/javascript" src="local/plugin1.jquery.js"></script>
  <script type="text/javascript" src="local/plugin2.jquery.js"></script>
  <script type="text/javascript" src="local/init.js"></script>
  <script type="text/javascript">
    initMyPage();
  </script>


  <script type="text/javascript" src="LAB.js"></script>
  <script type="text/javascript">
  $LAB
  .script("http://remote.tld/jquery.js").wait()
  .script("/local/plugin1.jquery.js")
  .script("/local/plugin2.jquery.js").wait()
  .script("/local/init.js").wait(function(){
    initMyPage();
  });
  </script>
JS Loading Asynchronously
FRONTEND - JAVASCRIPT
Also move inline scripts to bottom of HTML body
  <!DOCTYPE html>
  <html>
  <body>
    <p>NO</p>
    <script>sleep(2);</script>
    <p>'TIL BROOKLYN</p>
  </body>
  </html>


  <!DOCTYPE html>
  <html>
  <body>
    <p>Don't block me, bro!</p>
    <script>(function(){sleep(2);})();</script>
    <script>$({sleep(2);});</script>
    <script>$(document).ready(function(){sleep(2);});</script>
  </body>
  </html>
Assets mostly load
 before JS scripts
FRONTEND - CDN ADVANTAGES

Use a CDN, or giving your assets the home they deserve. There are
several advantages to using Amazon’s CDN.

•   Geographical edge caching brings files closer to your users

•   Purposefully set HTTP headers

•   Cookie-less domain

•   No need to use Apache/PHP to serve assets

•   Overall quicker downloads

•   Easy to round-robin domains
FRONTEND - STATIC FILES

Two classes of assets you’ll be serving:

Static
http://a1.cdnsters.com/static/images/slideshow/220x220rainydaydog.jpg


•   Files that rarely change

•   Typically libraries and images

•   User generated content

•   We mirror our images FTP server every 15 minutes
FRONTEND - RELEASE FILES

Two classes of assets you’ll be serving:

Release
http://a2.cdnsters.com/releases/20101014-1128/topic/css/
main.min.css.gz


• Files   that might change each release

• Typically   related to the apps
FRONTEND - CDN IMPLEMENTATION
So, how do you implement S3 and CloudFront?

1. Concat files by hand or using scripts

2. Compress images with ImageOptim

3. Create Minified versions of your JS and CSS

4. Create gzipped versions of all files

5. “rsync” white-listed folders to S3, with proper headers

6. CloudFront automatically gets files from S3
  Bonus: https://gist.github.com/b82e5671e1f46760f0d9
  Also try: http://tinycdn.com/
FRONTEND - HTTP HEADERS



                  Expires
FRONTEND - HTTP HEADERS



                   Gzip
FRONTEND - HTTP HEADERS



                Content-Type
FRONTEND - ADS

Ads typically load external scripts that block page rendering. You’ll
probably want to quarantine your ads in some manner.

•   Ads really really suck

•   Place them in iframes

•   Insert placeholders in HTML that populate at end of page via
    Javascript

•   Async loading probably doesn’t work because of
    document.write() in ad scripts
                                  * Google likely does count ads in overall page speed time
WRAP UP

     Backend Performance

  Benchmark, PHP, Database, Caching

  Symfony 1.4.X Performance

     You and your team, Caching

     Frontend Performance

Benchmark, HTML, JS, CSS, Images, CDN
THANK YOU.
QUESTIONS?
SF Symfony Meetup
http://www.dogster.com/
                                                             #sfsymfony
http://www.joedog.org/index/siege-home
http://github.com/smalyshev/migrate/
http://dev.mysql.com/doc/refman/5.5/en/slow-query-log.html
http://www.symfony-project.org/jobeet/1_4/Doctrine/en/21
http://www.yotta.com/
http://www.webpagetest.org/
http://labjs.com/

More JS loading tips: http://jquerysbestfriends.com/

Rules for Faster-Loading Web Sites: http://stevesouders.com/hpws/rules.php

http://aws.amazon.com/s3/
http://aws.amazon.com/cloudfront/
http://tinycdn.com/
http://code.google.com/p/minify/
http://www.io.com/~maus/HttpKeepAlive.html

Bonus S3 Symfony Task: https://gist.github.com/b82e5671e1f46760f0d9

Yuko Takahashi                                                 Paul Thrasher
@yukodesigns                            @thrashr888 | github.com/thrashr888
UI/Interactive Designer at Dogster          Sr. Software Engineer at Dogster

Symfony Performance

  • 1.
    SYMFONY PERFORMANCE Paul Thrasher @thrashr888 | github.com/thrashr888 Sr. Software Engineer at Dogster SF Symfony Meetup October #sfsymfony
  • 2.
    WHY WORRY ABOUT PERFORMANCE? yo u an d V • Google cares about user happiness, Google owns your search traffic ...so Google put page speed in PageRank (and crawl speed) • Your site is more trustworthy and less frustrating • Increase page views and ad impressions • Increase conversions and revenue! It pays for itself! • Bonus: run less app servers
  • 3.
    DOGSTER, INC. • Started in 2004 • Catster.com is the same codebase • ~2MM monthly uniques • ~12MM monthly page views • Over 1 million dogs and cats on our sites • Production servers: 5 app, 3 master DBs, 8 slave DBs • Spent the summer redesigning and working on performance
  • 4.
    Backend Performance Benchmark, PHP, Database, Caching Symfony 1.4.X Performance You and your team, Caching Frontend Performance Benchmark, HTML, JS, CSS, Images, CDN Questions at End
  • 5.
  • 6.
    BACKEND - OPPORTUNITIES Benchmarkbefore you do anything! • The servers • PHP • Apache • Database • Your crappy code • Caching
  • 7.
    Use siege orab (Apache Benchmark) http://www.joedog.org/index/siege-home thrashr888@Pauls-MacBook-Pro-2 workspace$ siege http://www.dogster.com ** SIEGE 2.69 ** Preparing 50 concurrent users for battle. The server is now under siege... 12: HTTP/1.1 200 0.65 secs: 11063 bytes ==> / 5: HTTP/1.1 200 0.68 secs: 11062 bytes ==> / 39: HTTP/1.1 200 0.70 secs: 11062 bytes ==> / 28: HTTP/1.1 200 0.73 secs: 11031 bytes ==> / 2: HTTP/1.1 200 0.74 secs: 11061 bytes ==> / 31: HTTP/1.1 200 0.48 secs: 11032 bytes ==> / 22: HTTP/1.1 200 0.48 secs: 11063 bytes ==> / 2: HTTP/1.1 200 0.46 secs: 11062 bytes ==> / 6: HTTP/1.1 200 0.46 secs: 11031 bytes ==> / 5: HTTP/1.1 200 0.47 secs: 11063 bytes ==> / ^C Lifting the server siege... done. Transactions: 224 hits Availability: 100.00 % Elapsed time: 5.11 secs Data transferred: 2.36 MB Response time: 0.55 secs Transaction rate: 43.84 trans/sec Throughput: 0.46 MB/sec Concurrency: 24.24 Successful transactions: 224 Failed transactions: 0 Longest transaction: 1.58 Shortest transaction: 0.32
  • 8.
    BACKEND - PHP5.3 Migrate to PHP 5.3 http://github.com/smalyshev/migrate/ thrashr888@MacBook workspace$ php migrate.php SymSters WARNING: Function 'spliti' is deprecated, please use 'preg_split' instead in file SymSters/lib/vendor/symfony/lib/ plugins/sfDoctrinePlugin/lib/vendor/doctrine/Doctrine/Connection/Mssql.php line 173 WARNING: Function 'spliti' is deprecated, please use 'preg_split' instead in file SymSters/lib/vendor/symfony/lib/ plugins/sfDoctrinePlugin/lib/vendor/doctrine/Doctrine/Connection/Mssql.php line 192 WARNING: Function 'ereg' is deprecated, please use 'preg_match' instead in file SymSters/lib/vendor/symfony/lib/ plugins/sfPropelPlugin/lib/vendor/phing/lib/Zip.php line 1852 WARNING: Function 'ereg' is deprecated, please use 'preg_match' instead in file SymSters/lib/vendor/symfony/lib/ plugins/sfPropelPlugin/lib/vendor/phing/lib/Zip.php line 2735 WARNING: Function 'split' is deprecated, please use 'explode' or 'preg_split' instead in file SymSters/lib/vendor/ symfony/lib/plugins/sfPropelPlugin/lib/vendor/phing/tasks/ext/coverage/CoverageReportTask.php line 168 WARNING: Function 'set_magic_quotes_runtime' is deprecated, its use is no longer recommended in file SymSters/lib/ vendor/symfony/lib/vendor/swiftmailer/classes/Swift/ByteStream/FileByteStream.php line 82 WARNING: Function 'set_magic_quotes_runtime' is deprecated, its use is no longer recommended in file SymSters/lib/ vendor/symfony/lib/vendor/swiftmailer/classes/Swift/ByteStream/FileByteStream.php line 87 WARNING: Function 'set_magic_quotes_runtime' is deprecated, its use is no longer recommended in file SymSters/lib/ vendor/symfony/lib/vendor/swiftmailer/classes/Swift/KeyCache/DiskKeyCache.php line 174 WARNING: Function 'set_magic_quotes_runtime' is deprecated, its use is no longer recommended in file SymSters/lib/ vendor/symfony/lib/vendor/swiftmailer/classes/Swift/KeyCache/DiskKeyCache.php line 183 WARNING: Function 'set_magic_quotes_runtime' is deprecated, its use is no longer recommended in file SymSters/lib/ vendor/symfony/lib/vendor/swiftmailer/classes/Swift/KeyCache/DiskKeyCache.php line 202 WARNING: Function 'set_magic_quotes_runtime' is deprecated, its use is no longer recommended in file SymSters/lib/ vendor/symfony/lib/vendor/swiftmailer/classes/Swift/KeyCache/DiskKeyCache.php line 210 WARNING: Function 'ereg' is deprecated, please use 'preg_match' instead in file SymSters/plugins/sfPropel15Plugin/ lib/vendor/phing/lib/Zip.php line 1852 WARNING: Function 'ereg' is deprecated, please use 'preg_match' instead in file SymSters/plugins/sfPropel15Plugin/ lib/vendor/phing/lib/Zip.php line 2735
  • 9.
    BACKEND - MYSQLSLOW QUERY LOG Count : 55 (5.46%) Time : 204.477485 s total, 3.717772 s avg, 1.007915 s to 20.940426 s max (9.81%) 95% of Time : 160.326234 s total, 3.083197 s avg, 1.007915 s to 9.951604 s max Lock Time (s) : 2.507 ms total, 46 avg, 34 to 65 max (1.86%) 95% of Lock : 2.318 ms total, 45 avg, 34 to 61 max Rows sent : 3 avg, 3 to 3 max (0.00%) Rows examined : 14.69k avg, 311 to 112.50k max (0.12%) Database : starster EXPLAIN : 14369 produced, 2278976448465661 read id: 1 select_type: SIMPLE table: p type: ref possible_keys: pub_index,user_id_idx,NI_PET_CODE key: user_id_idx key_len: 3 ref: const rows: 1732 Extra: Using where; Using filesort Query abstract: SET timestamp=N; SELECT p.post_id, p.body, p.pet_id, p.thread_id, p.main_topic_id FROM forums_post_new p WHERE p.pub_status != 'S' AND p.user_id = 'S' AND p.pet_code = 'S' ORDER BY p.post_id DESC LIMIT N; Query sample: SET timestamp=1286803854; SELECT p.post_id, p.body, p.pet_id, p.thread_id, p.main_topic_id FROM forums_post_new p WHERE p.pub_status != 'n' AND p.user_id = '243549' AND p.pet_code = 'd' ORDER BY p.post_id DESC LIMIT 3;
  • 10.
    BACKEND - OTHERMETHODS • Setup timers, refactor and cache slow code • Memcache, APC cache, etc. • Add app and DB servers • Use Twig for layouts, it uses file-based caching
  • 11.
    Don’t get toocaught up here unless there are major issues.
  • 12.
  • 13.
    The big secretto better performance with Symfony is…
  • 14.
    …you’re already doingit. (Symfony improves team performance!)
  • 15.
    Symfony already doesa few other things for you: • caches settings and config • keeps junk off production servers • provides caching framework to make your caching easier • Core Compilation (turns 30 files into 1 file) • BUT Symfony is for apps, not speedy scripts • Symfony performance mostly means caching…
  • 16.
    SYMFONY - PROJECT:OPTIMIZE thrashr888@MacBookworkspace$ php symfony project:optimize api prod >> sfPatternRouting Connect sfRoute "sf_guard_signin" (/login) >> sfPatternRouting Connect sfRoute "sf_guard_signout" (/logout) >> sfPatternRouting Connect sfRoute "sf_guard_password" (/request_password) >> sfPatternRouting Connect sfPropelRoute "sf_guard_user" (/sf_guard_user.:sf_format) >> sfPatternRouting Connect sfPropelRoute "sf_guard_user_new" (/sf_guard_user/new.:sf_format) >> sfPatternRouting Connect sfPropelRoute "sf_guard_user_create" (/sf_guard_user.:sf_format) >> sfPatternRouting Connect sfPropelRoute "sf_guard_user_edit" (/sf_guard_user/:id/edit.:sf_format) >> sfPatternRouting Connect sfPropelRoute "sf_guard_user_update" (/sf_guard_user/:id.:sf_format) >> sfPatternRouting Connect sfPropelRoute "sf_guard_user_delete" (/sf_guard_user/:id.:sf_format) >> sfPatternRouting Connect sfPropelRoute "sf_guard_user_show" (/sf_guard_user/:id.:sf_format) >> sfPatternRouting Connect sfPropelRoute "sf_guard_user_object" (/sf_guard_user/:id/:action.:sf_format) >> sfPatternRouting Connect sfPropelRoute "sf_guard_user_collection" (/sf_guard_user/:action/action.:sf_format) >> sfPatternRouting Connect sfRoute "sf_guard_signin" (/login) >> sfPatternRouting Connect sfRoute "sf_guard_signout" (/logout) >> sfPatternRouting Connect sfRoute "sf_guard_password" (/request_password) >> sfPatternRouting Connect sfPropelRoute "sf_guard_user" (/sf_guard_user.:sf_format) >> sfPatternRouting Connect sfPropelRoute "sf_guard_user_new" (/sf_guard_user/new.:sf_format) >> sfPatternRouting Connect sfPropelRoute "sf_guard_user_create" (/sf_guard_user.:sf_format) >> sfPatternRouting Connect sfPropelRoute "sf_guard_user_edit" (/sf_guard_user/:id/edit.:sf_format) >> sfPatternRouting Connect sfPropelRoute "sf_guard_user_update" (/sf_guard_user/:id.:sf_format) >> sfPatternRouting Connect sfPropelRoute "sf_guard_user_delete" (/sf_guard_user/:id.:sf_format) >> sfPatternRouting Connect sfPropelRoute "sf_guard_user_show" (/sf_guard_user/:id.:sf_format) >> sfPatternRouting Connect sfPropelRoute "sf_guard_user_object" (/sf_guard_user/:id/:action.:sf_format) >> sfPatternRouting Connect sfPropelRoute "sf_guard_user_collection" (/sf_guard_user/:action/action.:sf_format) >> dir+ /Users/thrashr888/workspace/SymSters/cache/api/prod/config >> file+ /Users/thrashr888/workspace/SymSters/cache/api/prod/config/configuration.php
  • 17.
    SYMFONY - VIEWCACHE # apps/frontend/config/settings.yml prod: .settings: cache: true # apps/frontend/config/cache.yml default: enabled: false with_layout: false lifetime: 86400 # apps/frontend/modules/homepage/config/cache.yml index: enabled: true all: with_layout: true http://www.symfony-project.org/jobeet/1_4/Doctrine/en/21
  • 18.
    SYMFONY - ACTIONCACHE Just cache the action, not the views: # apps/frontend/modules/homepage/config/cache.yml all: with_layout: false http://www.symfony-project.org/jobeet/1_4/Doctrine/en/21
  • 19.
    SYMFONY - PARTIALCACHE Just give it the name of the partial file: # apps/frontend/modules/homepage/config/cache.yml index: enabled: true _sidebar: enabled: true all: with_layout: true http://www.symfony-project.org/jobeet/1_4/Doctrine/en/21
  • 20.
    SYMFONY - FUNCTIONCACHE You can cache many function calls: <?php $dog = new Dog(); $cache = new sfMemcacheCache(); $func = new sfFunctionCache($cache); $func->call(array($dog, 'getFriends'), array('25'));
  • 21.
    SYMFONY - TEMPLATECACHE Cache expensive bits of your template: <?php if (!cache('name')): ?> <div id="dogs"> <?php foreach($dogs as $dog): ?> <div id="<?php echo $dog->id ?>" class="dog"><?php echo $dog->name ?></div> <?php endforeach; ?> </div> <?php cache_save() ?> <?php endif; ?>
  • 22.
    Stop worrying somuch about speeding up your backend because…
  • 23.
  • 25.
  • 26.
    URL domain timeline status size
  • 27.
  • 28.
  • 29.
    FRONTEND - HOWDO WE FIX THIS? Less HTML, JS, CSS Faster JS Less images Faster CSS Less photoshop Faster images (more HTML)
  • 30.
    FRONTEND - LESSIS MORE Less HTML, JS, CSS • Remove code you’re not using • Concat files together for lower HTTP requests Less images • Make design decisions to remove images • Use sprites for less HTTP requests Less Photoshop, more HTML • Don’t go crazy with Photoshop when you’re designing
  • 31.
    FRONTEND - FASTERDOWNLOADS Faster JavaScript • Be careful about where and how you place your JS Faster CSS • Minify and gzip your files Faster images • Compress your images before uploading
  • 32.
    GUEST SPEAKER YUKO TAKAHASHI DESIGNER AT DOGSTER
  • 33.
    FRONT END CSS SPRITES:: IMAGE OPTIMIZATION :: CSS3
  • 34.
    actual image: 1271pixels x 1230 pixels via: http://kenmat.tumblr.com/post/121458457/buildingssheet7dv-png
  • 35.
    WHAT IS ACSS SPRITE? •Asingle image that contains a series of smaller images
  • 36.
    CSS SPRITE -BUTTON EXAMPLES digicliff webair
  • 37.
    THE CSS ISEASY AS PIE • CSScalls and positions the sprite with background-image and background-position properties .image { background-image: url(http://www.website.com/images/sprite-image.png); background-position: 0px 100px; width: 100px; height: 50px; } • See? Easy as pie!
  • 38.
    WHY USE CSSSPRITES? • Reduce the number of HTTP Requests to server • Improves load time of your website • Faster load time on your pages means better search engine page ranking
  • 39.
    EXAMPLE • Dogster globalelements used 32 images that were “sprite-able”. We tiled all 32 images onto one image • Combined 32 images = 170 KB Single sprite image = 70 KB
  • 40.
    HOW TO CREATECSS SPRITES • Option 1: Create them manually • Option 2: Use a Sprite generator • SpriteMe – http://spriteme.org/ • Project Fondue CSS Sprite generator - http://spritegen.website-performance.org/ • SmartSprites - http://csssprites.org/
  • 41.
    IMAGE OPTIMIZATION Using imagecompression tools to make sure your files are as small as they can be • OptiPNG - http://optipng.sourceforge.net/ • Image Optimizer - http://www.imageoptimizer.net/Pages/Home.aspx • PNG Crusher - http://www.amake.us/software/pngcrusher/
  • 42.
    IMAGE OPTIMIZATION (CONT’D.) Avoidusing text images, i.e., images that just contain text. Try to use a font service instead: • Typekit - http://typekit.com/ • Font-Squirrel (free!) - http://www.fontsquirrel.com/ • FontFont - http://www.fontfont.com/ • Google Fonts - http://code.google.com/webfonts
  • 43.
    POWER OF CSS3 Usecool CSS3 style effects - enables you to style WITHOUT images • Rounded corners, drop shadows, gradients #findAVetMain { -moz-border-radius:10px 10px 10px 10px; -moz-box-shadow:0 0 8px #666666; background-color:#FFFFFF; border:1px solid #999999; height:180px; margin:10px 0 20px; }
  • 44.
    LESS PHOTOSHOP, MOREHTML When designing mockups for your site, think of how it will get built with html and css • E.g. Does your nav bar really need an image for each item? style it with css using a UL • Think of how you can build each element without an image • Build it with clean HTML - don’t stick everything in a div. Use your H1s, your Ps, ULs, etc...and it will perform better
  • 45.
  • 46.
    CSS SPRITE RESOURCES •http://www.alistapart.com/articles/sprites/ • http://css-tricks.com/holy-sprites/ • http://css-tricks.com/css-sprites/ • http://www.smashingmagazine.com/2009/04/27/the-mystery- of-css-sprites-techniques-tools-and-tutorials/
  • 47.
    FRONTEND - IMPLEMENTATIONS LABjs •Download your JS files in parallel CDN: Amazon S3 and CloudFront • Give your assets a proper home Quarantine Your Ads • They can be a pain, put them in a box
  • 48.
    FRONTEND - LABJS UseLABjs to download your JS in parallel <script type="text/javascript" src="http://remote.tld/jquery.js"></script> <script type="text/javascript" src="local/plugin1.jquery.js"></script> <script type="text/javascript" src="local/plugin2.jquery.js"></script> <script type="text/javascript" src="local/init.js"></script> <script type="text/javascript"> initMyPage(); </script> <script type="text/javascript" src="LAB.js"></script> <script type="text/javascript"> $LAB .script("http://remote.tld/jquery.js").wait() .script("/local/plugin1.jquery.js") .script("/local/plugin2.jquery.js").wait() .script("/local/init.js").wait(function(){ initMyPage(); }); </script>
  • 49.
  • 50.
    FRONTEND - JAVASCRIPT Alsomove inline scripts to bottom of HTML body <!DOCTYPE html> <html> <body> <p>NO</p> <script>sleep(2);</script> <p>'TIL BROOKLYN</p> </body> </html> <!DOCTYPE html> <html> <body> <p>Don't block me, bro!</p> <script>(function(){sleep(2);})();</script> <script>$({sleep(2);});</script> <script>$(document).ready(function(){sleep(2);});</script> </body> </html>
  • 51.
    Assets mostly load before JS scripts
  • 52.
    FRONTEND - CDNADVANTAGES Use a CDN, or giving your assets the home they deserve. There are several advantages to using Amazon’s CDN. • Geographical edge caching brings files closer to your users • Purposefully set HTTP headers • Cookie-less domain • No need to use Apache/PHP to serve assets • Overall quicker downloads • Easy to round-robin domains
  • 53.
    FRONTEND - STATICFILES Two classes of assets you’ll be serving: Static http://a1.cdnsters.com/static/images/slideshow/220x220rainydaydog.jpg • Files that rarely change • Typically libraries and images • User generated content • We mirror our images FTP server every 15 minutes
  • 54.
    FRONTEND - RELEASEFILES Two classes of assets you’ll be serving: Release http://a2.cdnsters.com/releases/20101014-1128/topic/css/ main.min.css.gz • Files that might change each release • Typically related to the apps
  • 55.
    FRONTEND - CDNIMPLEMENTATION So, how do you implement S3 and CloudFront? 1. Concat files by hand or using scripts 2. Compress images with ImageOptim 3. Create Minified versions of your JS and CSS 4. Create gzipped versions of all files 5. “rsync” white-listed folders to S3, with proper headers 6. CloudFront automatically gets files from S3 Bonus: https://gist.github.com/b82e5671e1f46760f0d9 Also try: http://tinycdn.com/
  • 56.
    FRONTEND - HTTPHEADERS Expires
  • 57.
    FRONTEND - HTTPHEADERS Gzip
  • 58.
    FRONTEND - HTTPHEADERS Content-Type
  • 59.
    FRONTEND - ADS Adstypically load external scripts that block page rendering. You’ll probably want to quarantine your ads in some manner. • Ads really really suck • Place them in iframes • Insert placeholders in HTML that populate at end of page via Javascript • Async loading probably doesn’t work because of document.write() in ad scripts * Google likely does count ads in overall page speed time
  • 60.
    WRAP UP Backend Performance Benchmark, PHP, Database, Caching Symfony 1.4.X Performance You and your team, Caching Frontend Performance Benchmark, HTML, JS, CSS, Images, CDN
  • 61.
  • 62.
    SF Symfony Meetup http://www.dogster.com/ #sfsymfony http://www.joedog.org/index/siege-home http://github.com/smalyshev/migrate/ http://dev.mysql.com/doc/refman/5.5/en/slow-query-log.html http://www.symfony-project.org/jobeet/1_4/Doctrine/en/21 http://www.yotta.com/ http://www.webpagetest.org/ http://labjs.com/ More JS loading tips: http://jquerysbestfriends.com/ Rules for Faster-Loading Web Sites: http://stevesouders.com/hpws/rules.php http://aws.amazon.com/s3/ http://aws.amazon.com/cloudfront/ http://tinycdn.com/ http://code.google.com/p/minify/ http://www.io.com/~maus/HttpKeepAlive.html Bonus S3 Symfony Task: https://gist.github.com/b82e5671e1f46760f0d9 Yuko Takahashi Paul Thrasher @yukodesigns @thrashr888 | github.com/thrashr888 UI/Interactive Designer at Dogster Sr. Software Engineer at Dogster

Editor's Notes

  • #3 Question: Who&apos;s already worrying about performance and doing something about it?
  • #32 1. Cut out code you&amp;#x2019;re not using 2. Make design decisions to cut out more images, use sprites 3. Don&amp;#x2019;t go crazy with Photoshop when you&amp;#x2019;re designing 4. Be careful about where you place your JS 5. Minify and gzip your files 6. Compress your images Use correct headers for your assets, we&amp;#x2019;ll go over that later.
  • #34 Use correct headers for your assets, we&amp;#x2019;ll go over that later.
  • #36 intro role at dogster excited to be here...wooo
  • #37 origins of css sprite Started off in video gaming: sprites were used to build visual effects in games Has evolved to being used on all kinds of websites, like Yahoo, Facebook and Google.
  • #38 Sprites are often confused as being a series of images, but it&amp;#x2019;s actually one large image Small images like buttons, roll-over or hover state, icons, logos, any small graphics Examples And they can be absurdly huge: Yahoo has one that is 380 pixels by 4314 pixels. It&amp;#x2019;s only 12KB
  • #39 Examples of button states used in a sprite
  • #40 Simple example of how css looks - mainly using background image style that calls the image and X and Y coordinates for background-position styles
  • #41 -think of all the information that goes into the image file...there&amp;#x2019;s meta data, there&amp;#x2019;s a color table associated with each file, and so if you think of all that information in each image file, you can see how that can slow down your site - having a sprite reduces those number HTTP requests - and also makes the experience with images more seamless - classic example are rollover buttons. with a sprite having a static state and rollover state as one image - with CSS styling the hover class is seamless... - we may enjoy lightning fast download times in either our office or at home, but many of your users may not have that kind of speed, so we need to always keep in mind the user experience - if it doesn&amp;#x2019;t load, they&amp;#x2019;ll hit the back button -&amp;#x201C;sprite-able&amp;#x201D; - not all images should be used in sprites. ideal is buttons, icons, little graphics as you saw in the previous slide. no large images and no images that require a repeating background - dogster example: as a proof of concept, i took all the little images from the chrome, used a sprite generator that laid out all 32 images onto one large image and you can see the results
  • #42 global elements = chrome = ubernav, nav, footer
  • #43 Option 1 - take the widest image you have - that would be your width, then place all the images below. you can add as many as you want. the pain is figuring out all the coordinates Option 2 - Sprite generators make sprites super fast and super easy. the only problem is maintaining it - if you need to add images, you&amp;#x2019;d have to run it through again. - SpriteMe - bookmarklet service - Project Fondue - one i used. zip images, customiz how the images are laid out
  • #46 basic example that illustrates what you can do with css3
  • #50 Use correct headers for your assets, we&amp;#x2019;ll go over that later.