SlideShare a Scribd company logo
1 of 96
Lorenzo Alberton


Profile your PHP application
             and make it fly
               The path to performance
                          and scalability




             PHPNW, Saturday 9th October 2010
                                                1
Quiz time!

             Which is faster?




                                2
Quiz time!

             Which is faster?

  (A) echo               (B) print




                                     2
Quiz time!

             Which is faster?

  (A) echo
      single             (B) print
                             double
      quotes                 quotes




                                      2
Answer



         It probably doesn’t matter.




                                       3
Awareness is the




  Know your targets
  Know what it will take to meet them
  Know your constraints


                                        4
Tools: Profilers
 Tools are just tools
 They are absolutely essential
 to doing your job
 They will never do your job for you
 Tools will never replace
 experience and discipline
 But tools can help you
 maintain discipline

 Theo Schlossnagle
                                       5
Xdebug + xCacheGrind




                http://xdebug.org/
                http://valgrind.org/

              http://kcachegrind.sf.net/
        http://sf.net/projects/wincachegrind
        http://code.google.com/p/webgrind/
           http://www.maccallgrind.com/

                                               6
XHProf

                           XHProf




             http://mirror.facebook.net/facebook/xhprof/
                  http://pecl.php.net/package/xhprof

   http://techportal.ibuildings.com/2009/12/01/profiling-with-xhprof/


                                                                       7
XHProf UI Report - Web interface




                                   8
XHProf UI Report - Web interface




                                   8
XHProf UI Report - Web interface




                                   8
XHProf UI Report - Web interface


      Function Name
      Calls
      Wall Time (inclusive / exclusive)
      CPU (inclusive / exclusive)
      Memory (inclusive / exclusive)
      Peak Memory Use (inclusive / exclusive)

                     # and %


                                                8
XHProf UI - Trace calls




                          9
XHProf UI - Call Graph




                         10
XHProf UI - Call Graph




                         10
Measuring
 Analyse the framework
Analyse your application




                           11
Know Your Framework

 Measure the baseline
 Shortcuts aren’t always “free”
 When there are two ways of doing something,
 usually one is much better
 Loading (classes, resources) is expensive




                                               12
Zend Framework                 Baseline




     $ zf.sh create project testzf
                                          13
Know Your Framework

 Measure the baseline
 Shortcuts aren’t always “free”
 When there are two ways of doing something,
 usually one is much better
 Loading (classes, resources) is expensive




                                               14
Shortcuts - The Real Cost
 public function doSomething(array $data) {
    // Zend_Config object
    $config = $this->getConfig();
    $var = $config->aaa->bbb->ccc;
    // ...
 }




                                              15
Shortcuts - The Real Cost
 public function doSomething(array $data) {
    // Zend_Config object
    $config = $this->getConfig();
    $var = $config->aaa->bbb->ccc;
    // ...
 }




                                              15
Shortcuts - The Real Cost
 public function doSomething(array $data) {
    // Zend_Config object
    $config = $this->getConfig();
    $var = $config->aaa->bbb->ccc;
    // ...
 }




                                              15
Shortcuts - The Real Cost
 public function doSomething(array $data) {
    // Zend_Config object
    $config = $this->getConfig();
    $var = $config->aaa->bbb->ccc;
    // ...
 }



      2

      1
      3
                                              15
Know Your Framework

 Measure the baseline
 Shortcuts aren’t always “free”
 When there are two ways of doing something,
 usually one is much better
 Loading (classes, resources) is expensive




                                               16
