What's up with OPCache ?
PHP 7 OPCode Cache tour
Hello everybody
 Julien PAULI
 Programming in PHP since ~20y (~1999-2000)
 Programming in C for PHP Internals
 PHP 5.5 and 5.6 Release Manager
 Working at SensioLabs in Paris
 http://www.phpinternalsbook.com co-author
 @julienpauli - http://jpauli.tech - jpauli@php.net
What we'll cover together
 Reminder on how PHP works
 Introduction to OPCodes
 The need of an OPCode cache
 OPCache in deep
 OPCache configuration settings
What is PHP ?
 PHP
 Programming language
 "Scripting language"
 No *manual* compilation needed
 Fire and forget
 Automatic memory management
 Facultative strong typing. Type juggler
 Provides OOP features
 Highly dynamic, highly extensible
How does PHP work ?
Parsing
(Lexer + parser)
Compiling
Executing
opcodes
PHP code
AST nodes
Result
Zend Virtual Machine
Parsing
(Lexer + parser)
Compiling
Executing
 "VirtualMachine"
 Its purpose is to provide a platform-
independent programming
environment that abstracts away
details of the underlying hardware or
operating system, and allows a
program to execute in the same way
on any platform (Wikipedia)
The PHP way
 Compile, execute, forget - Compile, execute, forget -
Compile, execute, forget - Compile, execute, forget -
Compile, execute, forget - Compile, execute, forget -
Compile, execute, forget - Compile, execute, forget …
 By default (by design), PHP discards all the code it just
executed
 Request n+1 knows nothing about request n
The PHP Way
 If your pages get hit several times without changing (most
likely)
 → compile the same scripts several times
 → it still produces the same OPCodes
Parsing
(Lexer + parser)
Compiling
Compiling VS Executing
 Compile, then execute
 Which one is the longest ?
 Depends on your scripts
Compile
Execute
Execute
Compile
Compiling VS Executing
 Compilation can really take time
 Usually less than execution, but...
Understanding compil. / exec.
 Classes usually require much more compile time than exec
time
 include / require / eval() = compile + execute
 autoload = compile + execute
 .. deffered at execution
Compile Execute
include/require ?
eval() ?
autoload ?
B
N
Y
E
OPCode cache roles
Parsing
(Lexer + parser)
Compiling
Executing
opcodes
PHP code
AST nodes
Result
Caching
opcodes
Save at first run
Compiling
Executing
opcodes
AST nodes
Caching
opcodesShared
Memory
opcodes
save
time
File
System
OR
Load (same script) after
OPCode cache
Executing
opcodes
PHP code
opcodes
load
Shared
Memory
File
System
OR
Optimize
 Why not optimize the OPCode array ?
opcodes
Optimizing
opcodes
opcodes
Caching
Compiling
save
Executing
opcodes
Shared
Memory
File
System
OR
PHP OPCache
OPCodes explained
OPCode
 In computer science, an opcode (operation code) is the
portion of a machine language instruction that specifies the
operation to be performed. (Wikipedia)
 Opcodes can also be found in so called byte codes and
other representations intended for a software interpreter
rather than a hardware device. (Wikipedia)
Zend OPCodes
Example of OPCode
<?php
const DEF = "default";
if (isset($argv[1])) {
$b = (array)$argv[1];
} else {
$b = DEF;
}
var_dump($b);
Example of OPCode
<?php
const DEF = "default";
if (isset($argv[1])) {
$b = (array)$argv[1];
} else {
$b = DEF;
}
var_dump($b);
L0 (3): DECLARE_CONST string("DEF") string("default")
L1 (5): T2 = ISSET_ISEMPTY_DIM_OBJ (isset) CV0($argv) int(1)
L2 (5): JMPZ T2 L7
L3 (6): T3 = FETCH_DIM_R CV0($argv) int(1)
L4 (6): T4 = CAST (array) T3
L5 (6): ASSIGN CV1($b) T4
L6 (6): JMP L9
L7 (8): T6 = FETCH_CONSTANT (unqualified) string("DEF")
L8 (8): ASSIGN CV1($b) T6
L9 (11): INIT_FCALL 1 96 string("var_dump")
L10 (11): SEND_VAR CV1($b) 1
L11 (11): DO_ICALL
L12 (12): RETURN int(1)
3
5
6
7
8
11
Example of OPCode
<?php
const DEF = "default";
if (isset($argv[1])) {
$b = (array)$argv[1];
} else {
$b = DEF;
}
var_dump($b);
Execution
Compilation
 The more code to parse, the longer the compilation phase
 The more OPCodes generated, the longer the execution
 Depends on OPCodes, some are long to run, some are very fast
