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. •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
  2. 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
  3. 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)
  4. 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
  5. 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
  6. 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
  7. 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)
  8. APC

  9. 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)
  10. 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)
  11. 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
  12. 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
  13. cache-primer Create a config.php: <?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 ];
  14. 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
  15. 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
  16. APC

  17. 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
  18. 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
  19. apc-primer Create a config.php: <?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', ] ];
  20. apc-primer Place a simple wrapper in your web-root, e.g. /public/admin/apc-cache-primer.php

    <?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
  21. The Worst Hello World, Ever <?php class Greeting { public

    function sayHello($to) { echo "Hello $to"; } } $greeter = new Greeting(); $greeter->sayHello("World"); ?>
  22. Token Name Value T_OPEN_TAG <?php 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
  23. 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"
  24. 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 <file> 48
  25. VLD — Vulcan Logic Dumper • Outputs, in order: •

    global code (main script) • global functions • class functions 49
  26. Understanding VLD Dumps Class Greeting: Function sayhello: filename: ./Greeting.php function

    name: sayHello Header compiled vars: !0 = $to number of ops: 8
  27. 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 ----------------------------------------------------------------
  28. 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
  29. 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"; } }
  30. 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
  31. 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");
  32. 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
  33. 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