Upgrade to Pro — share decks privately, control downloads, hide ads and more …

[Lonestar PHP] Fast, Not Furious: How to identify and fix slow code

[Lonestar PHP] Fast, Not Furious: How to identify and fix slow code

There's a saying "hardware is cheaper than developers", but this only holds true if you treat your hardware with the respect it deserves.

Learn how to diagnose, confirm and fix bottlenecks in your application using new tools like XHProf and tried and true tools like xdebug.

Also, we'll take an in-depth look at apc (advanced PHP cache) and memcache; even if you know and use memcache, this one can probably teach you a thing or two.

Davey Shafik

June 30, 2012
Tweet

More Decks by Davey Shafik

Other Decks in Programming

Transcript

  1. Fast, Not Furious
    How to identify and fix slow code
    1

    View Slide

  2. •Engineer at Engine Yard for
    Orchestra.io PHP Platform as a
    Service (PaaS)
    •Author of Zend PHP 5 Certification
    Study Guide, Sitepoints PHP
    Anthology: 101 Essential Tips, Tricks
    & Hacks & PHP Master: Write
    Cutting Edge Code
    •A contributor to Zend Framework,
    phpdoc, FRAPI and PHP internals
    •@dshafik
    •(Buy My Books!)
    Davey Shafik
    2

    View Slide

  3. About These Slides
    5

    View Slide

  4. About These Slides
    • Two slides per “slide”
    • Title Slide (for when I’m talking)
    • Details slide (for later)
    • Nobody likes it when you can read the slide just as
    well as the speaker can
    • I like slides that are useful
    6

    View Slide

  5. Hardware is Cheap,
    Programmers are
    Expensive
    - Jeff Atwood
    7

    View Slide

  6. But only if you respect
    the hardware.
    - Me
    8

    View Slide

  7. Anecdote
    OR: why you shouldn’t randomly optimize
    — and why you should be careful with
    PHP 5.3’s memory garbage collection
    9

    View Slide

  8. Common Causes of
    Slowdowns
    10

    View Slide

  9. Common Causes of Slowdown
    1. Datastore
    • Doesn’t matter if it’s PostgreSQL, MySQL, Oracle, MongoDB,
    CouchDB, or MSSQL
    2. External Resources
    • APIs, Filesystems, Network Sockets, External Processes
    3. Bad Code
    • The only great code, is code that never has to run.
    Everything else, is just good code.
    11

    View Slide

  10. Do You Have a
    Problem?
    12

    View Slide

  11. Do You Have a Problem?
    • The #1 issue with performance tuning, is assuming
    you even have a problem.
    • Premature Optimization is a waste of time.
    • Determine desired performance (e.g. 100 concurrent
    users with less than 1s response times). Benchmark
    on production hardware. Do you even have a
    problem? How big?
    13

    View Slide

  12. The Performance
    Loop
    14

    View Slide

  13. Benchmark
    Profile
    Make
    Changes
    15

    View Slide

  14. But isn’t Profiling the
    same as
    Benchmarking?
    16

    View Slide

  15. Benchmarking Vs Profiling
    • Profiling Records Relative Speed + Memory Usage +
    # of calls per function + Call graph
    • The act of profiling affects the speed (the outcome) of the code
    (just like quantum physics!)
    • Benchmarking Tests Actual Speed
    • What your users actually see
    17

    View Slide

  16. Profiling with xhprof
    18

    View Slide

  17. Grab the tarball:
    $ wget http://pecl.php.net/get/
    xhprof-0.9.2.tgz
    $ tar –zxvf xhprof-0.9.2.tgz
    Change to the sub-directory:
    $ cd xhprof-0.9.2/extension
    Compile:
    $ ./configure --enable-xhprof
    $ make
    $ make install
    Installing xhprof
    19

    View Slide

  18. Update php.ini:
    [xhprof]
    extension=xhprof.so
    xhprof.output_dir="/tmp/xhprof"
    Restart your httpd.
    Installing xhprof (cont.)
    20

    View Slide

  19. Clone from git:
    $ git clone git://github.com/preinheimer/xhprof.git
    Setup the correct Database adapter:
    $ cd xhprof/xhprof_lib/utils
    $ rm xhprof_runs.php
    $ ln –s xhprof_runs_mysql.php xhprof_runs.php
    Installing xh-gui
    21

    View Slide

  20. Create the Database:
    CREATE TABLE `details` (
    `id` char(17) NOT NULL, `url` varchar(255) default NULL,
    `c_url` varchar(255) default NULL,
    `timestamp` timestamp NOT NULL default CURRENT_TIMESTAMP on update
    CURRENT_TIMESTAMP,
    `server name` varchar(64) default NULL, `perfdata` MEDIUMBLOB,
    `type` tinyint(4) default NULL, `cookie` BLOB,
    `post` BLOB, `get` BLOB, `pmu` int(11) default NULL,
    `wt` int(11) default NULL, `cpu` int(11) default NULL,
    `server_id` char(3) NOT NULL default 't11',
    `aggregateCalls_include` varchar(255) DEFAULT NULL,
    PRIMARY KEY (`id`), KEY `url` (`url`), KEY `c_url` (`c_url`),
    KEY `cpu` (`cpu`), KEY `wt` (`wt`), KEY `pmu` (`pmu`),
    KEY `timestamp` (`timestamp`)
    ) ENGINE=MyISAM DEFAULT CHARSET=utf8;
    Installing xh-gui
    22

    View Slide

  21. Update the config:
    $ cd .. # back up to xhprof_lib
    $ cp config.sample.php config.php
    Change these:
    $_xhprof['dbhost'] = 'localhost';
    $_xhprof['dbuser'] = 'username';
    $_xhprof['dbpass'] = 'password';
    $_xhprof['dbname'] = 'xhprof';
    $_xhprof['servername'] = 'myserver';
    $_xhprof['namespace'] = 'myapp';
    $_xhprof['url'] = 'http://url/to/xhprof/xhprof_html';
    Installing xh-gui
    23

    View Slide

  22. Setup Httpd:
    Apache:

    ServerName xh.dev
    DocumentRoot /path/to/xhprof/xhprof_html

    Nginx:
    server {
    listen 80 default_server;
    server_name xh.dev;
    root /path/to/xhprof/xhprof_html;
    index index.php;
    }
    Installing xh-gui
    24

    View Slide

  23. Using xhprof/xh-gui
    25

    View Slide

  24. Add prepend/append config to php.ini:
    auto_prepend_file = "/path/to/xhprof/external/header.php"
    auto_append_file = "/path/to/xhprof/external/footer.php"
    OR Apache VirtualHost:
    php_admin_value auto_prepend_file /path/to/xhprof/external/header.php
    php_admin_value auto_append_file /path/to/xhprof/external/footer.php
    Using xhprof/xh-gui
    26

    View Slide

  25. Demo
    27

    View Slide

  26. function _urlSimilartor($url) {
    $url = preg_replace("/[0-9]+/", "XXX", $url);
    $qs = parse_url($url, PHP_URL_QUERY);
    if ($qs) {
    $parts = array();
    parse_str($qs, $parts);
    $values = array_pad(array(), sizeof($parts), "XXX");
    $normalized = array_combine(array_keys($parts), $values);
    $replace = http_build_query($normalized);
    $url = str_replace($qs, $replace, $url);
    }
    $url = preg_replace("![?&]_profile=\d!", "", $url);
    return $url;
    }
    URL Similartor
    28

    View Slide

  27. Caching
    29

    View Slide

  28. Key-Value Stores
    30

    View Slide

  29. Key-Value Stores
    • APC
    • memcache
    • Cassandra
    • redis
    • Most NoSQL implementations (CouchDB, MongoDB,
    MemBase)
    31

    View Slide

  30. Memcache
    Namespacing
    32

    View Slide

  31. Namespace 1
    Data
    Data
    Data
    Data
    Data
    Data
    Data
    Data
    Data
    Data
    Data
    Data
    Namespace 2
    Data
    Data
    Data
    Data
    Data
    Data
    Data
    Data
    Data
    Data
    Data
    Data
    Memcache Namespaces
    33

    View Slide

  32. Namespace 1
    Data
    Data
    Data
    Data
    Data
    Data
    Data
    Data
    Data
    Data
    Data
    Data
    Namespace 2
    Data
    Data
    Data
    Data
    Data
    Data
    Data
    Data
    Data
    Data
    Data
    Data
    Memcache Namespaces
    33

    View Slide

  33. • Create a namespace key in memcache if there isn’t
    one
    • memcache_set('mynamespace', rand(1, 1000));
    • Use the namespace name, value, and the items
    unique key to create a key
    • mynamespace_189_a1773d62a609dd09e98ea1aebeddbd94
    • When you want to clear the cache, increment the
    namespace key
    • memcache_increment(‘mynamespace’);
    The Code
    34

    View Slide

  34. Namespace 1
    Namespace 1.1 Namespace 1.2
    Namespace 1.3 Namespace 1.4
    Data Data Data
    Data Data Data
    Data Data Data
    Data Data Data
    Data Data Data
    Data Data Data
    Data Data Data
    Data Data Data
    Memcache Namespace Segmenting
    35

    View Slide

  35. The Code
    • Create a segment key in memcache if there isn’t one
    • memcache_set('mynamespace_config', rand(1, 1000));
    • Use the namespace name, value, segment name,
    value and the items unique key to create a key
    • mynamespace_189_config_4_a609dd09e98ea1aebeddbd94
    • When you want to clear the segment cache,
    increment the segment key
    • memcache_increment('mynamespace_config');
    36

    View Slide

  36. example.org
    example.org_session example.org_public
    example.org_admin example.org_config
    Data Data Data
    Data Data Data
    Data Data Data
    Data Data Data
    Data Data Data
    Data Data Data
    Data Data Data
    Data Data Data
    Practical Cache Layout
    37

    View Slide

  37. require_once 'Cache/Memcache.php';
    $cache = new Cache_Memcache();
    $key = $_SERVER['REQUEST_URI'];
    $data = $cache->get($key, 'blog-pages');
    if ($data !== false) {
    echo $data;
    } else {
    ob_start();
    // output all the data to the buffer

    // Assign to $data and actually output
    $data = ob_get_flush();
    // Cache it
    $cache->set($key, $data, 'blog-pages');
    }
    Using The Code
    38

    View Slide

  38. require_once 'Cache/Memcache.php';
    $cache = new Cache_Memcache();
    $cache->clearCache('blog-pages');
    Clearing the Cache
    39

    View Slide

  39. Other Memcache
    Tricks
    40

    View Slide

  40. Other Memcache Tricks
    • Meta Key
    • json string containing:
    • Last modified date
    • # of slabs
    • Use date to send Last-Modified header and 304
    Not Modified Status
    • Use # of slabs to split content across multiple keys if
    > 1MB in size
    41

    View Slide

  41. Other Memcache Tricks
    Key: mynamespace_189_a1773d62a609dd09e98ea1aebeddbd94_meta
    {
    /* RFC 1123 */
    lastModified: "Fri, 29 Jun 2012 00:30:25 -0400",
    slabs: 2
    }
    42

    View Slide

  42. The Code
    43

    View Slide

  43. APC
    Use it.
    44

    View Slide

  44. OR: Here be dragons
    Getting Inside PHP
    45

    View Slide

  45. The Worst Hello World, Ever
    class Greeting {
    public function sayHello($to)
    {
    echo "Hello $to";
    }
    }
    $greeter = new Greeting();
    $greeter->sayHello("World");
    ?>
    46

    View Slide

  46. Token Name Value Token Name Value
    T_OPEN_TAG T_CLASS class }
    T_WHITESPACE T_WHITESPACE
    T_STRING Greeting }
    T_WHITESPACE T_WHITESPACE
    { T_VARIABLE $greeter
    T_WHITESPACE T_WHITESPACE
    T_PUBLIC public =
    T_WHITESPACE T_WHITESPACE
    T_FUNCTION function T_NEW new
    T_WHITESPACE T_WHITESPACE
    T_STRING sayHello T_STRING Greeting
    ( (
    T_VARIABLE $to )
    ) ;
    T_WHITESPACE T_WHITESPACE
    { T_VARIABLE $greeter
    T_WHITESPACE T_OBJECT_OPERATOR ->
    T_ECHO echo T_STRING sayHello
    T_WHITESPACE (
    " T_CONSTANT_ENCAPSED_STRING "World"
    T_ENCAPSED_AND_WHITESPACE Hello )
    T_VARIABLE $to ;
    " T_WHITESPACE
    ; T_CLOSE_TAG ?>
    47

    View Slide

  47. Execution Lifecycle: PHP vs Java
    48

    View Slide

  48. Execution Lifecycle with APC
    49

    View Slide

  49. Installing APC
    •$ pecl install apc
    •Add: extension=apc.so to php.ini
    •Done. What’s your excuse?
    50

    View Slide

  50. Thank You!
    •Feedback:
    • https://joind.in/talk/view/6349
    • @dshafik
    [email protected]
    • Slides:
    • http://daveyshafik.com/slides
    51

    View Slide