DECLARE_CONST
ISSET_ISEMPTY_DIM_OBJ
JMPZ
FETCH_DIM_R
CAST
ASSIGN
JMP
FETCH_CONSTANT
ASSIGN
INIT_FCALL
SEND_VAR
DO_ICALL
RETURN
Optimize execution
 Some OPCodes are heavier than
others
 OPCodes may be run several
times (in fact, yes they do)
 The optimizer can play a role
Optimizing
Caching
Compiling
Executing
OPCache
 "OPCache" is PHP OPCode cache
 It is both a cache, and an optimizer
 It is bundled by defaut with PHP
 But it may not be activated by default
Optimizer
 Tries to simplify/optimize the OPCodes so that there are
less of them and they are more efficient
 Works on code branches (if, switch, try …)
 Optimize constant expressions - Look for dead code / code reuse
Try the optimizer
php 
-dzend_extension=opcache 
-dopcache.enable_cli=1 
-dopcache.opt_debug_level=0x30000 
-dopcache.optimization_level=0x7FFFFFFF 
/tmp/php.php
Optimizer impact
 The optimizer is very heavy, and burns tons of CPU cycles
 At compilation
 But compilation only happens once, as opcodes will be
cached
 So they'd better be cached optimized, than raw
 The very first run of a big application should pay a big perf
penalty
 Prime your caches
 Use OPCache file-based cache
Interned strings optimized
 In computer science, string interning is a method of storing
only one copy of each distinct string value, which must be
immutable. Interning strings makes some string processing
tasks more time- or space-efficient at the cost of requiring
more time when the string is created or interned. The
distinct values are stored in a string intern pool
Wikipedia
Interned strings concept
 Anytime a static string occurs in compiler, memorize it,
and reuse its pointer when needed.
 OPCache optimizes them even more
class foo
{
public function bar($a = "foo")
{
}
}
$foo = new foo;
$foo->bar("foo");
No Interned strings
class foo
{
public function bar($a = "foo")
{
}
}
$foo = new foo;
$foo->bar("foo");
foo bar a foo foo foo foo bar foo
memory
Interned strings
class foo
{
public function bar($a = "foo")
{
}
}
$foo = new foo;
$foo->bar("foo");
foo bar a
memory
OPCache & interned strings
 OPCache interns strings from all PHP processes of the same
PHP pool
 Nice memory savings on big pools
interned string mem interned string mem interned string mem
interned string mem
Tune your OPCache string buffer
php -dzend_extension=opcache 
-dopcache.memory_consumption=1024 
-dopcache.interned_strings_buffer=64 
/tmp/foo.php
Mb
Comments are interned strings
 How many interned string bytes for this script ?
<?php
/**
* @param $a string
*/
function foo(string $a)
{
}
PHPDoc comments are interned strings
 How many interned string bytes for this script ?
 opcache.save_comments = 0 disables saving of PHPDoc
comments to shared memory
<?php
/**
* @param $a string
*/
function foo(string $a)
{
}
28 + 3 + 1 + {garbage}
0 ending strings in C + some alignment bytes
PHP OPCache
OPCache API, settings and tuning
OPCache settings
 memory_consumption
 Size of Shared Memory
 Don't forget to increase according to your needs
 Buy more RAM, NEVER have a cache full, have margin
 max_accelerated_files (=2000)
 Max number of KEYS to be stored
 KEYS are paths to files : ./foo.php, ../foo.php, etc...
 One file usually is ~= 2 to 3 KEYS
 Aligned at next prime number
 Slots are preallocated : don't give too high number
 Monitor
OPCache explained
 memory_consumption=128M
 max_accelerated_files = 3000
 Next prime : 3907
 Cached files : 1878
 Cached keys : 2722 / 3907
