2. 2
Hello
● Julien PAULI
● Programming in PHP since early 2000s
● PHP Internals hacker and trainer
● PHP 5.5/5.6 Release Manager
● Working at SensioLabs in Paris - Blackfire
● Writing PHP tech articles and books
● http://phpinternalsbook.com
● @julienpauli - github.com/jpauli - jpauli@php.net
● Like working on OSS such as PHP :-)
3. 3
PHP
● A program in itself
● Written in C
● Goal : Define a programming Web language
● High level, interpreted
● Interpreted language
● Less efficient than native-instr compiled language
● but simpler to handle
6. 6
Zend Engine
● The heart of PHP
● An extensible part
● extensions and zend_extensions can change it
● A Virtual Machine
● A compiler
● An executor
● Some utilities
● OPCache
● A Zend extension that plays with the engine deeply
● Compiler optimizer is stored into OPCache
7. 7
Request treatment steps
● Startup (memory allocations)
● Compilation
● Lexical and syntaxic analysis
● Compilation (OP Code generation)
● Execution
● OPCode interpretation
● Several VM flavors
● Include/require/eval = go back to compilation
● Shutdown (free resources)
● "Share nothing architecture"
Startup
Shutdown
zend_compile_file()
zend_execute()
10. 10
Sementical analysis (parsing)
● "Understands" a set of tokens
● Defines the language syntax
● Parser generator : GNU/Bison (LALR)
● Foreach token or token set
● → Execute a function to generate an AST statement
● → Goto next token
● → Can generate "Parse error" and halt
● Very tied to lexical analyzer
12. 12
Compilation
● Invoked on final AST
● Userland AST: https://github.com/nikic/php-ast
● Creates an OPCodes array
● OPCode = low level VM instruction
● Somehow similar to low level assembly
● Compilation step is very heavy
● Lots of checks and memory accesses
● address resolutions and computations
● many stacks and memory pools
● Some early optimizations/computations are performed
13. 13
Optimization
● Optimizations are done by ext/opcache
● The optimizer is very heavy (in PHP 7)
● Steps are defined in opcache.optimization_level INI setting
#define ZEND_OPTIMIZER_PASS_1 (1<<0) /* CSE, STRING construction */
#define ZEND_OPTIMIZER_PASS_2 (1<<1) /* Constant conversion and jumps */
#define ZEND_OPTIMIZER_PASS_3 (1<<2) /* ++, +=, series of jumps */
#define ZEND_OPTIMIZER_PASS_4 (1<<3) /* INIT_FCALL_BY_NAME -> DO_FCALL */
#define ZEND_OPTIMIZER_PASS_5 (1<<4) /* CFG based optimization */
#define ZEND_OPTIMIZER_PASS_6 (1<<5) /* DFA based optimization */
#define ZEND_OPTIMIZER_PASS_7 (1<<6) /* CALL GRAPH optimization */
#define ZEND_OPTIMIZER_PASS_8 (1<<7) /* SCCP (constant propagation) */
#define ZEND_OPTIMIZER_PASS_9 (1<<8) /* TMP VAR usage */
#define ZEND_OPTIMIZER_PASS_10 (1<<9) /* NOP removal */
#define ZEND_OPTIMIZER_PASS_11 (1<<10) /* Merge equal constants */
#define ZEND_OPTIMIZER_PASS_12 (1<<11) /* Adjust used stack */
#define ZEND_OPTIMIZER_PASS_13 (1<<12) /* Remove unused variables */
#define ZEND_OPTIMIZER_PASS_14 (1<<13) /* DCE (dead code elimination) */
#define ZEND_OPTIMIZER_PASS_15 (1<<14) /* (unsafe) Collect constants */
#define ZEND_OPTIMIZER_PASS_16 (1<<15) /* Inline functions */
17. 17
Execution
● Execute OPCodes
● Most complex part of Zend Engine
● VM executor
● zend_vm_execute.h
● Each OPCode
● is run through a handler() function
● "zend_vm_handler"
● runs the instructions in an infinite dipatch
loop
● Branching possibles (loops, catch blocks,
gotos, etc...)
Startup
Shutdown
zend_compile_file()
zend_execute()
20. 20
Many OPCodes
● OPCodes are low level VM instructions
● Many of them, more and more as PHP evolves
● ~ 200 flavors in PHP 7
● See the list from Zend/zend_vm_opcodes.h
● ZEND_ADD
● ZEND_DECLARE_ANON_CLASS
● ZEND_FE_RESET
● ZEND_ADD_TRAIT
● ZEND_YIELD_FROM
● ...
21. 21
OPCode handlers
● Each OPCode is treated by a handler (a function)
● It takes up to 3 arguments and produces exactly one
result
● Arguments and result are "variable" like you know them
● ZEND_ADD(num1, num2) : result_num
● ZEND_DECLARE_ANON_CLASS(class) : result_bool
● ZEND_FE_RESET(array_or_object) : result
● ZEND_ADD_TRAIT(class, trait) : result_bool
● ZEND_YIELD_FROM(cur_gen, gen_from) : result
24. 24
OPCode Cache
● First time
● Compile
● Cache to SHM or cache file
● Execute
● Then, if file did not change
● Load from SHM or cache file
● Execute
● Compilation is very heavy
● Optimization can be as well
27. 27
CLI
● Even if more and more used, PHP has not been designed
to run in CLI (for long running scripts)
● In long run CLI ("consumers"), the VM never stops
● PHP never stops, thus never reaches its "cleaning memory
step"
● The "current request" memory is then never freed
● Even with GC on, the programmer has to really take care
not to create "memory leaks"
● And for that he has to master how PHP works internally
● Or use a low level memory debugger, like valgrind/massif
● OPCode caches and optimizers are pretty useless to CLI
● Optimization can be worth it
● Compilation prevention is useless as runtime will take a lot
28. 28
JIT ?
● JIT is a complex topic, and coming to PHP 8
● Still under development
● It should accelerate very CPU intensive tasks
● Aka : not web applications, usually
● Until you really treat that many data per request, which
you shouldn't do anyway with PHP.
● But CLI scripts will mainly benefit from JIT (composer ?)
● Take care as it wont accelerate any IO intensive tasks
● And we tend to run some using PHP nowadays
● (Aka "event loops" and things like that)
29. 29
PHP's memory consumption
● Know what you are talking about and what you're doing
● Know your OS and memory allocators
● memory_get_usage(): size used by your runtime code
● memory_get_usage(true): size allocated through the OS
● ZendMM caches blocks
● use gc_mem_caches() to reclaim them if needed
● Use your OS to be accurate
php> echo memory_get_usage();
625272
php> echo memory_get_usage(1);
786432
cat /proc/13399/status
Name:php
State: S (sleeping)
VmPeak: 154440 kB
VmSize: 133700 kB
VmRSS: 10304 kB
VmData: 4316 kB
VmStk: 136 kB
VmExe: 9876 kB
30. 30
A software VM
● PHP internally works the same as
● Java
● Python
● Ruby
● Lua
● [... others ]
● But PHP's VM is not threaded, it runs a monolithic path
● PHP's VM compiler/optimizer/interpreter are merged
into PHP source code
● zend_compile.c
● ext/opcache/Optimizer/zend_optimizer.c
● zend_vm_def.h / zend_execute.c