partial() vs. render()


   <!-- mytemplate.phtml -->
   <ul>
       <?php
       foreach ($this->rows as $row) {
          $this->partial(‘listItemTemplate.phtml’,
                ‘mymodule’, array(‘data’ => $row);
       }
       ?>
   </ul>



                                                     17
partial() vs. render()




                         18
partial() vs. render()




                         18
partial() vs. render()




                         18
partial() vs. render()




                         18
partial() vs. render()




                         18
partial() vs. render()




                         18
partial() vs. render()




                         18
partial() vs. render()


   <!-- mytemplate.phtml -->
   <ul>
       <?php
       foreach ($this->rows as $row) {
          $this->partial(‘listItemTemplate.phtml’,
                ‘mymodule’, array(‘data’ => $row);
       }
       ?>
   </ul>



                                                     19
partial() vs. render()


   <!-- mytemplate.phtml -->
   <ul>
       <?php
       foreach ($this->rows as $row) {
                               $this->row) {
          $this->render(‘listItemTemplate.phtml’);
          $this->partial(‘listItemTemplate.phtml’,
       }        ‘mymodule’, array(‘data’ => $row);
       ?>
       }
   </ul>
       ?>
   </ul>



                                                     19
Know Your Framework

 Measure the baseline
 Shortcuts aren’t always “free”
 When there are two ways of doing something,
 usually one is much better
 Loading (classes, resources) is expensive




                                               20
Plugins / Helpers

  <!-- mytemplate.phtml -->
  <ul>
      <?php

     foreach ($this->rows as $row) {
        echo $this->myViewHelper($row);
     }

      ?>
  </ul>




                                          21
Plugins / Helpers

  // calling:
  // Zend_View_Abstract::__call()
  <!-- mytemplate.phtml -->
  // Zend_View_Abstract::getHelper()
  <ul>
  // Zend_View_Abstract::_getPlugin()
      <?php
  // Zend_View_Abstract::_getPluginLoader()
  // Zend_Loader_PluginLoader::load()
      foreach ($this->rows as $row) {
  // Zend_Loader_PluginLoader::isLoaded()
         echo $this->myViewHelper($row);
  // Zend_Loader_PluginLoader::getClassName()
      }
  // Zend_Loader_PluginLoader::_formatName()
  // Zend_View_Abstract::setView()
      ?>
  // call_user_func_array()
  </ul>
  // My_Helpers_MyViewHelper::myViewHelper()



                                                21
Plugins / Helpers

  <!-- mytemplate.phtml -->
  <ul>
      <?php

     foreach ($this->rows as $row) {
        echo $this->myViewHelper($row);
     }

      ?>
  </ul>




                                          21
Plugins / Helpers

  <!-- mytemplate.phtml -->
  <ul>
      <?php

      foreach
      $helper   = $this->getHelper('myViewHelper');
                ($this->rows as $row) {
         echo   $this->myViewHelper($row);
      foreach
      }         ($this->rows as $row) {
         echo   $helper->myViewHelper($row);
      }
      ?>
  </ul>
      ?>
  </ul>


                                                      21
Know Your Application




       Every feature has a cost. Measure it.
                                               22
Optimisation Techniques
 Tips and tricks to get faster applications




                                              23
Rules of thumb
 Profile / Measure
 Sort by [ Excl. CPU | Memory | Time | Calls ]
 Start from the TOP of the list
 Analyse, refactor, optimise
 Measure improvement
 Start over




                                                 24
Rules of thumb
 Profile / Measure
 Sort by [ Excl. CPU | Memory | Time | Calls ]
 Start from the TOP of the list
 Analyse, refactor, optimise
 Measure improvement
 Start over


                Again, and again, and again.
                                                 24
Profiling as Design validation practice




                                     25
Easy performance targets

 External resources (http, db, disk I/O)
 Memory-hungry function
 (xml/json parsers, output buffering)
 Loops
 Regular expressions
 Wrappers




                                           26
Refactoring hints


               PREPARE SCREEN
               showing db calls




                                  27
Refactoring hints


               PREPARE SCREEN
               showing db calls




                                  27
Refactoring hints




                    28
Refactoring hints




                    28
Refactoring hints




                    28
Refactoring hints




                    29
Refactoring hints

  PHP is FAST




                    29
Refactoring hints

  PHP is FAST

  ...but do you really need to call strtolower()
      15000 times?




                                                   29
Refactoring hints

  PHP is FAST

  ...but do you really need to call strtolower()
      15000 times?


       Re-think why you’re doing something,
            if it’s the right place to do it,
   and if possible reduce the amount of data you
                     need to process
                                                   29
Code smells

 Immutable functions called within loops
 Same content being generated twice
 Content that does not change being generated every time
 Content being generated even if not used




                                                           30
Code smells

 Immutable functions called within loops
 Same content being generated twice
 Content that does not change being generated every time
 Content being generated even if not used




      Sometimes it’s less obvious than it might seem

                                                           30
Caching (computational reuse)
 Static variables
 APC / Zend Server Cache / ...
 Memcached
 Reverse proxies
 Browser




                                 31
Caching (computational reuse)
 Static variables
 APC / Zend Server Cache / ...
 Memcached
 Reverse proxies
 Browser



             Do no work at all, if you can avoid it


                                                      31
[Cache] Layers!




                  32
System calls
          strace / ltrace / dtrace / ktrace / truss


 # httpd -X &
 [1] 5772

 # strace -p 5772 -o /tmp/strace.out
 Process 5772 attached - interrupt to quit


 # curl http://mysite.local/


 # less /tmp/strace.out



                                                      33
System calls
 lstat("/mnt", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0


                                       strace / ltrace / dtrace / ktrace / truss
 lstat("/mnt/hgfs", {st_mode=S_IFDIR|0555, st_size=4192, ...}) = 0
 lstat("/mnt/hgfs/service_layer", {st_mode=S_IFDIR|0755, st_size=170, ...}) = 0
 lstat("/mnt/hgfs/service_layer/branches", {st_mode=S_IFDIR|0755, st_size=102, ...}) = 0
 lstat("/mnt/hgfs/service_layer/branches/1.9", {st_mode=S_IFDIR|0755, st_size=238, ...}) = 0
 lstat("/mnt/hgfs/service_layer/branches/1.9/php", {st_mode=S_IFDIR|0755, st_size=306, ...}) = 0
 lstat("/mnt/hgfs/service_layer/branches/1.9/php/library", {st_mode=S_IFDIR|0755, st_size=136, ...}) = 0
 lstat("/mnt/hgfs/service_layer/branches/1.9/php/library/Zend", 0x7fff89049af0) = -1 ENOENT (No such file or directory)
 open("/mnt/hgfs/service_layer/branches/1.9/php/library/Zend/Controller/Plugin/Abstract.php", O_RDONLY) = -1 ENOENT (No such file or directory)
 lstat("/mnt", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0
 lstat("/mnt/hgfs", {st_mode=S_IFDIR|0555, st_size=4192, ...}) = 0
 lstat("/mnt/hgfs/service_layer", {st_mode=S_IFDIR|0755, st_size=170, ...}) = 0
 lstat("/mnt/hgfs/service_layer/branches", {st_mode=S_IFDIR|0755, st_size=102, ...}) = 0

    # httpd -X &
 lstat("/mnt/hgfs/service_layer/branches/1.9", {st_mode=S_IFDIR|0755, st_size=238, ...}) = 0
 lstat("/mnt/hgfs/service_layer/branches/1.9/php", {st_mode=S_IFDIR|0755, st_size=306, ...}) = 0
 lstat("/mnt/hgfs/service_layer/branches/1.9/php/application", {st_mode=S_IFDIR|0755, st_size=340, ...}) = 0

    [1] 5772
 lstat("/mnt/hgfs/service_layer/branches/1.9/php/application/models", {st_mode=S_IFDIR|0755, st_size=306, ...}) = 0
 lstat("/mnt/hgfs/service_layer/branches/1.9/php/application/models/Zend", 0x7fff89049af0) = -1 ENOENT (No such file or directory)
 open("/mnt/hgfs/service_layer/branches/1.9/php/application/models/Zend/Controller/Plugin/Abstract.php", O_RDONLY) = -1 ENOENT (No such file or directory)
 getcwd("/mnt/hgfs/service_layer/branches/1.9/php/public"..., 4096) = 48
 lstat("/mnt", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0
 lstat("/mnt/hgfs", {st_mode=S_IFDIR|0555, st_size=4192, ...}) = 0
 lstat("/mnt/hgfs/service_layer", {st_mode=S_IFDIR|0755, st_size=170, ...}) = 0

    # strace -p 5772 -o /tmp/strace.out
 lstat("/mnt/hgfs/service_layer/branches", {st_mode=S_IFDIR|0755, st_size=102, ...}) = 0
 lstat("/mnt/hgfs/service_layer/branches/1.9", {st_mode=S_IFDIR|0755, st_size=238, ...}) = 0
 lstat("/mnt/hgfs/service_layer/branches/1.9/php", {st_mode=S_IFDIR|0755, st_size=306, ...}) = 0

    Process 5772 attached - interrupt to quit
 lstat("/mnt/hgfs/service_layer/branches/1.9/php/public", {st_mode=S_IFDIR|0755, st_size=340, ...}) = 0
 lstat("/mnt/hgfs/service_layer/branches/1.9/php/public/Zend", 0x7fff89049af0) = -1 ENOENT (No such file or directory)
 open("/mnt/hgfs/service_layer/branches/1.9/php/public/Zend/Controller/Plugin/Abstract.php", O_RDONLY) = -1 ENOENT (No such file or directory)
 lstat("/var", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0
 lstat("/var/www", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0
 lstat("/var/www/commonlib", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0
 lstat("/var/www/commonlib/current", {st_mode=S_IFLNK|0777, st_size=32, ...}) = 0
 readlink("/var/www/commonlib/current", "/mnt/hgfs/commonlib/branches/1.9"..., 4096) = 32

    # curl http://mysite.local/
 lstat("/mnt", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0
 lstat("/mnt/hgfs", {st_mode=S_IFDIR|0555, st_size=4192, ...}) = 0
 lstat("/mnt/hgfs/commonlib", {st_mode=S_IFDIR|0755, st_size=170, ...}) = 0
 lstat("/mnt/hgfs/commonlib/branches", {st_mode=S_IFDIR|0755, st_size=136, ...}) = 0
 lstat("/mnt/hgfs/commonlib/branches/1.9", {st_mode=S_IFDIR|0755, st_size=272, ...}) = 0
 lstat("/mnt/hgfs/commonlib/branches/1.9/Zend", 0x7fff89049af0) = -1 ENOENT (No such file or directory)
 open("/var/www/commonlib/current/Zend/Controller/Plugin/Abstract.php", O_RDONLY) = -1 ENOENT (No such file or directory)
 lstat("/usr", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0

    # less /tmp/strace.out
 lstat("/usr/local", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0
 lstat("/usr/local/zend", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0
 lstat("/usr/local/zend/share", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0
 lstat("/usr/local/zend/share/ZendFramework", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0
 lstat("/usr/local/zend/share/ZendFramework/library", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0
 lstat("/usr/local/zend/share/ZendFramework/library/Zend", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0
 lstat("/usr/local/zend/share/ZendFramework/library/Zend/Controller", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0
 lstat("/usr/local/zend/share/ZendFramework/library/Zend/Controller/Plugin", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0
 lstat("/usr/local/zend/share/ZendFramework/library/Zend/Controller/Plugin/Abstract.php", {st_mode=S_IFREG|0644, st_size=4298, ...}) = 0
 open("/usr/local/zend/share/ZendFramework/library/Zend/Controller/Plugin/Abstract.php", O_RDONLY) = 40


                                                                                                                                                            33
System calls
  lstat("/mnt", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0


                                        strace / ltrace / dtrace / ktrace / truss
  lstat("/mnt/hgfs", {st_mode=S_IFDIR|0555, st_size=4192, ...}) = 0
  lstat("/mnt/hgfs/service_layer", {st_mode=S_IFDIR|0755, st_size=170, ...}) = 0
  lstat("/mnt/hgfs/service_layer/branches", {st_mode=S_IFDIR|0755, st_size=102, ...}) = 0
  lstat("/mnt/hgfs/service_layer/branches/1.9", {st_mode=S_IFDIR|0755, st_size=238, ...}) = 0
  lstat("/mnt/hgfs/service_layer/branches/1.9/php", {st_mode=S_IFDIR|0755, st_size=306, ...}) = 0
  lstat("/mnt/hgfs/service_layer/branches/1.9/php/library", {st_mode=S_IFDIR|0755, st_size=136, ...}) = 0
  lstat("/mnt/hgfs/service_layer/branches/1.9/php/library/Zend", 0x7fff89049af0) = -1 ENOENT (No such file or directory)
  open("/mnt/hgfs/service_layer/branches/1.9/php/library/Zend/Controller/Plugin/Abstract.php", O_RDONLY) = -1 ENOENT (No such file or directory)

...
  lstat("/mnt", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0
  lstat("/mnt/hgfs", {st_mode=S_IFDIR|0555, st_size=4192, ...}) = 0
  lstat("/mnt/hgfs/service_layer", {st_mode=S_IFDIR|0755, st_size=170, ...}) = 0
getcwd("/var/www/site/php/public"..., 4096) = 48
  lstat("/mnt/hgfs/service_layer/branches", {st_mode=S_IFDIR|0755, st_size=102, ...}) = 0

    # httpd -X &
  lstat("/mnt/hgfs/service_layer/branches/1.9", {st_mode=S_IFDIR|0755, st_size=238, ...}) = 0
  lstat("/mnt/hgfs/service_layer/branches/1.9/php", {st_mode=S_IFDIR|0755, st_size=306, ...}) = 0
lstat("/var", {st_mode=S_IFDIR|0755, st_size=4096}) = 0
  lstat("/mnt/hgfs/service_layer/branches/1.9/php/application", {st_mode=S_IFDIR|0755, st_size=340, ...}) = 0

    [1] 5772
  lstat("/mnt/hgfs/service_layer/branches/1.9/php/application/models", {st_mode=S_IFDIR|0755, st_size=306, ...}) = 0
  lstat("/mnt/hgfs/service_layer/branches/1.9/php/application/models/Zend", 0x7fff89049af0) = -1 ENOENT (No such file or directory)
lstat("/var/www", {st_mode=S_IFDIR|0555, st_size=4192}) = 0
  open("/mnt/hgfs/service_layer/branches/1.9/php/application/models/Zend/Controller/Plugin/Abstract.php", O_RDONLY) = -1 ENOENT (No such file or directory)
  getcwd("/mnt/hgfs/service_layer/branches/1.9/php/public"..., 4096) = 48

lstat("/var/www/site", {st_mode=S_IFDIR|0755, st_size=170}) = 0
  lstat("/mnt", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0
  lstat("/mnt/hgfs", {st_mode=S_IFDIR|0555, st_size=4192, ...}) = 0
  lstat("/mnt/hgfs/service_layer", {st_mode=S_IFDIR|0755, st_size=170, ...}) = 0
lstat("/var/www/site/php", -o /tmp/strace.out
    # strace -p 5772 {st_mode=S_IFDIR|0755, st_size=306}) = 0
  lstat("/mnt/hgfs/service_layer/branches", {st_mode=S_IFDIR|0755, st_size=102, ...}) = 0
  lstat("/mnt/hgfs/service_layer/branches/1.9", {st_mode=S_IFDIR|0755, st_size=238, ...}) = 0
  lstat("/mnt/hgfs/service_layer/branches/1.9/php", {st_mode=S_IFDIR|0755, st_size=306, ...}) = 0
lstat("/var/www/site/php/public", {st_mode=S_IFDIR|0755, st_size=340}) = 0
    Process 5772 attached - interrupt to quit
  lstat("/mnt/hgfs/service_layer/branches/1.9/php/public", {st_mode=S_IFDIR|0755, st_size=340, ...}) = 0
  lstat("/mnt/hgfs/service_layer/branches/1.9/php/public/Zend", 0x7fff89049af0) = -1 ENOENT (No such file or directory)

lstat("/var/www/site/php/public/Zend", 0x7fff89049af0) = -1 ENOENT
  open("/mnt/hgfs/service_layer/branches/1.9/php/public/Zend/Controller/Plugin/Abstract.php", O_RDONLY) = -1 ENOENT (No such file or directory)
  lstat("/var", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0
  lstat("/var/www", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0
    (No such file or directory)
  lstat("/var/www/commonlib", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0
  lstat("/var/www/commonlib/current", {st_mode=S_IFLNK|0777, st_size=32, ...}) = 0
  readlink("/var/www/commonlib/current", "/mnt/hgfs/commonlib/branches/1.9"..., 4096) = 32
open("/var/www/site/php/public/Zend/Controller/Plugin/Abstract.php",
    # curl http://mysite.local/
  lstat("/mnt", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0
  lstat("/mnt/hgfs", {st_mode=S_IFDIR|0555, st_size=4192, ...}) = 0

    O_RDONLY) = -1 ENOENT (No such file or directory)
  lstat("/mnt/hgfs/commonlib", {st_mode=S_IFDIR|0755, st_size=170, ...}) = 0
  lstat("/mnt/hgfs/commonlib/branches", {st_mode=S_IFDIR|0755, st_size=136, ...}) = 0
  lstat("/mnt/hgfs/commonlib/branches/1.9", {st_mode=S_IFDIR|0755, st_size=272, ...}) = 0
  lstat("/mnt/hgfs/commonlib/branches/1.9/Zend", 0x7fff89049af0) = -1 ENOENT (No such file or directory)
...
  open("/var/www/commonlib/current/Zend/Controller/Plugin/Abstract.php", O_RDONLY) = -1 ENOENT (No such file or directory)
  lstat("/usr", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0

      # less /tmp/strace.out
  lstat("/usr/local", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0
  lstat("/usr/local/zend", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0
  lstat("/usr/local/zend/share", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0
  lstat("/usr/local/zend/share/ZendFramework", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0
  lstat("/usr/local/zend/share/ZendFramework/library", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0
  lstat("/usr/local/zend/share/ZendFramework/library/Zend", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0
  lstat("/usr/local/zend/share/ZendFramework/library/Zend/Controller", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0
  lstat("/usr/local/zend/share/ZendFramework/library/Zend/Controller/Plugin", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0
  lstat("/usr/local/zend/share/ZendFramework/library/Zend/Controller/Plugin/Abstract.php", {st_mode=S_IFREG|0644, st_size=4298, ...}) = 0
  open("/usr/local/zend/share/ZendFramework/library/Zend/Controller/Plugin/Abstract.php", O_RDONLY) = 40


                                                                                                                                                             33
System calls
 # grep 'stat' /tmp/strace.out | wc -l
 20511

 # /usr/bin/strace -p 5772 -c
 Process 5772 attached - interrupt to quit
 Process 5772 detached
 % time    seconds usecs/call calls errors     syscall
 ------ ---------- ---------- ------ ------    -------
  50.86   0.131501          7 20054    2029    lstat
  28.42   0.073497        742     99     76    access
  16.78   0.043385         32   1337   1095    open
   1.61   0.004167          5    798       1   read
   0.94   0.002436         13    193           getcwd
    ...
 ------ ---------- ---------- ------ ------    -------
 100.00   0.020951              1267    103    total
                                                         34
System calls
 # grep 'stat' /tmp/strace.out | wc -l
 20511

 # /usr/bin/strace -p 5772 -c
 Process 5772 attached - interrupt to quit
 Process 5772 detached
 % time    seconds usecs/call calls errors     syscall
 ------ ---------- ---------- ------ ------    -------
  50.86   0.131501          7 20054    2029    lstat
  28.42   0.073497        742     99     76    access
  16.78   0.043385         32   1337   1095    open
   1.61   0.004167          5    798       1   read
   0.94   0.002436         13    193           getcwd
    ...
 ------ ---------- ---------- ------ ------    -------
 100.00   0.020951              1267    103    total
                                                         34
Fix include_path (disk I/O)

  set_include_path(implode(PATH_SEPARATOR, array(
        ‘../library/’, // project library classes
        ‘./models/’,   // project models
        ‘/usr/local/php/share/’, // framework
  ));




                The order (and number!) of
              the include paths is important.
           Tip: increase the realpath_cache size.

                                                    35
Fix include_path (disk I/O)

  set_include_path(implode(PATH_SEPARATOR, array(
        ‘../library/’, // project// framework
        ‘/usr/local/php/share/’, library classes
        ‘./models/’,
        ‘../library/’, // project models classes
                                  library
        ‘/usr/local/php/share/’, // framework
        ‘./models/’,   // project models
  ));




                The order (and number!) of
              the include paths is important.
           Tip: increase the realpath_cache size.

                                                    35
Apache config
open("/var/www/.htaccess", O_RDONLY) = -1 ENOENT
open("/var/www/php/.htaccess", O_RDONLY) = -1 ENOENT
open("/var/www/php/site/.htaccess", O_RDONLY) = -1 ENOENT
open("/var/www/php/site/org/.htaccess", O_RDONLY) = -1 ENOENT
open("/var/www/php/site/org/view/.htaccess", O_RDONLY) = -1 ENOENT
...
open("/var/www/php/site/index.html", O_RDONLY) = -1 ENOENT
open("/var/www/php/site/index.cgi", O_RDONLY) = -1 ENOENT
open("/var/www/php/site/index.php", O_RDONLY) = 0
...
open("/var/www/php/site/favicon.ico", O_RDONLY) = -1 ENOENT


                     Turn AllowOverride off
                    Optimise DirectoryIndex
                        Add favicon.cio
                                                                 36
Fix autoloader (disk I/O)
 function __autoload($className) {
     if (class_exists($className, false)) return;
     if ( (($file = apc_fetch($className)) === false)
        || ($file === null)) {
         $classFile = str_replace(‘_’,
               DIRECTORY_SEPARATOR, $className) . ‘.php’;
         $file = stream_resolve_include_path($classFile);
         if ($file !== false) {
              apc_store($className, $file, 86400);
         } else {
              apc_store($className, null, 86400);
         }
     }
     if (($file !== false) && ($file !== null)) {
         include $file;
     }
 }
                                                            37
Fix autoloader (disk I/O)
 function __autoload($className) {
     if (class_exists($className, false)) return;
     if ( (($file = apc_fetch($className)) === false)
        || ($file === null)) {
         $classFile = str_replace(‘_’,
               DIRECTORY_SEPARATOR, $className) . ‘.php’;
         $file = stream_resolve_include_path($classFile);
         if ($file !== false) {
              apc_store($className, $file, 86400);
         } else {
              apc_store($className, null, 86400);
         }
     }
     if (($file !== false) && ($file !== null)) {
         include $file;
     }
 }
                                                            37
Fix autoloader (disk I/O)
 function __autoload($className) {
     if (class_exists($className, false)) return;
     if ( (($file = apc_fetch($className)) === false)
        || ($file === null)) {
         $classFile = str_replace(‘_’,
               DIRECTORY_SEPARATOR, $className) . ‘.php’;
         $file = stream_resolve_include_path($classFile);
         if ($file !== false) {
              apc_store($className, $file, 86400);
         } else {
              apc_store($className, null, 86400);
         }
     }
     if (($file !== false) the ($file !== null)) {
                   Rely on && autoloader.
         include $file;
     }             Avoid explicit includes
 }                   http://devzone.zend.com/article/4525
                                                            37
OPCode cache
          APC                XCache
          Zend Accelerator   WinCache
          eAccelerator       ...




                                        38
OPCode cache
                    APC                     XCache
                    Zend Accelerator        WinCache
                    eAccelerator            ...

 # grep 'open(' /tmp/strace.out

 open("/usr/local/php/share/Zend/Log.php", O_RDONLY) = 40
 open("/usr/local/php/share/Zend/Form.php", O_RDONLY) = 40
 open("/usr/local/php/share/Zend/Locale.php", O_RDONLY) = 40




                                                               38
OPCode cache
                    APC                     XCache
                    Zend Accelerator        WinCache
                    eAccelerator            ...

 # grep 'open(' /tmp/strace.out

 open("/usr/local/php/share/Zend/Log.php", O_RDONLY) = 40
 open("/usr/local/php/share/Zend/Form.php", O_RDONLY) = 40
 open("/usr/local/php/share/Zend/Locale.php", O_RDONLY) = 40


             Conditional includes may cause
                 OPCode cache trashing
                                                               38
Include Hierarchy - PECL inclued




http://pecl.php.net/package/inclued
                                      39
Watch your error log!
 Warning:     Undefined      index: NAME in          file.php      on   line   1269
 Warning:     Undefined      index: DESC in          file.php      on   line   1270
 Warning:     Undefined      variable: $str          in a.php      on   line   341
 Warning:     Undefined      index: DESC in          file.php      on   line   1270




                                     @
                        Error suppression is bad

  http://derickrethans.nl/five-reasons-why-the-shutop-operator-should-be-avoided.html

                                                                                       40
Watch your error log!
 Warning:     Undefined      index: NAME in          file.php      on   line   1269
 Warning:     Undefined      index: DESC in          file.php      on   line   1270
 Warning:     Undefined      variable: $str          in a.php      on   line   341
 Warning:     Undefined      index: DESC in          file.php      on   line   1270




                                     @
                        Error suppression is bad

  http://derickrethans.nl/five-reasons-why-the-shutop-operator-should-be-avoided.html

                                                                                       40
Log and analyse external requests
 /* HTTP Client */
 function request($url, $method = ‘GET’) {
     $this->log(‘[HTTP] ’ . $method . ‘ ’ . $url);
     $ch = curl_init();
     // ...
 }


 /* DB Client */
 function query($sql) {
     $this->log(‘[DB] ’ . $query);
     // ...
     return $this->db->query($sql);
 }

                                                     41
Log and analyse external requests
 /* HTTP Client */
 function request($url, $method = ‘GET’) {
     $this->log(‘[HTTP] ’ . $method . ‘ ’ . $url);
     $ch = curl_init();
     // ...
 }


 /* DB Client */
 function query($sql) {
     $this->log(‘[DB] ’ . $query);
     // ...
     return $this->db->query($sql);
 }

                                                     41
Analyse logs (Observability)
 [HTTP]   GET   http://myservice.com/list/somelist
 [HTTP]   GET   http://myservice.com/id/1
 [HTTP]   PUT   http://myservice.com/id/3/value/xyz
 [HTTP]   GET   http://myservice.com/list/somelist
 [HTTP]   GET   http://myservice.com/list/somelist

 [DB]   SELECT   * FROM mytable;
 [DB]   SELECT   name FROM cities ORDER   BY name;
 [DB]   SELECT   name FROM cities ORDER   BY name;
 [DB]   SELECT   name FROM cities ORDER   BY name;
 [DB]   UPDATE   mytable SET name=‘xyz’   WHERE id=3;



                  Consider caching frequent requests


                                                        42
Profile under load
 Collect profile data from a sample of random requests
      if (0 == mt_rand(0, 1000)) {
          // collect profile data
      }




                                                        43
Profile under load
 Collect profile data from a sample of random requests
      if (0 == mt_rand(0, 1000)) {
          // collect profile data
      }

 Monitor resource usage in real time (top / htop / vmstat)




                                                             43
Profile under load
 Collect profile data from a sample of random requests
      if (0 == mt_rand(0, 1000)) {
          // collect profile data
      }

 Monitor resource usage in real time (top / htop / vmstat)



 Analyse graphs

                                              JMeter
                                            The Grinder

                                                             43
Performance Counters
 Used / available memory (local, shared)
 Pages / sec
 Response time & Time-outs
 Successful / failed transactions
 Open sockets / connections
 Bandwidth (internal network too!)
 CPU
                         All the resources are limited
 ...
                                                         44
Thundering Herd




                  45
Circuit Breaker




                  46
Circuit Breaker




   public function fetchData($key) {
       return $this->callService($key);
   }




                                          47
Circuit Breaker
 public function fetchData($key) {
       $config = array(
 	 	 	 'check_timeout'          => 10,
 	 	 	 'failure_threshold' => 10,
 	 	 );
 	 	 $cb = new Circuit_Breaker('name', $config);
 	 	 if ($cb->isClosed()) {
             $ok = $this->callService($key);
    public function fetchData($key) {
             if ($ok) {
        return $this->callService($key);
    }            $cb->success();
             } else {
                 //increment failures count
                 $cb->fail();
             }
       }
 }
                                                   47
Poor man’s circuit breaker
  public function fetchData($key) {
       static $failures = 0;
  	 	 if ($failures < self::MAX_FAILURES) {
             $ok = $this->callService($key);
             if ($ok) {
                 --$failures;
             } else {
                 ++$failures;
             }
        }
  }
             Save the counter in memcached
           instead of a static variable, if possible
                                                       48
Reverse Proxy




        http://www.varnish-cache.org/



                                        49
Conclusions
    Parting thoughts




                       50
Performance Checklist
 Deep understanding of the problem at hand
 Good architecture / design / data structures / algorithms
 Do the absolute minimum
 Use the right tools, always validate assumptions
 Monitor resource usage (!), with many metrics
 Spread the load uniformly across the resources
 Decouple services
 Good caching strategy strategies (sharing / reuse)

                                                             51
Links + References
            http://www.slideshare.net/postwait/scalable-internet-architecture
           http://techportal.ibuildings.com/2009/12/01/profiling-with-xhprof/
http://www.chehodgins.com/php/sorting-out-your-php-includes-using-inclued/
http://weierophinney.net/matthew/archives/245-Autoloading-Benchmarks.html
         http://www.mail-archive.com/internals@lists.php.net/msg37192.html
                                               http://talks.php.net/show/digg
                                 http://mirror.facebook.net/facebook/xhprof/
                                                           http://xdebug.org/
                                             http://github.com/facebook/pfff/




                                                                                52
Image Credits
 http://michaelscomments.files.wordpress.com/2009/10/onion-
                                              centurion.jpg

       http://www.socketmanufacturers.com/miniature-circuit-
            breaker/DZ47-63-3P-Miniature-Circuit-Breaker.jpg

http://onscreencars.com/tv/the-homer-the-car-built-for-homer/

            http://etc.usf.edu/presentations/themes/index.html

                                  http://www.iconfinder.com/




                                                                 53
Questions?




             54
Lorenzo Alberton
                   @lorenzoalberton




   Thank you!
       lorenzo@alberton.info
http://www.alberton.info/talks




   http://joind.in/talk/view/2051
                                      55

More Related Content

Recently uploaded

Time Series Foundation Models - current state and future directions
Time Series Foundation Models - current state and future directionsTime Series Foundation Models - current state and future directions
Time Series Foundation Models - current state and future directionsNathaniel Shimoni
 
Passkey Providers and Enabling Portability: FIDO Paris Seminar.pptx
Passkey Providers and Enabling Portability: FIDO Paris Seminar.pptxPasskey Providers and Enabling Portability: FIDO Paris Seminar.pptx
Passkey Providers and Enabling Portability: FIDO Paris Seminar.pptxLoriGlavin3
 
DevoxxFR 2024 Reproducible Builds with Apache Maven
DevoxxFR 2024 Reproducible Builds with Apache MavenDevoxxFR 2024 Reproducible Builds with Apache Maven
DevoxxFR 2024 Reproducible Builds with Apache MavenHervé Boutemy
 
"ML in Production",Oleksandr Bagan
"ML in Production",Oleksandr Bagan"ML in Production",Oleksandr Bagan
"ML in Production",Oleksandr BaganFwdays
 
Transcript: New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024
Transcript: New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024Transcript: New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024
Transcript: New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024BookNet Canada
 
Digital Identity is Under Attack: FIDO Paris Seminar.pptx
Digital Identity is Under Attack: FIDO Paris Seminar.pptxDigital Identity is Under Attack: FIDO Paris Seminar.pptx
Digital Identity is Under Attack: FIDO Paris Seminar.pptxLoriGlavin3
 
Generative AI for Technical Writer or Information Developers
Generative AI for Technical Writer or Information DevelopersGenerative AI for Technical Writer or Information Developers
Generative AI for Technical Writer or Information DevelopersRaghuram Pandurangan
 
Anypoint Exchange: It’s Not Just a Repo!
Anypoint Exchange: It’s Not Just a Repo!Anypoint Exchange: It’s Not Just a Repo!
Anypoint Exchange: It’s Not Just a Repo!Manik S Magar
 
SIP trunking in Janus @ Kamailio World 2024
SIP trunking in Janus @ Kamailio World 2024SIP trunking in Janus @ Kamailio World 2024
SIP trunking in Janus @ Kamailio World 2024Lorenzo Miniero
 
The Role of FIDO in a Cyber Secure Netherlands: FIDO Paris Seminar.pptx
The Role of FIDO in a Cyber Secure Netherlands: FIDO Paris Seminar.pptxThe Role of FIDO in a Cyber Secure Netherlands: FIDO Paris Seminar.pptx
The Role of FIDO in a Cyber Secure Netherlands: FIDO Paris Seminar.pptxLoriGlavin3
 
WordPress Websites for Engineers: Elevate Your Brand
WordPress Websites for Engineers: Elevate Your BrandWordPress Websites for Engineers: Elevate Your Brand
WordPress Websites for Engineers: Elevate Your Brandgvaughan
 
Gen AI in Business - Global Trends Report 2024.pdf
Gen AI in Business - Global Trends Report 2024.pdfGen AI in Business - Global Trends Report 2024.pdf
Gen AI in Business - Global Trends Report 2024.pdfAddepto
 
Training state-of-the-art general text embedding
Training state-of-the-art general text embeddingTraining state-of-the-art general text embedding
Training state-of-the-art general text embeddingZilliz
 
Sample pptx for embedding into website for demo
Sample pptx for embedding into website for demoSample pptx for embedding into website for demo
Sample pptx for embedding into website for demoHarshalMandlekar2
 
"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek Schlawack
"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek Schlawack"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek Schlawack
"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek SchlawackFwdays
 
Moving Beyond Passwords: FIDO Paris Seminar.pdf
Moving Beyond Passwords: FIDO Paris Seminar.pdfMoving Beyond Passwords: FIDO Paris Seminar.pdf
Moving Beyond Passwords: FIDO Paris Seminar.pdfLoriGlavin3
 
What is Artificial Intelligence?????????
What is Artificial Intelligence?????????What is Artificial Intelligence?????????
What is Artificial Intelligence?????????blackmambaettijean
 
SALESFORCE EDUCATION CLOUD | FEXLE SERVICES
SALESFORCE EDUCATION CLOUD | FEXLE SERVICESSALESFORCE EDUCATION CLOUD | FEXLE SERVICES
SALESFORCE EDUCATION CLOUD | FEXLE SERVICESmohitsingh558521
 
Developer Data Modeling Mistakes: From Postgres to NoSQL
Developer Data Modeling Mistakes: From Postgres to NoSQLDeveloper Data Modeling Mistakes: From Postgres to NoSQL
Developer Data Modeling Mistakes: From Postgres to NoSQLScyllaDB
 
DevEX - reference for building teams, processes, and platforms
DevEX - reference for building teams, processes, and platformsDevEX - reference for building teams, processes, and platforms
DevEX - reference for building teams, processes, and platformsSergiu Bodiu
 

Recently uploaded (20)

Time Series Foundation Models - current state and future directions
Time Series Foundation Models - current state and future directionsTime Series Foundation Models - current state and future directions
Time Series Foundation Models - current state and future directions
 
Passkey Providers and Enabling Portability: FIDO Paris Seminar.pptx
Passkey Providers and Enabling Portability: FIDO Paris Seminar.pptxPasskey Providers and Enabling Portability: FIDO Paris Seminar.pptx
Passkey Providers and Enabling Portability: FIDO Paris Seminar.pptx
 
DevoxxFR 2024 Reproducible Builds with Apache Maven
DevoxxFR 2024 Reproducible Builds with Apache MavenDevoxxFR 2024 Reproducible Builds with Apache Maven
DevoxxFR 2024 Reproducible Builds with Apache Maven
 
"ML in Production",Oleksandr Bagan
"ML in Production",Oleksandr Bagan"ML in Production",Oleksandr Bagan
"ML in Production",Oleksandr Bagan
 
Transcript: New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024
Transcript: New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024Transcript: New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024
Transcript: New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024
 
Digital Identity is Under Attack: FIDO Paris Seminar.pptx
Digital Identity is Under Attack: FIDO Paris Seminar.pptxDigital Identity is Under Attack: FIDO Paris Seminar.pptx
Digital Identity is Under Attack: FIDO Paris Seminar.pptx
 
Generative AI for Technical Writer or Information Developers
Generative AI for Technical Writer or Information DevelopersGenerative AI for Technical Writer or Information Developers
Generative AI for Technical Writer or Information Developers
 
Anypoint Exchange: It’s Not Just a Repo!
Anypoint Exchange: It’s Not Just a Repo!Anypoint Exchange: It’s Not Just a Repo!
Anypoint Exchange: It’s Not Just a Repo!
 
SIP trunking in Janus @ Kamailio World 2024
SIP trunking in Janus @ Kamailio World 2024SIP trunking in Janus @ Kamailio World 2024
SIP trunking in Janus @ Kamailio World 2024
 
The Role of FIDO in a Cyber Secure Netherlands: FIDO Paris Seminar.pptx
The Role of FIDO in a Cyber Secure Netherlands: FIDO Paris Seminar.pptxThe Role of FIDO in a Cyber Secure Netherlands: FIDO Paris Seminar.pptx
The Role of FIDO in a Cyber Secure Netherlands: FIDO Paris Seminar.pptx
 
WordPress Websites for Engineers: Elevate Your Brand
WordPress Websites for Engineers: Elevate Your BrandWordPress Websites for Engineers: Elevate Your Brand
WordPress Websites for Engineers: Elevate Your Brand
 
Gen AI in Business - Global Trends Report 2024.pdf
Gen AI in Business - Global Trends Report 2024.pdfGen AI in Business - Global Trends Report 2024.pdf
Gen AI in Business - Global Trends Report 2024.pdf
 
Training state-of-the-art general text embedding
Training state-of-the-art general text embeddingTraining state-of-the-art general text embedding
Training state-of-the-art general text embedding
 
Sample pptx for embedding into website for demo
Sample pptx for embedding into website for demoSample pptx for embedding into website for demo
Sample pptx for embedding into website for demo
 
"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek Schlawack
"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek Schlawack"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek Schlawack
"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek Schlawack
 
Moving Beyond Passwords: FIDO Paris Seminar.pdf
Moving Beyond Passwords: FIDO Paris Seminar.pdfMoving Beyond Passwords: FIDO Paris Seminar.pdf
Moving Beyond Passwords: FIDO Paris Seminar.pdf
 
What is Artificial Intelligence?????????
What is Artificial Intelligence?????????What is Artificial Intelligence?????????
What is Artificial Intelligence?????????
 
SALESFORCE EDUCATION CLOUD | FEXLE SERVICES
SALESFORCE EDUCATION CLOUD | FEXLE SERVICESSALESFORCE EDUCATION CLOUD | FEXLE SERVICES
SALESFORCE EDUCATION CLOUD | FEXLE SERVICES
 
Developer Data Modeling Mistakes: From Postgres to NoSQL
Developer Data Modeling Mistakes: From Postgres to NoSQLDeveloper Data Modeling Mistakes: From Postgres to NoSQL
Developer Data Modeling Mistakes: From Postgres to NoSQL
 
DevEX - reference for building teams, processes, and platforms
DevEX - reference for building teams, processes, and platformsDevEX - reference for building teams, processes, and platforms
DevEX - reference for building teams, processes, and platforms
 

Featured

2024 State of Marketing Report – by Hubspot
2024 State of Marketing Report – by Hubspot2024 State of Marketing Report – by Hubspot
2024 State of Marketing Report – by HubspotMarius Sescu
 
Everything You Need To Know About ChatGPT
Everything You Need To Know About ChatGPTEverything You Need To Know About ChatGPT
Everything You Need To Know About ChatGPTExpeed Software
 
Product Design Trends in 2024 | Teenage Engineerings
Product Design Trends in 2024 | Teenage EngineeringsProduct Design Trends in 2024 | Teenage Engineerings
Product Design Trends in 2024 | Teenage EngineeringsPixeldarts
 
How Race, Age and Gender Shape Attitudes Towards Mental Health
How Race, Age and Gender Shape Attitudes Towards Mental HealthHow Race, Age and Gender Shape Attitudes Towards Mental Health
How Race, Age and Gender Shape Attitudes Towards Mental HealthThinkNow
 
AI Trends in Creative Operations 2024 by Artwork Flow.pdf
AI Trends in Creative Operations 2024 by Artwork Flow.pdfAI Trends in Creative Operations 2024 by Artwork Flow.pdf
AI Trends in Creative Operations 2024 by Artwork Flow.pdfmarketingartwork
 
PEPSICO Presentation to CAGNY Conference Feb 2024
PEPSICO Presentation to CAGNY Conference Feb 2024PEPSICO Presentation to CAGNY Conference Feb 2024
PEPSICO Presentation to CAGNY Conference Feb 2024Neil Kimberley
 
Content Methodology: A Best Practices Report (Webinar)
Content Methodology: A Best Practices Report (Webinar)Content Methodology: A Best Practices Report (Webinar)
Content Methodology: A Best Practices Report (Webinar)contently
 
How to Prepare For a Successful Job Search for 2024
How to Prepare For a Successful Job Search for 2024How to Prepare For a Successful Job Search for 2024
How to Prepare For a Successful Job Search for 2024Albert Qian
 
Social Media Marketing Trends 2024 // The Global Indie Insights
Social Media Marketing Trends 2024 // The Global Indie InsightsSocial Media Marketing Trends 2024 // The Global Indie Insights
Social Media Marketing Trends 2024 // The Global Indie InsightsKurio // The Social Media Age(ncy)
 
Trends In Paid Search: Navigating The Digital Landscape In 2024
Trends In Paid Search: Navigating The Digital Landscape In 2024Trends In Paid Search: Navigating The Digital Landscape In 2024
Trends In Paid Search: Navigating The Digital Landscape In 2024Search Engine Journal
 
5 Public speaking tips from TED - Visualized summary
5 Public speaking tips from TED - Visualized summary5 Public speaking tips from TED - Visualized summary
5 Public speaking tips from TED - Visualized summarySpeakerHub
 
ChatGPT and the Future of Work - Clark Boyd
ChatGPT and the Future of Work - Clark Boyd ChatGPT and the Future of Work - Clark Boyd
ChatGPT and the Future of Work - Clark Boyd Clark Boyd
 
Getting into the tech field. what next
Getting into the tech field. what next Getting into the tech field. what next
Getting into the tech field. what next Tessa Mero
 
Google's Just Not That Into You: Understanding Core Updates & Search Intent
Google's Just Not That Into You: Understanding Core Updates & Search IntentGoogle's Just Not That Into You: Understanding Core Updates & Search Intent
Google's Just Not That Into You: Understanding Core Updates & Search IntentLily Ray
 
Time Management & Productivity - Best Practices
Time Management & Productivity -  Best PracticesTime Management & Productivity -  Best Practices
Time Management & Productivity - Best PracticesVit Horky
 
The six step guide to practical project management
The six step guide to practical project managementThe six step guide to practical project management
The six step guide to practical project managementMindGenius
 
Beginners Guide to TikTok for Search - Rachel Pearson - We are Tilt __ Bright...
Beginners Guide to TikTok for Search - Rachel Pearson - We are Tilt __ Bright...Beginners Guide to TikTok for Search - Rachel Pearson - We are Tilt __ Bright...
Beginners Guide to TikTok for Search - Rachel Pearson - We are Tilt __ Bright...RachelPearson36
 

Featured (20)

2024 State of Marketing Report – by Hubspot
2024 State of Marketing Report – by Hubspot2024 State of Marketing Report – by Hubspot
2024 State of Marketing Report – by Hubspot
 
Everything You Need To Know About ChatGPT
Everything You Need To Know About ChatGPTEverything You Need To Know About ChatGPT
Everything You Need To Know About ChatGPT
 
Product Design Trends in 2024 | Teenage Engineerings
Product Design Trends in 2024 | Teenage EngineeringsProduct Design Trends in 2024 | Teenage Engineerings
Product Design Trends in 2024 | Teenage Engineerings
 
How Race, Age and Gender Shape Attitudes Towards Mental Health
How Race, Age and Gender Shape Attitudes Towards Mental HealthHow Race, Age and Gender Shape Attitudes Towards Mental Health
How Race, Age and Gender Shape Attitudes Towards Mental Health
 
AI Trends in Creative Operations 2024 by Artwork Flow.pdf
AI Trends in Creative Operations 2024 by Artwork Flow.pdfAI Trends in Creative Operations 2024 by Artwork Flow.pdf
AI Trends in Creative Operations 2024 by Artwork Flow.pdf
 
Skeleton Culture Code
Skeleton Culture CodeSkeleton Culture Code
Skeleton Culture Code
 
PEPSICO Presentation to CAGNY Conference Feb 2024
PEPSICO Presentation to CAGNY Conference Feb 2024PEPSICO Presentation to CAGNY Conference Feb 2024
PEPSICO Presentation to CAGNY Conference Feb 2024
 
Content Methodology: A Best Practices Report (Webinar)
Content Methodology: A Best Practices Report (Webinar)Content Methodology: A Best Practices Report (Webinar)
Content Methodology: A Best Practices Report (Webinar)
 
How to Prepare For a Successful Job Search for 2024
How to Prepare For a Successful Job Search for 2024How to Prepare For a Successful Job Search for 2024
How to Prepare For a Successful Job Search for 2024
 
Social Media Marketing Trends 2024 // The Global Indie Insights
Social Media Marketing Trends 2024 // The Global Indie InsightsSocial Media Marketing Trends 2024 // The Global Indie Insights
Social Media Marketing Trends 2024 // The Global Indie Insights
 
Trends In Paid Search: Navigating The Digital Landscape In 2024
Trends In Paid Search: Navigating The Digital Landscape In 2024Trends In Paid Search: Navigating The Digital Landscape In 2024
Trends In Paid Search: Navigating The Digital Landscape In 2024
 
5 Public speaking tips from TED - Visualized summary
5 Public speaking tips from TED - Visualized summary5 Public speaking tips from TED - Visualized summary
5 Public speaking tips from TED - Visualized summary
 
ChatGPT and the Future of Work - Clark Boyd
ChatGPT and the Future of Work - Clark Boyd ChatGPT and the Future of Work - Clark Boyd
ChatGPT and the Future of Work - Clark Boyd
 
Getting into the tech field. what next
Getting into the tech field. what next Getting into the tech field. what next
Getting into the tech field. what next
 
Google's Just Not That Into You: Understanding Core Updates & Search Intent
Google's Just Not That Into You: Understanding Core Updates & Search IntentGoogle's Just Not That Into You: Understanding Core Updates & Search Intent
Google's Just Not That Into You: Understanding Core Updates & Search Intent
 
How to have difficult conversations
How to have difficult conversations How to have difficult conversations
How to have difficult conversations
 
Introduction to Data Science
Introduction to Data ScienceIntroduction to Data Science
Introduction to Data Science
 
Time Management & Productivity - Best Practices
Time Management & Productivity -  Best PracticesTime Management & Productivity -  Best Practices
Time Management & Productivity - Best Practices
 
The six step guide to practical project management
The six step guide to practical project managementThe six step guide to practical project management
The six step guide to practical project management
 
Beginners Guide to TikTok for Search - Rachel Pearson - We are Tilt __ Bright...
Beginners Guide to TikTok for Search - Rachel Pearson - We are Tilt __ Bright...Beginners Guide to TikTok for Search - Rachel Pearson - We are Tilt __ Bright...
Beginners Guide to TikTok for Search - Rachel Pearson - We are Tilt __ Bright...
 

Profile your PHP application and make it fly

  • 1. Lorenzo Alberton Profile your PHP application and make it fly The path to performance and scalability PHPNW, Saturday 9th October 2010 1
  • 2. Quiz time! Which is faster? 2
  • 3. Quiz time! Which is faster? (A) echo (B) print 2
  • 4. Quiz time! Which is faster? (A) echo single (B) print double quotes quotes 2
  • 5. Answer It probably doesn’t matter. 3
  • 6. Awareness is the Know your targets Know what it will take to meet them Know your constraints 4
  • 7. Tools: Profilers Tools are just tools They are absolutely essential to doing your job They will never do your job for you Tools will never replace experience and discipline But tools can help you maintain discipline Theo Schlossnagle 5
  • 8. Xdebug + xCacheGrind http://xdebug.org/ http://valgrind.org/ http://kcachegrind.sf.net/ http://sf.net/projects/wincachegrind http://code.google.com/p/webgrind/ http://www.maccallgrind.com/ 6
  • 9. XHProf XHProf http://mirror.facebook.net/facebook/xhprof/ http://pecl.php.net/package/xhprof http://techportal.ibuildings.com/2009/12/01/profiling-with-xhprof/ 7
  • 10. XHProf UI Report - Web interface 8
  • 11. XHProf UI Report - Web interface 8
  • 12. XHProf UI Report - Web interface 8
  • 13. XHProf UI Report - Web interface Function Name Calls Wall Time (inclusive / exclusive) CPU (inclusive / exclusive) Memory (inclusive / exclusive) Peak Memory Use (inclusive / exclusive) # and % 8
  • 14. XHProf UI - Trace calls 9
  • 15. XHProf UI - Call Graph 10
  • 16. XHProf UI - Call Graph 10
  • 17. Measuring Analyse the framework Analyse your application 11
  • 18. Know Your Framework Measure the baseline Shortcuts aren’t always “free” When there are two ways of doing something, usually one is much better Loading (classes, resources) is expensive 12
  • 19. Zend Framework Baseline $ zf.sh create project testzf 13
  • 20. Know Your Framework Measure the baseline Shortcuts aren’t always “free” When there are two ways of doing something, usually one is much better Loading (classes, resources) is expensive 14
  • 21. Shortcuts - The Real Cost public function doSomething(array $data) { // Zend_Config object $config = $this->getConfig(); $var = $config->aaa->bbb->ccc; // ... } 15
  • 22. Shortcuts - The Real Cost public function doSomething(array $data) { // Zend_Config object $config = $this->getConfig(); $var = $config->aaa->bbb->ccc; // ... } 15
  • 23. Shortcuts - The Real Cost public function doSomething(array $data) { // Zend_Config object $config = $this->getConfig(); $var = $config->aaa->bbb->ccc; // ... } 15
  • 24. Shortcuts - The Real Cost public function doSomething(array $data) { // Zend_Config object $config = $this->getConfig(); $var = $config->aaa->bbb->ccc; // ... } 2 1 3 15
  • 25. Know Your Framework Measure the baseline Shortcuts aren’t always “free” When there are two ways of doing something, usually one is much better Loading (classes, resources) is expensive 16
  • 26. partial() vs. render() <!-- mytemplate.phtml --> <ul> <?php foreach ($this->rows as $row) { $this->partial(‘listItemTemplate.phtml’, ‘mymodule’, array(‘data’ => $row); } ?> </ul> 17
  • 34. partial() vs. render() <!-- mytemplate.phtml --> <ul> <?php foreach ($this->rows as $row) { $this->partial(‘listItemTemplate.phtml’, ‘mymodule’, array(‘data’ => $row); } ?> </ul> 19
  • 35. partial() vs. render() <!-- mytemplate.phtml --> <ul> <?php foreach ($this->rows as $row) { $this->row) { $this->render(‘listItemTemplate.phtml’); $this->partial(‘listItemTemplate.phtml’, } ‘mymodule’, array(‘data’ => $row); ?> } </ul> ?> </ul> 19
  • 36. Know Your Framework Measure the baseline Shortcuts aren’t always “free” When there are two ways of doing something, usually one is much better Loading (classes, resources) is expensive 20
  • 37. Plugins / Helpers <!-- mytemplate.phtml --> <ul> <?php foreach ($this->rows as $row) { echo $this->myViewHelper($row); } ?> </ul> 21
  • 38. Plugins / Helpers // calling: // Zend_View_Abstract::__call() <!-- mytemplate.phtml --> // Zend_View_Abstract::getHelper() <ul> // Zend_View_Abstract::_getPlugin() <?php // Zend_View_Abstract::_getPluginLoader() // Zend_Loader_PluginLoader::load() foreach ($this->rows as $row) { // Zend_Loader_PluginLoader::isLoaded() echo $this->myViewHelper($row); // Zend_Loader_PluginLoader::getClassName() } // Zend_Loader_PluginLoader::_formatName() // Zend_View_Abstract::setView() ?> // call_user_func_array() </ul> // My_Helpers_MyViewHelper::myViewHelper() 21
  • 39. Plugins / Helpers <!-- mytemplate.phtml --> <ul> <?php foreach ($this->rows as $row) { echo $this->myViewHelper($row); } ?> </ul> 21
  • 40. Plugins / Helpers <!-- mytemplate.phtml --> <ul> <?php foreach $helper = $this->getHelper('myViewHelper'); ($this->rows as $row) { echo $this->myViewHelper($row); foreach } ($this->rows as $row) { echo $helper->myViewHelper($row); } ?> </ul> ?> </ul> 21
  • 41. Know Your Application Every feature has a cost. Measure it. 22
  • 42. Optimisation Techniques Tips and tricks to get faster applications 23
  • 43. Rules of thumb Profile / Measure Sort by [ Excl. CPU | Memory | Time | Calls ] Start from the TOP of the list Analyse, refactor, optimise Measure improvement Start over 24
  • 44. Rules of thumb Profile / Measure Sort by [ Excl. CPU | Memory | Time | Calls ] Start from the TOP of the list Analyse, refactor, optimise Measure improvement Start over Again, and again, and again. 24
  • 45. Profiling as Design validation practice 25
  • 46. Easy performance targets External resources (http, db, disk I/O) Memory-hungry function (xml/json parsers, output buffering) Loops Regular expressions Wrappers 26
  • 47. Refactoring hints PREPARE SCREEN showing db calls 27
  • 48. Refactoring hints PREPARE SCREEN showing db calls 27
  • 53. Refactoring hints PHP is FAST 29
  • 54. Refactoring hints PHP is FAST ...but do you really need to call strtolower() 15000 times? 29
  • 55. Refactoring hints PHP is FAST ...but do you really need to call strtolower() 15000 times? Re-think why you’re doing something, if it’s the right place to do it, and if possible reduce the amount of data you need to process 29
  • 56. Code smells Immutable functions called within loops Same content being generated twice Content that does not change being generated every time Content being generated even if not used 30
  • 57. Code smells Immutable functions called within loops Same content being generated twice Content that does not change being generated every time Content being generated even if not used Sometimes it’s less obvious than it might seem 30
  • 58. Caching (computational reuse) Static variables APC / Zend Server Cache / ... Memcached Reverse proxies Browser 31
  • 59. Caching (computational reuse) Static variables APC / Zend Server Cache / ... Memcached Reverse proxies Browser Do no work at all, if you can avoid it 31
  • 61. System calls strace / ltrace / dtrace / ktrace / truss # httpd -X & [1] 5772 # strace -p 5772 -o /tmp/strace.out Process 5772 attached - interrupt to quit # curl http://mysite.local/ # less /tmp/strace.out 33
  • 62. System calls lstat("/mnt", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0 strace / ltrace / dtrace / ktrace / truss lstat("/mnt/hgfs", {st_mode=S_IFDIR|0555, st_size=4192, ...}) = 0 lstat("/mnt/hgfs/service_layer", {st_mode=S_IFDIR|0755, st_size=170, ...}) = 0 lstat("/mnt/hgfs/service_layer/branches", {st_mode=S_IFDIR|0755, st_size=102, ...}) = 0 lstat("/mnt/hgfs/service_layer/branches/1.9", {st_mode=S_IFDIR|0755, st_size=238, ...}) = 0 lstat("/mnt/hgfs/service_layer/branches/1.9/php", {st_mode=S_IFDIR|0755, st_size=306, ...}) = 0 lstat("/mnt/hgfs/service_layer/branches/1.9/php/library", {st_mode=S_IFDIR|0755, st_size=136, ...}) = 0 lstat("/mnt/hgfs/service_layer/branches/1.9/php/library/Zend", 0x7fff89049af0) = -1 ENOENT (No such file or directory) open("/mnt/hgfs/service_layer/branches/1.9/php/library/Zend/Controller/Plugin/Abstract.php", O_RDONLY) = -1 ENOENT (No such file or directory) lstat("/mnt", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0 lstat("/mnt/hgfs", {st_mode=S_IFDIR|0555, st_size=4192, ...}) = 0 lstat("/mnt/hgfs/service_layer", {st_mode=S_IFDIR|0755, st_size=170, ...}) = 0 lstat("/mnt/hgfs/service_layer/branches", {st_mode=S_IFDIR|0755, st_size=102, ...}) = 0 # httpd -X & lstat("/mnt/hgfs/service_layer/branches/1.9", {st_mode=S_IFDIR|0755, st_size=238, ...}) = 0 lstat("/mnt/hgfs/service_layer/branches/1.9/php", {st_mode=S_IFDIR|0755, st_size=306, ...}) = 0 lstat("/mnt/hgfs/service_layer/branches/1.9/php/application", {st_mode=S_IFDIR|0755, st_size=340, ...}) = 0 [1] 5772 lstat("/mnt/hgfs/service_layer/branches/1.9/php/application/models", {st_mode=S_IFDIR|0755, st_size=306, ...}) = 0 lstat("/mnt/hgfs/service_layer/branches/1.9/php/application/models/Zend", 0x7fff89049af0) = -1 ENOENT (No such file or directory) open("/mnt/hgfs/service_layer/branches/1.9/php/application/models/Zend/Controller/Plugin/Abstract.php", O_RDONLY) = -1 ENOENT (No such file or directory) getcwd("/mnt/hgfs/service_layer/branches/1.9/php/public"..., 4096) = 48 lstat("/mnt", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0 lstat("/mnt/hgfs", {st_mode=S_IFDIR|0555, st_size=4192, ...}) = 0 lstat("/mnt/hgfs/service_layer", {st_mode=S_IFDIR|0755, st_size=170, ...}) = 0 # strace -p 5772 -o /tmp/strace.out lstat("/mnt/hgfs/service_layer/branches", {st_mode=S_IFDIR|0755, st_size=102, ...}) = 0 lstat("/mnt/hgfs/service_layer/branches/1.9", {st_mode=S_IFDIR|0755, st_size=238, ...}) = 0 lstat("/mnt/hgfs/service_layer/branches/1.9/php", {st_mode=S_IFDIR|0755, st_size=306, ...}) = 0 Process 5772 attached - interrupt to quit lstat("/mnt/hgfs/service_layer/branches/1.9/php/public", {st_mode=S_IFDIR|0755, st_size=340, ...}) = 0 lstat("/mnt/hgfs/service_layer/branches/1.9/php/public/Zend", 0x7fff89049af0) = -1 ENOENT (No such file or directory) open("/mnt/hgfs/service_layer/branches/1.9/php/public/Zend/Controller/Plugin/Abstract.php", O_RDONLY) = -1 ENOENT (No such file or directory) lstat("/var", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0 lstat("/var/www", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0 lstat("/var/www/commonlib", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0 lstat("/var/www/commonlib/current", {st_mode=S_IFLNK|0777, st_size=32, ...}) = 0 readlink("/var/www/commonlib/current", "/mnt/hgfs/commonlib/branches/1.9"..., 4096) = 32 # curl http://mysite.local/ lstat("/mnt", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0 lstat("/mnt/hgfs", {st_mode=S_IFDIR|0555, st_size=4192, ...}) = 0 lstat("/mnt/hgfs/commonlib", {st_mode=S_IFDIR|0755, st_size=170, ...}) = 0 lstat("/mnt/hgfs/commonlib/branches", {st_mode=S_IFDIR|0755, st_size=136, ...}) = 0 lstat("/mnt/hgfs/commonlib/branches/1.9", {st_mode=S_IFDIR|0755, st_size=272, ...}) = 0 lstat("/mnt/hgfs/commonlib/branches/1.9/Zend", 0x7fff89049af0) = -1 ENOENT (No such file or directory) open("/var/www/commonlib/current/Zend/Controller/Plugin/Abstract.php", O_RDONLY) = -1 ENOENT (No such file or directory) lstat("/usr", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0 # less /tmp/strace.out lstat("/usr/local", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0 lstat("/usr/local/zend", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0 lstat("/usr/local/zend/share", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0 lstat("/usr/local/zend/share/ZendFramework", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0 lstat("/usr/local/zend/share/ZendFramework/library", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0 lstat("/usr/local/zend/share/ZendFramework/library/Zend", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0 lstat("/usr/local/zend/share/ZendFramework/library/Zend/Controller", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0 lstat("/usr/local/zend/share/ZendFramework/library/Zend/Controller/Plugin", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0 lstat("/usr/local/zend/share/ZendFramework/library/Zend/Controller/Plugin/Abstract.php", {st_mode=S_IFREG|0644, st_size=4298, ...}) = 0 open("/usr/local/zend/share/ZendFramework/library/Zend/Controller/Plugin/Abstract.php", O_RDONLY) = 40 33
  • 63. System calls lstat("/mnt", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0 strace / ltrace / dtrace / ktrace / truss lstat("/mnt/hgfs", {st_mode=S_IFDIR|0555, st_size=4192, ...}) = 0 lstat("/mnt/hgfs/service_layer", {st_mode=S_IFDIR|0755, st_size=170, ...}) = 0 lstat("/mnt/hgfs/service_layer/branches", {st_mode=S_IFDIR|0755, st_size=102, ...}) = 0 lstat("/mnt/hgfs/service_layer/branches/1.9", {st_mode=S_IFDIR|0755, st_size=238, ...}) = 0 lstat("/mnt/hgfs/service_layer/branches/1.9/php", {st_mode=S_IFDIR|0755, st_size=306, ...}) = 0 lstat("/mnt/hgfs/service_layer/branches/1.9/php/library", {st_mode=S_IFDIR|0755, st_size=136, ...}) = 0 lstat("/mnt/hgfs/service_layer/branches/1.9/php/library/Zend", 0x7fff89049af0) = -1 ENOENT (No such file or directory) open("/mnt/hgfs/service_layer/branches/1.9/php/library/Zend/Controller/Plugin/Abstract.php", O_RDONLY) = -1 ENOENT (No such file or directory) ... lstat("/mnt", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0 lstat("/mnt/hgfs", {st_mode=S_IFDIR|0555, st_size=4192, ...}) = 0 lstat("/mnt/hgfs/service_layer", {st_mode=S_IFDIR|0755, st_size=170, ...}) = 0 getcwd("/var/www/site/php/public"..., 4096) = 48 lstat("/mnt/hgfs/service_layer/branches", {st_mode=S_IFDIR|0755, st_size=102, ...}) = 0 # httpd -X & lstat("/mnt/hgfs/service_layer/branches/1.9", {st_mode=S_IFDIR|0755, st_size=238, ...}) = 0 lstat("/mnt/hgfs/service_layer/branches/1.9/php", {st_mode=S_IFDIR|0755, st_size=306, ...}) = 0 lstat("/var", {st_mode=S_IFDIR|0755, st_size=4096}) = 0 lstat("/mnt/hgfs/service_layer/branches/1.9/php/application", {st_mode=S_IFDIR|0755, st_size=340, ...}) = 0 [1] 5772 lstat("/mnt/hgfs/service_layer/branches/1.9/php/application/models", {st_mode=S_IFDIR|0755, st_size=306, ...}) = 0 lstat("/mnt/hgfs/service_layer/branches/1.9/php/application/models/Zend", 0x7fff89049af0) = -1 ENOENT (No such file or directory) lstat("/var/www", {st_mode=S_IFDIR|0555, st_size=4192}) = 0 open("/mnt/hgfs/service_layer/branches/1.9/php/application/models/Zend/Controller/Plugin/Abstract.php", O_RDONLY) = -1 ENOENT (No such file or directory) getcwd("/mnt/hgfs/service_layer/branches/1.9/php/public"..., 4096) = 48 lstat("/var/www/site", {st_mode=S_IFDIR|0755, st_size=170}) = 0 lstat("/mnt", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0 lstat("/mnt/hgfs", {st_mode=S_IFDIR|0555, st_size=4192, ...}) = 0 lstat("/mnt/hgfs/service_layer", {st_mode=S_IFDIR|0755, st_size=170, ...}) = 0 lstat("/var/www/site/php", -o /tmp/strace.out # strace -p 5772 {st_mode=S_IFDIR|0755, st_size=306}) = 0 lstat("/mnt/hgfs/service_layer/branches", {st_mode=S_IFDIR|0755, st_size=102, ...}) = 0 lstat("/mnt/hgfs/service_layer/branches/1.9", {st_mode=S_IFDIR|0755, st_size=238, ...}) = 0 lstat("/mnt/hgfs/service_layer/branches/1.9/php", {st_mode=S_IFDIR|0755, st_size=306, ...}) = 0 lstat("/var/www/site/php/public", {st_mode=S_IFDIR|0755, st_size=340}) = 0 Process 5772 attached - interrupt to quit lstat("/mnt/hgfs/service_layer/branches/1.9/php/public", {st_mode=S_IFDIR|0755, st_size=340, ...}) = 0 lstat("/mnt/hgfs/service_layer/branches/1.9/php/public/Zend", 0x7fff89049af0) = -1 ENOENT (No such file or directory) lstat("/var/www/site/php/public/Zend", 0x7fff89049af0) = -1 ENOENT open("/mnt/hgfs/service_layer/branches/1.9/php/public/Zend/Controller/Plugin/Abstract.php", O_RDONLY) = -1 ENOENT (No such file or directory) lstat("/var", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0 lstat("/var/www", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0 (No such file or directory) lstat("/var/www/commonlib", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0 lstat("/var/www/commonlib/current", {st_mode=S_IFLNK|0777, st_size=32, ...}) = 0 readlink("/var/www/commonlib/current", "/mnt/hgfs/commonlib/branches/1.9"..., 4096) = 32 open("/var/www/site/php/public/Zend/Controller/Plugin/Abstract.php", # curl http://mysite.local/ lstat("/mnt", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0 lstat("/mnt/hgfs", {st_mode=S_IFDIR|0555, st_size=4192, ...}) = 0 O_RDONLY) = -1 ENOENT (No such file or directory) lstat("/mnt/hgfs/commonlib", {st_mode=S_IFDIR|0755, st_size=170, ...}) = 0 lstat("/mnt/hgfs/commonlib/branches", {st_mode=S_IFDIR|0755, st_size=136, ...}) = 0 lstat("/mnt/hgfs/commonlib/branches/1.9", {st_mode=S_IFDIR|0755, st_size=272, ...}) = 0 lstat("/mnt/hgfs/commonlib/branches/1.9/Zend", 0x7fff89049af0) = -1 ENOENT (No such file or directory) ... open("/var/www/commonlib/current/Zend/Controller/Plugin/Abstract.php", O_RDONLY) = -1 ENOENT (No such file or directory) lstat("/usr", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0 # less /tmp/strace.out lstat("/usr/local", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0 lstat("/usr/local/zend", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0 lstat("/usr/local/zend/share", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0 lstat("/usr/local/zend/share/ZendFramework", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0 lstat("/usr/local/zend/share/ZendFramework/library", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0 lstat("/usr/local/zend/share/ZendFramework/library/Zend", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0 lstat("/usr/local/zend/share/ZendFramework/library/Zend/Controller", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0 lstat("/usr/local/zend/share/ZendFramework/library/Zend/Controller/Plugin", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0 lstat("/usr/local/zend/share/ZendFramework/library/Zend/Controller/Plugin/Abstract.php", {st_mode=S_IFREG|0644, st_size=4298, ...}) = 0 open("/usr/local/zend/share/ZendFramework/library/Zend/Controller/Plugin/Abstract.php", O_RDONLY) = 40 33
  • 64. System calls # grep 'stat' /tmp/strace.out | wc -l 20511 # /usr/bin/strace -p 5772 -c Process 5772 attached - interrupt to quit Process 5772 detached % time seconds usecs/call calls errors syscall ------ ---------- ---------- ------ ------ ------- 50.86 0.131501 7 20054 2029 lstat 28.42 0.073497 742 99 76 access 16.78 0.043385 32 1337 1095 open 1.61 0.004167 5 798 1 read 0.94 0.002436 13 193 getcwd ... ------ ---------- ---------- ------ ------ ------- 100.00 0.020951 1267 103 total 34
  • 65. System calls # grep 'stat' /tmp/strace.out | wc -l 20511 # /usr/bin/strace -p 5772 -c Process 5772 attached - interrupt to quit Process 5772 detached % time seconds usecs/call calls errors syscall ------ ---------- ---------- ------ ------ ------- 50.86 0.131501 7 20054 2029 lstat 28.42 0.073497 742 99 76 access 16.78 0.043385 32 1337 1095 open 1.61 0.004167 5 798 1 read 0.94 0.002436 13 193 getcwd ... ------ ---------- ---------- ------ ------ ------- 100.00 0.020951 1267 103 total 34
  • 66. Fix include_path (disk I/O) set_include_path(implode(PATH_SEPARATOR, array( ‘../library/’, // project library classes ‘./models/’, // project models ‘/usr/local/php/share/’, // framework )); The order (and number!) of the include paths is important. Tip: increase the realpath_cache size. 35
  • 67. Fix include_path (disk I/O) set_include_path(implode(PATH_SEPARATOR, array( ‘../library/’, // project// framework ‘/usr/local/php/share/’, library classes ‘./models/’, ‘../library/’, // project models classes library ‘/usr/local/php/share/’, // framework ‘./models/’, // project models )); The order (and number!) of the include paths is important. Tip: increase the realpath_cache size. 35
  • 68. Apache config open("/var/www/.htaccess", O_RDONLY) = -1 ENOENT open("/var/www/php/.htaccess", O_RDONLY) = -1 ENOENT open("/var/www/php/site/.htaccess", O_RDONLY) = -1 ENOENT open("/var/www/php/site/org/.htaccess", O_RDONLY) = -1 ENOENT open("/var/www/php/site/org/view/.htaccess", O_RDONLY) = -1 ENOENT ... open("/var/www/php/site/index.html", O_RDONLY) = -1 ENOENT open("/var/www/php/site/index.cgi", O_RDONLY) = -1 ENOENT open("/var/www/php/site/index.php", O_RDONLY) = 0 ... open("/var/www/php/site/favicon.ico", O_RDONLY) = -1 ENOENT Turn AllowOverride off Optimise DirectoryIndex Add favicon.cio 36
  • 69. Fix autoloader (disk I/O) function __autoload($className) { if (class_exists($className, false)) return; if ( (($file = apc_fetch($className)) === false) || ($file === null)) { $classFile = str_replace(‘_’, DIRECTORY_SEPARATOR, $className) . ‘.php’; $file = stream_resolve_include_path($classFile); if ($file !== false) { apc_store($className, $file, 86400); } else { apc_store($className, null, 86400); } } if (($file !== false) && ($file !== null)) { include $file; } } 37
  • 70. Fix autoloader (disk I/O) function __autoload($className) { if (class_exists($className, false)) return; if ( (($file = apc_fetch($className)) === false) || ($file === null)) { $classFile = str_replace(‘_’, DIRECTORY_SEPARATOR, $className) . ‘.php’; $file = stream_resolve_include_path($classFile); if ($file !== false) { apc_store($className, $file, 86400); } else { apc_store($className, null, 86400); } } if (($file !== false) && ($file !== null)) { include $file; } } 37
  • 71. Fix autoloader (disk I/O) function __autoload($className) { if (class_exists($className, false)) return; if ( (($file = apc_fetch($className)) === false) || ($file === null)) { $classFile = str_replace(‘_’, DIRECTORY_SEPARATOR, $className) . ‘.php’; $file = stream_resolve_include_path($classFile); if ($file !== false) { apc_store($className, $file, 86400); } else { apc_store($className, null, 86400); } } if (($file !== false) the ($file !== null)) { Rely on && autoloader. include $file; } Avoid explicit includes } http://devzone.zend.com/article/4525 37
  • 72. OPCode cache APC XCache Zend Accelerator WinCache eAccelerator ... 38
  • 73. OPCode cache APC XCache Zend Accelerator WinCache eAccelerator ... # grep 'open(' /tmp/strace.out open("/usr/local/php/share/Zend/Log.php", O_RDONLY) = 40 open("/usr/local/php/share/Zend/Form.php", O_RDONLY) = 40 open("/usr/local/php/share/Zend/Locale.php", O_RDONLY) = 40 38
  • 74. OPCode cache APC XCache Zend Accelerator WinCache eAccelerator ... # grep 'open(' /tmp/strace.out open("/usr/local/php/share/Zend/Log.php", O_RDONLY) = 40 open("/usr/local/php/share/Zend/Form.php", O_RDONLY) = 40 open("/usr/local/php/share/Zend/Locale.php", O_RDONLY) = 40 Conditional includes may cause OPCode cache trashing 38
  • 75. Include Hierarchy - PECL inclued http://pecl.php.net/package/inclued 39
  • 76. Watch your error log! Warning: Undefined index: NAME in file.php on line 1269 Warning: Undefined index: DESC in file.php on line 1270 Warning: Undefined variable: $str in a.php on line 341 Warning: Undefined index: DESC in file.php on line 1270 @ Error suppression is bad http://derickrethans.nl/five-reasons-why-the-shutop-operator-should-be-avoided.html 40
  • 77. Watch your error log! Warning: Undefined index: NAME in file.php on line 1269 Warning: Undefined index: DESC in file.php on line 1270 Warning: Undefined variable: $str in a.php on line 341 Warning: Undefined index: DESC in file.php on line 1270 @ Error suppression is bad http://derickrethans.nl/five-reasons-why-the-shutop-operator-should-be-avoided.html 40
  • 78. Log and analyse external requests /* HTTP Client */ function request($url, $method = ‘GET’) { $this->log(‘[HTTP] ’ . $method . ‘ ’ . $url); $ch = curl_init(); // ... } /* DB Client */ function query($sql) { $this->log(‘[DB] ’ . $query); // ... return $this->db->query($sql); } 41
  • 79. Log and analyse external requests /* HTTP Client */ function request($url, $method = ‘GET’) { $this->log(‘[HTTP] ’ . $method . ‘ ’ . $url); $ch = curl_init(); // ... } /* DB Client */ function query($sql) { $this->log(‘[DB] ’ . $query); // ... return $this->db->query($sql); } 41
  • 80. Analyse logs (Observability) [HTTP] GET http://myservice.com/list/somelist [HTTP] GET http://myservice.com/id/1 [HTTP] PUT http://myservice.com/id/3/value/xyz [HTTP] GET http://myservice.com/list/somelist [HTTP] GET http://myservice.com/list/somelist [DB] SELECT * FROM mytable; [DB] SELECT name FROM cities ORDER BY name; [DB] SELECT name FROM cities ORDER BY name; [DB] SELECT name FROM cities ORDER BY name; [DB] UPDATE mytable SET name=‘xyz’ WHERE id=3; Consider caching frequent requests 42
  • 81. Profile under load Collect profile data from a sample of random requests if (0 == mt_rand(0, 1000)) { // collect profile data } 43
  • 82. Profile under load Collect profile data from a sample of random requests if (0 == mt_rand(0, 1000)) { // collect profile data } Monitor resource usage in real time (top / htop / vmstat) 43
  • 83. Profile under load Collect profile data from a sample of random requests if (0 == mt_rand(0, 1000)) { // collect profile data } Monitor resource usage in real time (top / htop / vmstat) Analyse graphs JMeter The Grinder 43
  • 84. Performance Counters Used / available memory (local, shared) Pages / sec Response time & Time-outs Successful / failed transactions Open sockets / connections Bandwidth (internal network too!) CPU All the resources are limited ... 44
  • 87. Circuit Breaker public function fetchData($key) { return $this->callService($key); } 47
  • 88. Circuit Breaker public function fetchData($key) { $config = array( 'check_timeout' => 10, 'failure_threshold' => 10, ); $cb = new Circuit_Breaker('name', $config); if ($cb->isClosed()) { $ok = $this->callService($key); public function fetchData($key) { if ($ok) { return $this->callService($key); } $cb->success(); } else { //increment failures count $cb->fail(); } } } 47
  • 89. Poor man’s circuit breaker public function fetchData($key) { static $failures = 0; if ($failures < self::MAX_FAILURES) { $ok = $this->callService($key); if ($ok) { --$failures; } else { ++$failures; } } } Save the counter in memcached instead of a static variable, if possible 48
  • 90. Reverse Proxy http://www.varnish-cache.org/ 49
  • 91. Conclusions Parting thoughts 50
  • 92. Performance Checklist Deep understanding of the problem at hand Good architecture / design / data structures / algorithms Do the absolute minimum Use the right tools, always validate assumptions Monitor resource usage (!), with many metrics Spread the load uniformly across the resources Decouple services Good caching strategy strategies (sharing / reuse) 51
  • 93. Links + References http://www.slideshare.net/postwait/scalable-internet-architecture http://techportal.ibuildings.com/2009/12/01/profiling-with-xhprof/ http://www.chehodgins.com/php/sorting-out-your-php-includes-using-inclued/ http://weierophinney.net/matthew/archives/245-Autoloading-Benchmarks.html http://www.mail-archive.com/internals@lists.php.net/msg37192.html http://talks.php.net/show/digg http://mirror.facebook.net/facebook/xhprof/ http://xdebug.org/ http://github.com/facebook/pfff/ 52
  • 94. Image Credits http://michaelscomments.files.wordpress.com/2009/10/onion- centurion.jpg http://www.socketmanufacturers.com/miniature-circuit- breaker/DZ47-63-3P-Miniature-Circuit-Breaker.jpg http://onscreencars.com/tv/the-homer-the-car-built-for-homer/ http://etc.usf.edu/presentations/themes/index.html http://www.iconfinder.com/ 53
  • 96. Lorenzo Alberton @lorenzoalberton Thank you! lorenzo@alberton.info http://www.alberton.info/talks http://joind.in/talk/view/2051 55

Editor's Notes