OPCache settings
 validate_timestamps (=true)
 Check for file update to invalidate it
 Checks are triggered every revalidate_freq seconds
 revalidate_freq (=2)
 How often check for file updates to invalidate them
 0 = every time
 Revalidate = syscall cached by PHP's realpath cache
 revalidate_paths (=0)
 1 : only the resolved realpath is used as cache key
 0 : the unresolved path is also added as a cache key
 use_cwd (=1)
 prepend cwd to every cache key for relative paths
OPCache memory details
 When a script changes, it is
recompiled (if validate_timestamps
= 1)
 Its old memory space is then
considered as "wasted" (it is then
NOT freed)
 When cache is full, if max_wasted_percentage is reached :
a cache restart is triggered
 Cache restart = empty cache and recompile all
 Cache is never restarted if not full
OPcache other settings
 optimization_level (=0x7fffffff)
 Enable/disable some optimizations.
 enable_file_override (=0)
 Redefines file_exists(), is_readable() and is_file() to look into cache
before : recommanded
 blacklist_filename (=NULL)
 Prevents caching some files you decide
 consistency_checks (=0)
 Computes a checksum at each file fetch. Not recommanded, ~5-
8% slowdown
 opcache.save_comments (=1)
 Saves PHPDoc comments to shared memory
OPcache other settings
 enable_cli (=0)
 Enables opcache in CLI mode
 Long living apps like PHPUnit and COmposer mat benefit from the
optimizer and the cache
 Other short scripts will pay an impact against the optimizer : don't
enable
 huge_code_pages (=0)
 Moves the PHP process code memory segment to huge pages
 On some specific OS, with a mainly-statically-linked PHP, that can have
a beneficial impact
 Check /proc/meminfo to activate HugePage before usage
 protect_memory (=0)
 mprotect() the SHM against writes. Useless until you find a bug, crash,
and want to debug it
Know what happens
 error_log (=stderr)
 File to write log to
 log_verbosity_level (=1)
 0=fatals … 4=debug
OPCache do's and don't's
 Prime your cache smoothly
 https://github.com/engineyard/ey-php-performance-tools
 Prevent cache stampede
 Have enough shared memory
 Size your hashtables correctly
 Try not to generate php files on runtime
 Prevent highly modified files from beeing cached
 Use blacklists
 Every cache action will lock the shared memory
 And PHP Engine is not threaded
Thank you for listening

