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

PHP Performance I: Everything You Need to Know about OpCode Caches

Davey Shafik
September 30, 2013

PHP Performance I: Everything You Need to Know about OpCode Caches

Davey Shafik

September 30, 2013
Tweet

More Decks by Davey Shafik

Other Decks in Programming

Transcript

  1. PHP Performance I
    Everything you need to know about
    OpCode caches

    View Slide

  2. •Community Engineer at Engine
    Yard
    •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 1 & 2, phpdoc, and
    PHP internals
    •@dshafik
    Davey Shafik

    View Slide

  3. What are OpCode Caches?

    View Slide

  4. What are OpCode Caches?
    • Performance enhancing extensions for PHP
    • Inject themselves into the execution life-cycle of PHP
    and cache as much of it as possible
    • Common to see a 300% speed increase with default
    settings!
    4

    View Slide

  5. When Should I Use an
    OpCache?

    View Slide

  6. Always.
    No, really.

    View Slide

  7. Side Effects
    (I knew it couldn’t be that easy!)

    View Slide

  8. Cache Stampede

    View Slide

  9. Side Effects
    The primary side effect of using a cache is known as a
    cache stampede.
    This is where your cache expires while under heavy
    load.
    Caused by:
    • Restarting Server
    • Cache invalidation because of data edits
    • Newly provisioned servers being added to a cluster to help
    scale under load
    • Corruption (hardware issues)

    View Slide

  10. Which OpCode Cache

    View Slide

  11. Which OpCode Cache
    • There have been many caches, however till PHP 5.5
    the dominant choice was the Alternative PHP Cache
    (APC)
    • With PHP 5.5, Zend open sourced it’s proprietary
    Zend OpCache and contributed it to the PHP project
    • Zend OpCache is now enabled by default with PHP
    5.5+ unless disabled by --disable-all.
    • Zend OpCache is between 6-100% faster than APC
    11

    View Slide

  12. Which OpCode Cache
    • PHP 5.3 or 5.4, choose between Zend OpCache and
    Alternative PHP Cache (APC)
    • PHP 5.5+, we recommend Zend OpCache
    • Zend OpCache can be used with PHP 5.2+
    12

    View Slide

  13. Which OpCode Cache
    • A second extension can be installed alongside Zend
    OpCache to give backwards compatibility with APC’s
    User Cache: APCu
    • APCu is APC with the OpCode Caching removed
    • 100% Backwards Compatible
    13

    View Slide

  14. Installation

    View Slide

  15. Zend OpCache

    View Slide

  16. Installing Zend OpCache
    $ pecl install zendopcache-beta
    Add the following to your php.ini:
    [zendopcache]
    zend_extension=/full/path/to/opcache.so ; May be added by pecl
    opcache.memory_consumption=128
    opcache.interned_strings_buffer=8
    opcache.max_accelerated_files=4000
    opcache.revalidate_freq=60
    opcache.fast_shutdown=1
    opcache.enable_cli=1
    Restart PHP (php-fpm/apache)

    View Slide

  17. APC

    View Slide

  18. Installing APC
    $ pecl install apc-beta
    Add the following to your php.ini:
    [apc]
    extension=apc.so ; May be added by pecl
    apc.enabled=1
    Restart PHP (php-fpm/apache)

    View Slide

  19. APCu
    (Optional)
    For APC User Cache Compatibility

    View Slide

  20. Installing APCu
    $ pecl install apcu-beta
    Add the following to your php.ini:
    [apcu]
    extension=apcu.so ; May be added by pecl
    apc.serializer=php ; See bug report for more info: http://ey.io/1aJhcOY
    Restart PHP (php-fpm/apache)

    View Slide

  21. Engine Yard
    PHP Performance Tools

    View Slide

  22. Engine Yard PHP Performance Tools
    • A suite of tools to aid with improving PHP
    performance
    • Open Source, Apache 2.0 License
    • On Github: http://github.com/engineyard/ey-php-
    performance-tools
    • Composer Compatible Package
    22

    View Slide

  23. Installation
    Add composer.json configuration:
    "repositories": [
    {
    "type": "vcs",
    "url": "http://github.com/engineyard/ey-php-
    performance-tools"
    }
    ],
    "require": {
    "php": ">=5.3.3",
    "engineyard/php-performance-tools": "dev-master"
    }
    Run composer update:
    $ composer.phar update engineyard/php-performance-tools

    View Slide

  24. Solving The Cache Stampede

    View Slide

  25. Priming The Cache

    View Slide

  26. Zend OpCache

    View Slide

  27. cache-primer

    View Slide

  28. cache-primer
    Create a config.php:
    return [
    /* URLs to cache */
    'urls' => [
    'http://ephernote.com/',
    'http://ephernote.com/user/login',
    'http://ephernote.com/user/register',
    'http://ephernote.com/privary', // Note: this is a
    typo
    ],
    /* How many concurrent HTTP requests to make (requires
    the pecl_http extension) */
    'threads' => 3
    ];

    View Slide

  29. cache-primer
    Run the primer:
    $ /path/composer/vendor/bin/cache-primer
    === Cache Primer ===
    Attempting to cache 4 URLs:
    Running in parallel with 3 concurrent requests
    ...!
    Cached 3 URLs in 0.6162059307098 seconds
    Encountered 1 errors

    View Slide

  30. cache-primer
    === Cache Primer ===
    Attempting to cache 104 URLs:
    Running in parallel with 10 concurrent requests
    ..........................................................
    ..................!...........................
    Cached 103 URLs in 4.6162059307098 seconds
    Encountered 1 errors

    View Slide

  31. APC

    View Slide

  32. apc-primer

    View Slide

  33. Priming the Cache (APC)
    • Has built-in tools for priming the cache
    • Still requires a single HTTP request
    • Can cache more than just easily web accessible code
    • Any valid PHP can be cached, including partial view
    templates, global code, etc.
    • Use: engineyard/php-performance-tools/apc-primer
    33

    View Slide

  34. apc-primer
    • Provides basic HTTP security
    • We recommend not relying on it, instead integrate it behind
    other authentication instead (e.g. embed it into your admin
    control panel)
    • Uses apc_compile_file() to add code to the cache
    • Requires a wrapper to expose via HTTP
    • Caches all .php and .phtml files not inside a tests
    directory
    34

    View Slide

  35. apc-primer
    Create a config.php:
    if (!defined('DS')) {
    define('DS', DIRECTORY_SEPARATOR);
    }
    return [
    /* HTTP Basic Authentication: NOT RECOMMENDED */
    'auth' => [
    'enabled' => true,
    'username' => 'admin',
    'password' => 'changeme',
    ],
    /* Paths to cache (recursively) */
    'paths' => [
    __DIR__ .DS. '..' .DS. '..' .DS. '..' .DS. 'config',
    __DIR__ .DS. '..' .DS. '..' .DS. '..' .DS. 'module',
    __DIR__ .DS. '..' .DS. '..' .DS. '..' .DS. 'vendor',
    __DIR__ .DS. '..' .DS. '..' .DS. '..' .DS. 'public',
    ]
    ];

    View Slide

  36. apc-primer
    Place a simple wrapper in your web-root, e.g.
    /public/admin/apc-cache-primer.php
    // public/admin/apc-cache-primer.php
    require '../../vendor/engineyard/php-performance-
    tools/apc-primer/apc-primer.php';
    Request the file via HTTP:
    Cached 4841 files in 2.1302671432495 seconds

    View Slide

  37. Under the Hood
    OR: Here be dragons!

    View Slide

  38. Execution Life-Cycle

    View Slide

  39. Execution Life-cycle: PHP vs Java
    39

    View Slide

  40. Execution Lifecycle with an OpCode Cache

    View Slide

  41. Tokens & OpCodes

    View Slide

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

    View Slide

  43. Tokenizing

    View Slide

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

    View Slide

  45. Tokenizing
    • Note the difference between interpolated and non-
    interpolated strings.
    • They are both double quoted strings!
    • Interpolated: 4 Tokens
    • Non-interpolated: 1 Token
    • Start to see why this matters for performance: but
    don’t get caught up by micro-optimizations.
    45
    "
    T_ENCAPSED_AND_WHITESPACE Hello
    T_VARIABLE $to
    "
    T_CONSTANT_ENCAPSED_STRING "World"

    View Slide

  46. Compiling

    View Slide

  47. VLD
    Vulcan Logic Dumper

    View Slide

  48. VLD — Vulcan Logic Dumper
    • An extension to dump the compiled opcodes
    • Installed via PECL
    $ pecl install vld-beta
    Add the following to php.ini:
    extension=vld.so
    • Use via command line:
    $ php -dvld.active=1 -dvld.execute=0
    48

    View Slide

  49. VLD — Vulcan Logic Dumper
    • Outputs, in order:
    • global code (main script)
    • global functions
    • class functions
    49

    View Slide

  50. Understanding VLD Dumps
    Class Greeting:
    Function sayhello:
    filename: ./Greeting.php
    function name: sayHello
    Header
    compiled vars: !0 = $to
    number of ops: 8

    View Slide

  51. Understanding VLD Dumps (Cont.)
    • line: The line number in the source file
    • #: The opcode number
    • *: entry (left aligned) and exit points (right aligned), indicated by greater
    than symbols (>)
    • op: The opcode name
    • fetch: Details on global variable fetches (super globals, or the use of the
    global keyword)
    • ext: Extra data associated with the opcode, for example the opcode to
    which it should JMP
    • return: The location where return data from the operation is stored
    • operands: the operands used by the opcode (e.g. two variables to concat)
    51
    line # * op fetch ext return operands
    ----------------------------------------------------------------

    View Slide

  52. VLD — Variables
    • Four types of variables
    1. Exclamation point (!) are compiled variables (CVs) — these
    are pointers to userland variables
    2. Tilde (~) are temporary variables used for temporary
    storage (TMP_VARs) of in-process operations
    3. Dollar ($) are another type of temporary variables (VARs)
    which are tied to userland variables like CVs and therefore
    require things like refcounting.
    4. Colon (:) are temporary variables used for the storage of
    the result of lookups in the class hashtable
    52

    View Slide

  53. class Greeting -> sayHello
    Class Greeting:
    Function sayhello:
    compiled vars: !0 = $to
    line # * op fetch ext return operands
    ----------------------------------------------------------------
    3 0 > EXT_NOP
    1 RECV !0
    5 2 EXT_STMT
    3 ADD_STRING ~0 'Hello+'
    4 ADD_VAR ~0 ~0, !0
    5 ECHO ~0
    6 6 EXT_STMT
    7 > RETURN null
    class Greeting {
    public function sayHello($to) {
    echo "Hello $to";
    }
    }

    View Slide

  54. class Greeting -> sayHello
    • RECV: The function receives a value which is assigned
    to !0 (which represents $to)
    • ADD_STRING: Next we create a temporary variable
    identified by a ~, ~0 and assign the static string,
    'Hello+', where the + represents a space
    • ADD_VAR: After this, we concat the contents our
    variable, !0 to our temporary variable, ~0
    • ECHO: Then we echo that temporary variable
    • RETURN: Finally we return nothing as the function
    ends
    54

    View Slide

  55. Main Script
    compiled vars: !0 = $greeter
    line # * op fetch ext return operands
    --------------------------------------------------------------------
    2 0 > EXT_STMT
    1 NOP
    9 2 EXT_STMT
    3 FETCH_CLASS 4 :1 'Greeting'
    4 EXT_FCALL_BEGIN
    5 NEW $2 :1
    6 DO_FCALL_BY_NAME 0
    7 EXT_FCALL_END
    8 ASSIGN !0, $2
    10 9 EXT_STMT
    10 INIT_METHOD_CALL !0, 'sayHello'
    11 EXT_FCALL_BEGIN
    12 SEND_VAL 'World'
    13 DO_FCALL_BY_NAME 1
    14 EXT_FCALL_END
    12 15 EXT_STMT
    16 > RETURN 1
    $greeter = new Greeting();
    $greeter->sayHello("World");

    View Slide

  56. Main Script
    • FETCH_CLASS: First we lookup the class, Greeting; we store
    this reference in :1
    • NEW: Then we instantiate an instance of the class (:1) and
    assign it to a VAR, $2, and
    • DO_FCALL_BY_NAME: call the constructor
    • ASSIGN: Next we assign the resulting object (in VAR $2) to
    our CV (!0)
    • INIT_METHOD_CALL: We start calling the sayHello method,
    and
    • SEND_VAL: pass in 'World' to the method, and
    • DO_FCALL_BY_NAME: Actually execute the method
    • RETURN: The script ends successfully, with an implicit return
    of 1.
    56

    View Slide

  57. 57
    Resources
    • Zend OpCache Source Code: http://ey.io/17Qt6W9
    • Zend OpCache PECL Package: http://ey.io/18h2Inp
    • APC Source Code: http://ey.io/18gZ9iW
    • APC PECL Package: http://ey.io/15JuQkp
    • Understanding Opcodes (Sara Golemon): http://ey.io/19q32iD
    • More source analysis with VLD (Derick Rethans): http://ey.io/bx0q8N
    http://ey.io/opcaches

    View Slide

  58. http://ey.io/opcaches
    Feedback & Questions:
    Twitter: @dshafik
    Email: [email protected]

    View Slide