Slide 1

Slide 1 text

PHP Performance I Everything you need to know about OpCode caches

Slide 2

Slide 2 text

•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

Slide 3

Slide 3 text

What are OpCode Caches?

Slide 4

Slide 4 text

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

Slide 5

Slide 5 text

When Should I Use an OpCache?

Slide 6

Slide 6 text

Always. No, really.

Slide 7

Slide 7 text

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

Slide 8

Slide 8 text

Cache Stampede

Slide 9

Slide 9 text

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)

Slide 10

Slide 10 text

Which OpCode Cache

Slide 11

Slide 11 text

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

Slide 12

Slide 12 text

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

Slide 13

Slide 13 text

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

Slide 14

Slide 14 text

Installation

Slide 15

Slide 15 text

Zend OpCache

Slide 16

Slide 16 text

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)

Slide 17

Slide 17 text

APC

Slide 18

Slide 18 text

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)

Slide 19

Slide 19 text

APCu (Optional) For APC User Cache Compatibility

Slide 20

Slide 20 text

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)

Slide 21

Slide 21 text

Engine Yard PHP Performance Tools

Slide 22

Slide 22 text

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

Slide 23

Slide 23 text

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

Slide 24

Slide 24 text

Solving The Cache Stampede

Slide 25

Slide 25 text

Priming The Cache

Slide 26

Slide 26 text

Zend OpCache

Slide 27

Slide 27 text

cache-primer

Slide 28

Slide 28 text

cache-primer Create a config.php: [ '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 ];

Slide 29

Slide 29 text

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

Slide 30

Slide 30 text

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

Slide 31

Slide 31 text

APC

Slide 32

Slide 32 text

apc-primer

Slide 33

Slide 33 text

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

Slide 34

Slide 34 text

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

Slide 35

Slide 35 text

apc-primer Create a config.php: [ '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', ] ];

Slide 36

Slide 36 text

apc-primer Place a simple wrapper in your web-root, e.g. /public/admin/apc-cache-primer.php

Slide 37

Slide 37 text

Under the Hood OR: Here be dragons!

Slide 38

Slide 38 text

Execution Life-Cycle

Slide 39

Slide 39 text

Execution Life-cycle: PHP vs Java 39

Slide 40

Slide 40 text

Execution Lifecycle with an OpCode Cache

Slide 41

Slide 41 text

Tokens & OpCodes

Slide 42

Slide 42 text

The Worst Hello World, Ever sayHello("World"); ?>

Slide 43

Slide 43 text

Tokenizing

Slide 44

Slide 44 text

Token Name Value T_OPEN_TAG T_STRING sayHello ( T_CONSTANT_ENCAPSED_STRING "World" ) ; T_WHITESPACE T_CLOSE_TAG ?> Tokenizing

Slide 45

Slide 45 text

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"

Slide 46

Slide 46 text

Compiling

Slide 47

Slide 47 text

VLD Vulcan Logic Dumper

Slide 48

Slide 48 text

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

Slide 49

Slide 49 text

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

Slide 50

Slide 50 text

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

Slide 51

Slide 51 text

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 ----------------------------------------------------------------

Slide 52

Slide 52 text

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

Slide 53

Slide 53 text

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"; } }

Slide 54

Slide 54 text

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

Slide 55

Slide 55 text

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");

Slide 56

Slide 56 text

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

Slide 57

Slide 57 text

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

Slide 58

Slide 58 text

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