PHP 7 OPCache extension review

  • 1.
    What's up withOPCache ? PHP 7 OPCode Cache tour
  • 2.
    Hello everybody  JulienPAULI  Programming in PHP since ~20y (~1999-2000)  Programming in C for PHP Internals  PHP 5.5 and 5.6 Release Manager  Working at SensioLabs in Paris  http://www.phpinternalsbook.com co-author  @julienpauli - http://jpauli.tech - jpauli@php.net
  • 3.
    What we'll covertogether  Reminder on how PHP works  Introduction to OPCodes  The need of an OPCode cache  OPCache in deep  OPCache configuration settings
  • 4.
    What is PHP?  PHP  Programming language  "Scripting language"  No *manual* compilation needed  Fire and forget  Automatic memory management  Facultative strong typing. Type juggler  Provides OOP features  Highly dynamic, highly extensible
  • 5.
    How does PHPwork ? Parsing (Lexer + parser) Compiling Executing opcodes PHP code AST nodes Result
  • 6.
    Zend Virtual Machine Parsing (Lexer+ parser) Compiling Executing  "VirtualMachine"  Its purpose is to provide a platform- independent programming environment that abstracts away details of the underlying hardware or operating system, and allows a program to execute in the same way on any platform (Wikipedia)
  • 7.
    The PHP way Compile, execute, forget - Compile, execute, forget - Compile, execute, forget - Compile, execute, forget - Compile, execute, forget - Compile, execute, forget - Compile, execute, forget - Compile, execute, forget …  By default (by design), PHP discards all the code it just executed  Request n+1 knows nothing about request n
  • 8.
    The PHP Way If your pages get hit several times without changing (most likely)  → compile the same scripts several times  → it still produces the same OPCodes Parsing (Lexer + parser) Compiling
  • 9.
    Compiling VS Executing Compile, then execute  Which one is the longest ?  Depends on your scripts Compile Execute Execute Compile
  • 10.
    Compiling VS Executing Compilation can really take time  Usually less than execution, but...
  • 11.
    Understanding compil. /exec.  Classes usually require much more compile time than exec time  include / require / eval() = compile + execute  autoload = compile + execute  .. deffered at execution Compile Execute include/require ? eval() ? autoload ? B N Y E
  • 12.
    OPCode cache roles Parsing (Lexer+ parser) Compiling Executing opcodes PHP code AST nodes Result Caching opcodes
  • 13.
    Save at firstrun Compiling Executing opcodes AST nodes Caching opcodesShared Memory opcodes save time File System OR
  • 14.
    Load (same script)after OPCode cache Executing opcodes PHP code opcodes load Shared Memory File System OR
  • 15.
    Optimize  Why notoptimize the OPCode array ? opcodes Optimizing opcodes opcodes Caching Compiling save Executing opcodes Shared Memory File System OR
  • 16.
  • 17.
    OPCode  In computerscience, an opcode (operation code) is the portion of a machine language instruction that specifies the operation to be performed. (Wikipedia)  Opcodes can also be found in so called byte codes and other representations intended for a software interpreter rather than a hardware device. (Wikipedia)
  • 18.
  • 19.
    Example of OPCode <?php constDEF = "default"; if (isset($argv[1])) { $b = (array)$argv[1]; } else { $b = DEF; } var_dump($b);
  • 20.
    Example of OPCode <?php constDEF = "default"; if (isset($argv[1])) { $b = (array)$argv[1]; } else { $b = DEF; } var_dump($b); L0 (3): DECLARE_CONST string("DEF") string("default") L1 (5): T2 = ISSET_ISEMPTY_DIM_OBJ (isset) CV0($argv) int(1) L2 (5): JMPZ T2 L7 L3 (6): T3 = FETCH_DIM_R CV0($argv) int(1) L4 (6): T4 = CAST (array) T3 L5 (6): ASSIGN CV1($b) T4 L6 (6): JMP L9 L7 (8): T6 = FETCH_CONSTANT (unqualified) string("DEF") L8 (8): ASSIGN CV1($b) T6 L9 (11): INIT_FCALL 1 96 string("var_dump") L10 (11): SEND_VAR CV1($b) 1 L11 (11): DO_ICALL L12 (12): RETURN int(1) 3 5 6 7 8 11
  • 21.
    Example of OPCode <?php constDEF = "default"; if (isset($argv[1])) { $b = (array)$argv[1]; } else { $b = DEF; } var_dump($b); Execution Compilation  The more code to parse, the longer the compilation phase  The more OPCodes generated, the longer the execution  Depends on OPCodes, some are long to run, some are very fast DECLARE_CONST ISSET_ISEMPTY_DIM_OBJ JMPZ FETCH_DIM_R CAST ASSIGN JMP FETCH_CONSTANT ASSIGN INIT_FCALL SEND_VAR DO_ICALL RETURN
  • 22.
    Optimize execution  SomeOPCodes are heavier than others  OPCodes may be run several times (in fact, yes they do)  The optimizer can play a role Optimizing Caching Compiling Executing
  • 23.
    OPCache  "OPCache" isPHP OPCode cache  It is both a cache, and an optimizer  It is bundled by defaut with PHP  But it may not be activated by default
  • 24.
    Optimizer  Tries tosimplify/optimize the OPCodes so that there are less of them and they are more efficient  Works on code branches (if, switch, try …)  Optimize constant expressions - Look for dead code / code reuse
  • 25.
    Try the optimizer php -dzend_extension=opcache -dopcache.enable_cli=1 -dopcache.opt_debug_level=0x30000 -dopcache.optimization_level=0x7FFFFFFF /tmp/php.php
  • 26.
    Optimizer impact  Theoptimizer is very heavy, and burns tons of CPU cycles  At compilation  But compilation only happens once, as opcodes will be cached  So they'd better be cached optimized, than raw  The very first run of a big application should pay a big perf penalty  Prime your caches  Use OPCache file-based cache
  • 27.
    Interned strings optimized In computer science, string interning is a method of storing only one copy of each distinct string value, which must be immutable. Interning strings makes some string processing tasks more time- or space-efficient at the cost of requiring more time when the string is created or interned. The distinct values are stored in a string intern pool Wikipedia
  • 28.
    Interned strings concept Anytime a static string occurs in compiler, memorize it, and reuse its pointer when needed.  OPCache optimizes them even more class foo { public function bar($a = "foo") { } } $foo = new foo; $foo->bar("foo");
  • 29.
    No Interned strings classfoo { public function bar($a = "foo") { } } $foo = new foo; $foo->bar("foo"); foo bar a foo foo foo foo bar foo memory
  • 30.
    Interned strings class foo { publicfunction bar($a = "foo") { } } $foo = new foo; $foo->bar("foo"); foo bar a memory
  • 31.
    OPCache & internedstrings  OPCache interns strings from all PHP processes of the same PHP pool  Nice memory savings on big pools interned string mem interned string mem interned string mem interned string mem
  • 32.
    Tune your OPCachestring buffer php -dzend_extension=opcache -dopcache.memory_consumption=1024 -dopcache.interned_strings_buffer=64 /tmp/foo.php Mb
  • 33.
    Comments are internedstrings  How many interned string bytes for this script ? <?php /** * @param $a string */ function foo(string $a) { }
  • 34.
    PHPDoc comments areinterned strings  How many interned string bytes for this script ?  opcache.save_comments = 0 disables saving of PHPDoc comments to shared memory <?php /** * @param $a string */ function foo(string $a) { } 28 + 3 + 1 + {garbage} 0 ending strings in C + some alignment bytes
  • 35.
    PHP OPCache OPCache API,settings and tuning
  • 36.
    OPCache settings  memory_consumption Size of Shared Memory  Don't forget to increase according to your needs  Buy more RAM, NEVER have a cache full, have margin  max_accelerated_files (=2000)  Max number of KEYS to be stored  KEYS are paths to files : ./foo.php, ../foo.php, etc...  One file usually is ~= 2 to 3 KEYS  Aligned at next prime number  Slots are preallocated : don't give too high number  Monitor
  • 37.
    OPCache explained  memory_consumption=128M max_accelerated_files = 3000  Next prime : 3907  Cached files : 1878  Cached keys : 2722 / 3907
  • 38.
    OPCache settings  validate_timestamps(=true)  Check for file update to invalidate it  Checks are triggered every revalidate_freq seconds  revalidate_freq (=2)  How often check for file updates to invalidate them  0 = every time  Revalidate = syscall cached by PHP's realpath cache  revalidate_paths (=0)  1 : only the resolved realpath is used as cache key  0 : the unresolved path is also added as a cache key  use_cwd (=1)  prepend cwd to every cache key for relative paths
  • 39.
    OPCache memory details When a script changes, it is recompiled (if validate_timestamps = 1)  Its old memory space is then considered as "wasted" (it is then NOT freed)  When cache is full, if max_wasted_percentage is reached : a cache restart is triggered  Cache restart = empty cache and recompile all  Cache is never restarted if not full
  • 40.
    OPcache other settings optimization_level (=0x7fffffff)  Enable/disable some optimizations.  enable_file_override (=0)  Redefines file_exists(), is_readable() and is_file() to look into cache before : recommanded  blacklist_filename (=NULL)  Prevents caching some files you decide  consistency_checks (=0)  Computes a checksum at each file fetch. Not recommanded, ~5- 8% slowdown  opcache.save_comments (=1)  Saves PHPDoc comments to shared memory
  • 41.
    OPcache other settings enable_cli (=0)  Enables opcache in CLI mode  Long living apps like PHPUnit and COmposer mat benefit from the optimizer and the cache  Other short scripts will pay an impact against the optimizer : don't enable  huge_code_pages (=0)  Moves the PHP process code memory segment to huge pages  On some specific OS, with a mainly-statically-linked PHP, that can have a beneficial impact  Check /proc/meminfo to activate HugePage before usage  protect_memory (=0)  mprotect() the SHM against writes. Useless until you find a bug, crash, and want to debug it
  • 42.
    Know what happens error_log (=stderr)  File to write log to  log_verbosity_level (=1)  0=fatals … 4=debug
  • 43.
    OPCache do's anddon't's  Prime your cache smoothly  https://github.com/engineyard/ey-php-performance-tools  Prevent cache stampede  Have enough shared memory  Size your hashtables correctly  Try not to generate php files on runtime  Prevent highly modified files from beeing cached  Use blacklists  Every cache action will lock the shared memory  And PHP Engine is not threaded
  • 44.
    Thank you forlistening