PHP 7 release
Nov 12th
* if everything goes as planned
http://hhvm.com/blog/9293/lockdown-results-and-hhvm-performance
Memory optimization
Memory optimization
• Reduce number of allocations
Memory optimization
• Reduce number of allocations
Memory
Memory optimization
• Reduce number of allocations
• PHP 5 spends 20% of CPU time in the allocator
Memory
Memory optimization
• Reduce number of allocations
• Reduce memory usage
Memory optimization
• Reduce number of allocations
• Reduce memory usage
• Memory access has high latency
Memory optimization
• Reduce number of allocations
• Reduce memory usage
• Memory access has high latency
CPU
Memory optimization
• Reduce number of allocations
• Reduce memory usage
• Memory access has high latency
CPU L1D
1ns 32KB
Memory optimization
• Reduce number of allocations
• Reduce memory usage
• Memory access has high latency
CPU
4ns
L2
256 KB
L1D
1ns 32KB
Memory optimization
• Reduce number of allocations
• Reduce memory usage
• Memory access has high latency
CPU L312ns
a few MB
4ns
L2
256 KB
L1D
1ns 32KB
RAM
100ns
Memory optimization
• Reduce number of allocations
• Reduce memory usage
• Memory access has high latency
CPU L312ns
a few MB
4ns
L2
256 KB
L1D
1ns 32KB
RAM
100ns
Memory optimization
• Reduce number of allocations
• Reduce memory usage
• Memory access has high latency
• Less data => more fits into the cache
CPU L312ns
a few MB
4ns
L2
256 KB
L1D
1ns 32KB
Memory optimization
• Reduce number of allocations
• Reduce memory usage
• Reduce indirection
Memory optimization
• Reduce number of allocations
• Reduce memory usage
• Reduce indirection
• Pointer points to pointer pointing to pointer pointing to pointer pointing to
pointer pointing to pointer pointing to what you actually want
What you
have
What you
want
Memory optimization
• Reduce number of allocations
• Reduce memory usage
• Reduce indirection
• Pointer points to pointer pointing to pointer pointing to pointer pointing to
pointer pointing to pointer pointing to what you actually want
• Fewer memory accesses
What you
have
What you
want
Zvals: PHP 5
• Zval = Type + Value
value
ty
zval
Zvals: PHP 5
• Zval = Type + Value
value
ty
zval
$a = 42;Code:
Zvals: PHP 5
• Zval = Type + Value
value = int(42)
ty
zval *
zval
$a:
$a = 42;Code:
Zvals: PHP 5
• Zval = Type + Value
value (simple):
null, bool, int, float
ty
zval *
zval
$a:
$a = 42;Code:
Zvals: PHP 5
• Zval = Type + Value
value (complex)
ty
zval *
zval
$a:
Complex data structure:
string, array, object
$a = [];Code:
Zvals: PHP 5
• Zval = Type + Value
value (complex)
ty
zval *
zval
$a:
Complex data structure:
string, array, object
$a = [];
$b = $a;
Code:
Zvals: PHP 5
• Zval = Type + Value + Refcount
value (complex)
refcount = 1 ty
zval *
zval
$a:
Complex data structure:
string, array, object
$a = [];
$b = $a;
Code:
Zvals: PHP 5
• Zval = Type + Value + Refcount
value (complex)
refcount = 2 ty
zval *
zval
$a:
Complex data structure:
string, array, object
$a = [];
$b = $a;
Code:
zval *$b:
Zvals: PHP 7
• Zval = Type + Value
value (complex)
ty
zval *
zval
$a:
$a = [];
$b = $a;
Code:
zval *$b:
Complex data structure:
string, array, object
refcount = 2
Zvals: PHP 7
• Zval = Type + Value
zval *
zval
$a:
$a = [];
$b = $a;
Code:
zval *$b:
Complex data structure:
string, array, object
refcount = 2
value (complex)
type_info
value (complex)
type_info
value (complex)
type_info
Zvals: PHP 7
• Zval = Type + Value
$a:
Complex data structure:
string, array, object
$b:
refcount = 2
zval
zval
PHP 5 PHP 7
value (simple):
null, bool, int, float
refcount ty
gc_buffer
zval * value (simple): …
type_info
1 allocations
1 level of indirection
40 bytes
no allocations
no indirection
16 bytes
PHP 5 PHP 7
value (complex)
refcount ty
gc_root
zval *
Complex data structure:
string, array, object
value (complex)
type_info
Complex data structure:
string, array, object
refcount gc_info
2 allocations
2 levels of indirection
40 bytes
1 allocation
1 level of indirection
24 bytes
val (char *)
len (int)
A B C 0
zval value:
PHP 5
zend_string *
refcount gc_info
hash
len (size_t)
A B C 0
val (char *)
len (int)
A B C 0
zval value: zval value:
PHP 5 PHP 7
[0]: (empty)
[1]: (empty)
[2]: (empty)
[3]: (empty)
hash()
“xyz”
Arrays: PHP 5
[0]: (empty)
[1]:
[2]: (empty)
[3]: (empty)
hash()
“xyz”
data
key “xyz”
Arrays: PHP 5
[0]: (empty)
[1]:
[2]: (empty)
[3]:
“foo”
data
key “foo”
hash()
“xyz”
data
key “xyz”
Arrays: PHP 5
[0]: (empty)
[1]:
[2]: (empty)
[3]:
“foo”
data
key “foo”
next
data
key “bar”
next = NULL
hash()
“bar”
“xyz”
data
key “xyz”
next = NULL
Arrays: PHP 5
[0]: (empty)
[1]:
[2]: (empty)
[3]:
“foo”
hash()
“bar”
“xyz”
Arrays: PHP 5
head
tail
data
key “foo”
next
data
key “bar”
next = NULL
data
key “xyz”
next = NULL
[0]: (empty)
[1]:
[2]: (empty)
[3]:
“foo”
hash()
“bar”
“xyz”
Arrays: PHP 7
data
key “foo”
next
data
key “bar”
next = NULL
data
key “xyz”
next = NULL
[0]: (empty)
[1]:
[2]: (empty)
[3]:
“foo”
hash()
“bar”
“xyz”
Arrays: PHP 7
data
key “foo”
next
data
key “bar”
next = NULL
data
key “xyz”
next = NULL
Bucket *
uint32_t
PHP 5 without zval PHP 7 with zval
Allocations: 2 + 1 per element 2
Size: 72 + 80 per element 56 + 36 per element
Indirections (lookup): 4 2
Arrays: comparison
PHP 5 without zval PHP 7 with zval
Allocations: 2 + 1 per element 2
Size: 72 + 80 per element 56 + 36 per element
Indirections (lookup): 4 2
PHP 5 w/ unique zvals
2 + 2 per element
72 + 112 per element
4
Arrays: comparison
Immutable arrays
$arrays = [];
for ($i = 0; $i < 1000000; ++$i) {
$arrays[] = [1, 2, 3, 4, 5, 6, 7, 8];
}
Immutable arrays
$arrays = [];
for ($i = 0; $i < 1000000; ++$i) {
$arrays[] = [1, 2, 3, 4, 5, 6, 7, 8];
}
PHP 5
Memory usage 1336 MB
Execution time (create) 0.77 s
Execution time (destroy) 1.45 s
Immutable arrays
$arrays = [];
for ($i = 0; $i < 1000000; ++$i) {
$arrays[] = [1, 2, 3, 4, 5, 6, 7, 8];
}
PHP 5 PHP 7
Memory usage 1336 MB 391 MB
Execution time (create) 0.77 s 0.29 s
Execution time (destroy) 1.45 s 0.05 s
Immutable arrays
$arrays = [];
for ($i = 0; $i < 1000000; ++$i) {
$arrays[] = [1, 2, 3, 4, 5, 6, 7, 8];
}
PHP 5 PHP 7 PHP 7 with opcache
Memory usage 1336 MB 391 MB 32 MB
Execution time (create) 0.77 s 0.29 s 0.03 s
Execution time (destroy) 1.45 s 0.05 s 0.002 s
handle (ID)
handlers
zval value
D V ac
object
dtor()
free_storage()
clone()
handlers
refcount
gc_root
ce
properties
properties_table
guards
[0] (stores $prop1)
[1] (stores $prop2)
[2] (stores $prop3)
zval
zval
zval
object store bucket
Zend object
Objects: PHP 5
zend_object * refcount type_info
handle
ce
handlers
properties
value
type_info
value
type_info
value
type_info
$prop1 zval
$prop2 zval
$prop3 zval
Zend object
Objects:
PHP 7
PHP 5 without zval PHP 7 with zval
Allocations: 2 1
Size: 96 + 8 per element 48 + 16 per element
Indirections (prop val): 4 1
Objects: comparison
Integers
• long  zend_long
• 64-bit integers on LLP64 platforms (= Windows)
AST
<?php
$a = 42;
$b = 24;
echo $a + $b;
AST
<?php
$a = 42;
$b = 24;
echo $a + $b;
<?php T_OPEN_TAG
$a T_VARIABLE
=
42 T_LNUMBER
;
$b T_VARIABLE
=
24 T_LNUMBER
;
echo T_ECHO
$a T_VARIABLE
+
$b T_VARIABLE
;
lex
AST
<?php
$a = 42;
$b = 24;
echo $a + $b;
<?php T_OPEN_TAG
$a T_VARIABLE
=
42 T_LNUMBER
;
$b T_VARIABLE
=
24 T_LNUMBER
;
echo T_ECHO
$a T_VARIABLE
+
$b T_VARIABLE
;
ASSIGN $a 42
ASSIGN $b 24
ADD $a $b ~2
ECHO ~2
RETURN 1
lex
parse + compile
AST
<?php
$a = 42;
$b = 24;
echo $a + $b;
<?php T_OPEN_TAG
$a T_VARIABLE
=
42 T_LNUMBER
;
$b T_VARIABLE
=
24 T_LNUMBER
;
echo T_ECHO
$a T_VARIABLE
+
$b T_VARIABLE
;
ASSIGN $a 42
ASSIGN $b 24
ADD $a $b ~2
ECHO ~2
RETURN 1
lex parse
compile
stmts
assign
var 42
$a
assign
$b
echo
+
$a $b
var 24
AST
<?php
$a = 42;
$b = 24;
echo $a + $b;
<?php T_OPEN_TAG
$a T_VARIABLE
=
42 T_LNUMBER
;
$b T_VARIABLE
=
24 T_LNUMBER
;
echo T_ECHO
$a T_VARIABLE
+
$b T_VARIABLE
;
ASSIGN $a 42
ASSIGN $b 24
ADD $a $b ~0
ECHO ~0
RETURN 1
lex parse
compile
token_get_all()
nikic/php-ast
phpdbg -p
stmts
assign
var 42
$a
assign
$b
echo
+
$a $b
var 24
Virtual machine
Virtual machine – stack management (PHP 5)
function foo($a, $b) {
return $a + $b;
}
foo(1, 2);
Virtual machine – stack management (PHP 5)
function foo($a, $b) {
return $a + $b;
}
foo(1, 2);
SEND_VAL 1
SEND_VAL 2
DO_FCALL foo
RECV $a
RECV $b
ADD $a $b ~0
RETURN ~0
{main}
foo()
Virtual machine – stack management (PHP 5)
function foo($a, $b) {
return $a + $b;
}
foo(1, 2);
SEND_VAL 1
SEND_VAL 2
DO_FCALL foo
RECV $a
RECV $b
ADD $a $b ~0
RETURN ~0
{main}
foo()
…
VM stack
Virtual machine – stack management (PHP 5)
function foo($a, $b) {
return $a + $b;
}
foo(1, 2);
SEND_VAL 1
SEND_VAL 2
DO_FCALL foo
RECV $a
RECV $b
ADD $a $b ~0
RETURN ~0
{main}
foo()
…
int(1)
int(2)
VM stack
arg[0]
arg[1]
Virtual machine – stack management (PHP 5)
function foo($a, $b) {
return $a + $b;
}
foo(1, 2);
SEND_VAL 1
SEND_VAL 2
DO_FCALL foo
RECV $a
RECV $b
ADD $a $b ~0
RETURN ~0
{main}
foo()
…
int(1)
int(2)
execute_data
VM stack
arg[0]
arg[1]
~0
$a
$b
Virtual machine – stack management (PHP 5)
function foo($a, $b) {
return $a + $b;
}
foo(1, 2);
SEND_VAL 1
SEND_VAL 2
DO_FCALL foo
RECV $a
RECV $b
ADD $a $b ~0
RETURN ~0
{main}
foo()
…
int(1)
int(2)
execute_data
int(1)
int(2)
VM stack
arg[0]
arg[1]
~0
$a
$b
Virtual machine – stack management (PHP 5)
function foo($a, $b) {
return $a + $b;
}
foo(1, 2);
SEND_VAL 1
SEND_VAL 2
DO_FCALL foo
RECV $a
RECV $b
ADD $a $b ~0
RETURN ~0
{main}
foo()
…
int(1)
int(2)
int(3)
execute_data
int(1)
int(2)
VM stack
arg[0]
arg[1]
~0
$a
$b
Virtual machine – stack management (PHP 7)
function foo($a, $b) {
return $a + $b;
}
foo(1, 2);
{main}
foo()
…
VM stack
INIT_FCALL foo
SEND_VAL 1
SEND_VAL 2
DO_FCALL
RECV $a
RECV $b
ADD $a $b ~0
RETURN ~0
Virtual machine – stack management (PHP 7)
function foo($a, $b) {
return $a + $b;
}
foo(1, 2);
{main}
foo()
…
execute_data
VM stack
~0
$a
$b
INIT_FCALL foo
SEND_VAL 1
SEND_VAL 2
DO_FCALL
RECV $a
RECV $b
ADD $a $b ~0
RETURN ~0
Virtual machine – stack management (PHP 7)
function foo($a, $b) {
return $a + $b;
}
foo(1, 2);
{main}
foo()
…
execute_data
int(1)
int(2)
VM stack
~0
$a
$b
INIT_FCALL foo
SEND_VAL 1
SEND_VAL 2
DO_FCALL
RECV $a
RECV $b
ADD $a $b ~0
RETURN ~0
Virtual machine – stack management (PHP 7)
function foo($a, $b) {
return $a + $b;
}
foo(1, 2);
{main}
foo()
…
execute_data
int(1)
int(2)
VM stack
~0
$a
$b
INIT_FCALL foo
SEND_VAL 1
SEND_VAL 2
DO_FCALL
RECV $a
RECV $b
ADD $a $b ~0
RETURN ~0
Virtual machine – stack management (PHP 7)
function foo($a, $b) {
return $a + $b;
}
foo(1, 2);
{main}
foo()
…
execute_data
int(1)
int(2)
int(3)
VM stack
~0
$a
$b
INIT_FCALL foo
SEND_VAL 1
SEND_VAL 2
DO_FCALL
RECV $a
RECV $b
ADD $a $b ~0
RETURN ~0
Virtual machine – inlined internal functions
• Functions with custom opcodes:
• strlen()
• is_*()
• defined()
• call_user_func()
• call_user_func_array()
Virtual machine – inlined internal functions
• Functions with custom opcodes:
• strlen()
• is_*()
• defined()
• call_user_func()
• call_user_func_array()
• Only in global scope or for fully qualified calls
namespace foo;
echo strlen($str);
Virtual machine – inlined internal functions
• Functions with custom opcodes:
• strlen()
• is_*()
• defined()
• call_user_func()
• call_user_func_array()
• Only in global scope or for fully qualified calls
namespace foo;
echo strlen($str);
Is this strlen() or foostrlen()?
Virtual machine – inlined internal functions
• Functions with custom opcodes:
• strlen()
• is_*()
• defined()
• call_user_func()
• call_user_func_array()
• Only in global scope or for fully qualified calls
namespace foo;
echo strlen($str);
This is definitely strlen()!
Virtual machine – global registers
zend_execute_data* execute_data;
const zend_op* opline;
Virtual machine – global registers
register zend_execute_data* execute_data __asm__("%r14");
register const zend_op* opline __asm__("%r15");
Virtual machine – global registers
register zend_execute_data* execute_data __asm__("%r14");
register const zend_op* opline __asm__("%r15");
• Registers reserved in VM code
Virtual machine – global registers
register zend_execute_data* execute_data __asm__("%r14");
register const zend_op* opline __asm__("%r15");
• Registers reserved in VM code
• Avoid reloading from executor_globals / execute_data
Virtual machine – global registers
register zend_execute_data* execute_data __asm__("%r14");
register const zend_op* opline __asm__("%r15");
• Registers reserved in VM code
• Avoid reloading from executor_globals / execute_data
• Avoid save/restore during calls
Opcache
Opcache
• File cache
Opcache
• File cache
• Alternative (or addition) to SHM
Opcache
• File cache
• Alternative (or addition) to SHM
• Shared hosting? PHP restart / cache reset?
Opcache
• File cache
• Alternative (or addition) to SHM
• Shared hosting? PHP restart / cache reset?
• Time for 500 sequential WP 4.1 requests
SHM 3 s
File cache 6 s
No cache 24 s
Opcache
• Huge Pages
Opcache
• Huge Pages
• Code segment of PHP binary remapped into huge pages
• Reduces iTLB misses
Opcache
• Huge Pages
• Code segment of PHP binary remapped into huge pages
• Reduces iTLB misses
CPU L2L1I …
Opcache
• Huge Pages
• Code segment of PHP binary remapped into huge pages
• Reduces iTLB misses
CPU L2L1I
L1 iTLB 4K
…
L2 TLB
Opcache
• Huge Pages
• Code segment of PHP binary remapped into huge pages
• Reduces iTLB misses
CPU L2L1I
L1 iTLB 4K L1 iTLB 2M
…
L2 TLB
@nikita_ppv
nikic@php.net
https://joind.in/talk/view/15865

PHP 7 – What changed internally? (PHP Barcelona 2015)

  • 2.
    PHP 7 release Nov12th * if everything goes as planned
  • 3.
  • 4.
  • 5.
    Memory optimization • Reducenumber of allocations
  • 6.
    Memory optimization • Reducenumber of allocations Memory
  • 7.
    Memory optimization • Reducenumber of allocations • PHP 5 spends 20% of CPU time in the allocator Memory
  • 8.
    Memory optimization • Reducenumber of allocations • Reduce memory usage
  • 9.
    Memory optimization • Reducenumber of allocations • Reduce memory usage • Memory access has high latency
  • 10.
    Memory optimization • Reducenumber of allocations • Reduce memory usage • Memory access has high latency CPU
  • 11.
    Memory optimization • Reducenumber of allocations • Reduce memory usage • Memory access has high latency CPU L1D 1ns 32KB
  • 12.
    Memory optimization • Reducenumber of allocations • Reduce memory usage • Memory access has high latency CPU 4ns L2 256 KB L1D 1ns 32KB
  • 13.
    Memory optimization • Reducenumber of allocations • Reduce memory usage • Memory access has high latency CPU L312ns a few MB 4ns L2 256 KB L1D 1ns 32KB
  • 14.
    RAM 100ns Memory optimization • Reducenumber of allocations • Reduce memory usage • Memory access has high latency CPU L312ns a few MB 4ns L2 256 KB L1D 1ns 32KB
  • 15.
    RAM 100ns Memory optimization • Reducenumber of allocations • Reduce memory usage • Memory access has high latency • Less data => more fits into the cache CPU L312ns a few MB 4ns L2 256 KB L1D 1ns 32KB
  • 16.
    Memory optimization • Reducenumber of allocations • Reduce memory usage • Reduce indirection
  • 17.
    Memory optimization • Reducenumber of allocations • Reduce memory usage • Reduce indirection • Pointer points to pointer pointing to pointer pointing to pointer pointing to pointer pointing to pointer pointing to what you actually want What you have What you want
  • 18.
    Memory optimization • Reducenumber of allocations • Reduce memory usage • Reduce indirection • Pointer points to pointer pointing to pointer pointing to pointer pointing to pointer pointing to pointer pointing to what you actually want • Fewer memory accesses What you have What you want
  • 19.
    Zvals: PHP 5 •Zval = Type + Value value ty zval
  • 20.
    Zvals: PHP 5 •Zval = Type + Value value ty zval $a = 42;Code:
  • 21.
    Zvals: PHP 5 •Zval = Type + Value value = int(42) ty zval * zval $a: $a = 42;Code:
  • 22.
    Zvals: PHP 5 •Zval = Type + Value value (simple): null, bool, int, float ty zval * zval $a: $a = 42;Code:
  • 23.
    Zvals: PHP 5 •Zval = Type + Value value (complex) ty zval * zval $a: Complex data structure: string, array, object $a = [];Code:
  • 24.
    Zvals: PHP 5 •Zval = Type + Value value (complex) ty zval * zval $a: Complex data structure: string, array, object $a = []; $b = $a; Code:
  • 25.
    Zvals: PHP 5 •Zval = Type + Value + Refcount value (complex) refcount = 1 ty zval * zval $a: Complex data structure: string, array, object $a = []; $b = $a; Code:
  • 26.
    Zvals: PHP 5 •Zval = Type + Value + Refcount value (complex) refcount = 2 ty zval * zval $a: Complex data structure: string, array, object $a = []; $b = $a; Code: zval *$b:
  • 27.
    Zvals: PHP 7 •Zval = Type + Value value (complex) ty zval * zval $a: $a = []; $b = $a; Code: zval *$b: Complex data structure: string, array, object refcount = 2
  • 28.
    Zvals: PHP 7 •Zval = Type + Value zval * zval $a: $a = []; $b = $a; Code: zval *$b: Complex data structure: string, array, object refcount = 2 value (complex) type_info
  • 29.
    value (complex) type_info value (complex) type_info Zvals:PHP 7 • Zval = Type + Value $a: Complex data structure: string, array, object $b: refcount = 2 zval zval
  • 30.
    PHP 5 PHP7 value (simple): null, bool, int, float refcount ty gc_buffer zval * value (simple): … type_info 1 allocations 1 level of indirection 40 bytes no allocations no indirection 16 bytes
  • 31.
    PHP 5 PHP7 value (complex) refcount ty gc_root zval * Complex data structure: string, array, object value (complex) type_info Complex data structure: string, array, object refcount gc_info 2 allocations 2 levels of indirection 40 bytes 1 allocation 1 level of indirection 24 bytes
  • 32.
    val (char *) len(int) A B C 0 zval value: PHP 5
  • 33.
    zend_string * refcount gc_info hash len(size_t) A B C 0 val (char *) len (int) A B C 0 zval value: zval value: PHP 5 PHP 7
  • 34.
    [0]: (empty) [1]: (empty) [2]:(empty) [3]: (empty) hash() “xyz” Arrays: PHP 5
  • 35.
    [0]: (empty) [1]: [2]: (empty) [3]:(empty) hash() “xyz” data key “xyz” Arrays: PHP 5
  • 36.
    [0]: (empty) [1]: [2]: (empty) [3]: “foo” data key“foo” hash() “xyz” data key “xyz” Arrays: PHP 5
  • 37.
    [0]: (empty) [1]: [2]: (empty) [3]: “foo” data key“foo” next data key “bar” next = NULL hash() “bar” “xyz” data key “xyz” next = NULL Arrays: PHP 5
  • 38.
    [0]: (empty) [1]: [2]: (empty) [3]: “foo” hash() “bar” “xyz” Arrays:PHP 5 head tail data key “foo” next data key “bar” next = NULL data key “xyz” next = NULL
  • 39.
    [0]: (empty) [1]: [2]: (empty) [3]: “foo” hash() “bar” “xyz” Arrays:PHP 7 data key “foo” next data key “bar” next = NULL data key “xyz” next = NULL
  • 40.
    [0]: (empty) [1]: [2]: (empty) [3]: “foo” hash() “bar” “xyz” Arrays:PHP 7 data key “foo” next data key “bar” next = NULL data key “xyz” next = NULL Bucket * uint32_t
  • 41.
    PHP 5 withoutzval PHP 7 with zval Allocations: 2 + 1 per element 2 Size: 72 + 80 per element 56 + 36 per element Indirections (lookup): 4 2 Arrays: comparison
  • 42.
    PHP 5 withoutzval PHP 7 with zval Allocations: 2 + 1 per element 2 Size: 72 + 80 per element 56 + 36 per element Indirections (lookup): 4 2 PHP 5 w/ unique zvals 2 + 2 per element 72 + 112 per element 4 Arrays: comparison
  • 43.
    Immutable arrays $arrays =[]; for ($i = 0; $i < 1000000; ++$i) { $arrays[] = [1, 2, 3, 4, 5, 6, 7, 8]; }
  • 44.
    Immutable arrays $arrays =[]; for ($i = 0; $i < 1000000; ++$i) { $arrays[] = [1, 2, 3, 4, 5, 6, 7, 8]; } PHP 5 Memory usage 1336 MB Execution time (create) 0.77 s Execution time (destroy) 1.45 s
  • 45.
    Immutable arrays $arrays =[]; for ($i = 0; $i < 1000000; ++$i) { $arrays[] = [1, 2, 3, 4, 5, 6, 7, 8]; } PHP 5 PHP 7 Memory usage 1336 MB 391 MB Execution time (create) 0.77 s 0.29 s Execution time (destroy) 1.45 s 0.05 s
  • 46.
    Immutable arrays $arrays =[]; for ($i = 0; $i < 1000000; ++$i) { $arrays[] = [1, 2, 3, 4, 5, 6, 7, 8]; } PHP 5 PHP 7 PHP 7 with opcache Memory usage 1336 MB 391 MB 32 MB Execution time (create) 0.77 s 0.29 s 0.03 s Execution time (destroy) 1.45 s 0.05 s 0.002 s
  • 47.
    handle (ID) handlers zval value DV ac object dtor() free_storage() clone() handlers refcount gc_root ce properties properties_table guards [0] (stores $prop1) [1] (stores $prop2) [2] (stores $prop3) zval zval zval object store bucket Zend object Objects: PHP 5
  • 48.
    zend_object * refcounttype_info handle ce handlers properties value type_info value type_info value type_info $prop1 zval $prop2 zval $prop3 zval Zend object Objects: PHP 7
  • 49.
    PHP 5 withoutzval PHP 7 with zval Allocations: 2 1 Size: 96 + 8 per element 48 + 16 per element Indirections (prop val): 4 1 Objects: comparison
  • 50.
    Integers • long zend_long • 64-bit integers on LLP64 platforms (= Windows)
  • 51.
    AST <?php $a = 42; $b= 24; echo $a + $b;
  • 52.
    AST <?php $a = 42; $b= 24; echo $a + $b; <?php T_OPEN_TAG $a T_VARIABLE = 42 T_LNUMBER ; $b T_VARIABLE = 24 T_LNUMBER ; echo T_ECHO $a T_VARIABLE + $b T_VARIABLE ; lex
  • 53.
    AST <?php $a = 42; $b= 24; echo $a + $b; <?php T_OPEN_TAG $a T_VARIABLE = 42 T_LNUMBER ; $b T_VARIABLE = 24 T_LNUMBER ; echo T_ECHO $a T_VARIABLE + $b T_VARIABLE ; ASSIGN $a 42 ASSIGN $b 24 ADD $a $b ~2 ECHO ~2 RETURN 1 lex parse + compile
  • 54.
    AST <?php $a = 42; $b= 24; echo $a + $b; <?php T_OPEN_TAG $a T_VARIABLE = 42 T_LNUMBER ; $b T_VARIABLE = 24 T_LNUMBER ; echo T_ECHO $a T_VARIABLE + $b T_VARIABLE ; ASSIGN $a 42 ASSIGN $b 24 ADD $a $b ~2 ECHO ~2 RETURN 1 lex parse compile stmts assign var 42 $a assign $b echo + $a $b var 24
  • 55.
    AST <?php $a = 42; $b= 24; echo $a + $b; <?php T_OPEN_TAG $a T_VARIABLE = 42 T_LNUMBER ; $b T_VARIABLE = 24 T_LNUMBER ; echo T_ECHO $a T_VARIABLE + $b T_VARIABLE ; ASSIGN $a 42 ASSIGN $b 24 ADD $a $b ~0 ECHO ~0 RETURN 1 lex parse compile token_get_all() nikic/php-ast phpdbg -p stmts assign var 42 $a assign $b echo + $a $b var 24
  • 56.
  • 57.
    Virtual machine –stack management (PHP 5) function foo($a, $b) { return $a + $b; } foo(1, 2);
  • 58.
    Virtual machine –stack management (PHP 5) function foo($a, $b) { return $a + $b; } foo(1, 2); SEND_VAL 1 SEND_VAL 2 DO_FCALL foo RECV $a RECV $b ADD $a $b ~0 RETURN ~0 {main} foo()
  • 59.
    Virtual machine –stack management (PHP 5) function foo($a, $b) { return $a + $b; } foo(1, 2); SEND_VAL 1 SEND_VAL 2 DO_FCALL foo RECV $a RECV $b ADD $a $b ~0 RETURN ~0 {main} foo() … VM stack
  • 60.
    Virtual machine –stack management (PHP 5) function foo($a, $b) { return $a + $b; } foo(1, 2); SEND_VAL 1 SEND_VAL 2 DO_FCALL foo RECV $a RECV $b ADD $a $b ~0 RETURN ~0 {main} foo() … int(1) int(2) VM stack arg[0] arg[1]
  • 61.
    Virtual machine –stack management (PHP 5) function foo($a, $b) { return $a + $b; } foo(1, 2); SEND_VAL 1 SEND_VAL 2 DO_FCALL foo RECV $a RECV $b ADD $a $b ~0 RETURN ~0 {main} foo() … int(1) int(2) execute_data VM stack arg[0] arg[1] ~0 $a $b
  • 62.
    Virtual machine –stack management (PHP 5) function foo($a, $b) { return $a + $b; } foo(1, 2); SEND_VAL 1 SEND_VAL 2 DO_FCALL foo RECV $a RECV $b ADD $a $b ~0 RETURN ~0 {main} foo() … int(1) int(2) execute_data int(1) int(2) VM stack arg[0] arg[1] ~0 $a $b
  • 63.
    Virtual machine –stack management (PHP 5) function foo($a, $b) { return $a + $b; } foo(1, 2); SEND_VAL 1 SEND_VAL 2 DO_FCALL foo RECV $a RECV $b ADD $a $b ~0 RETURN ~0 {main} foo() … int(1) int(2) int(3) execute_data int(1) int(2) VM stack arg[0] arg[1] ~0 $a $b
  • 64.
    Virtual machine –stack management (PHP 7) function foo($a, $b) { return $a + $b; } foo(1, 2); {main} foo() … VM stack INIT_FCALL foo SEND_VAL 1 SEND_VAL 2 DO_FCALL RECV $a RECV $b ADD $a $b ~0 RETURN ~0
  • 65.
    Virtual machine –stack management (PHP 7) function foo($a, $b) { return $a + $b; } foo(1, 2); {main} foo() … execute_data VM stack ~0 $a $b INIT_FCALL foo SEND_VAL 1 SEND_VAL 2 DO_FCALL RECV $a RECV $b ADD $a $b ~0 RETURN ~0
  • 66.
    Virtual machine –stack management (PHP 7) function foo($a, $b) { return $a + $b; } foo(1, 2); {main} foo() … execute_data int(1) int(2) VM stack ~0 $a $b INIT_FCALL foo SEND_VAL 1 SEND_VAL 2 DO_FCALL RECV $a RECV $b ADD $a $b ~0 RETURN ~0
  • 67.
    Virtual machine –stack management (PHP 7) function foo($a, $b) { return $a + $b; } foo(1, 2); {main} foo() … execute_data int(1) int(2) VM stack ~0 $a $b INIT_FCALL foo SEND_VAL 1 SEND_VAL 2 DO_FCALL RECV $a RECV $b ADD $a $b ~0 RETURN ~0
  • 68.
    Virtual machine –stack management (PHP 7) function foo($a, $b) { return $a + $b; } foo(1, 2); {main} foo() … execute_data int(1) int(2) int(3) VM stack ~0 $a $b INIT_FCALL foo SEND_VAL 1 SEND_VAL 2 DO_FCALL RECV $a RECV $b ADD $a $b ~0 RETURN ~0
  • 69.
    Virtual machine –inlined internal functions • Functions with custom opcodes: • strlen() • is_*() • defined() • call_user_func() • call_user_func_array()
  • 70.
    Virtual machine –inlined internal functions • Functions with custom opcodes: • strlen() • is_*() • defined() • call_user_func() • call_user_func_array() • Only in global scope or for fully qualified calls namespace foo; echo strlen($str);
  • 71.
    Virtual machine –inlined internal functions • Functions with custom opcodes: • strlen() • is_*() • defined() • call_user_func() • call_user_func_array() • Only in global scope or for fully qualified calls namespace foo; echo strlen($str); Is this strlen() or foostrlen()?
  • 72.
    Virtual machine –inlined internal functions • Functions with custom opcodes: • strlen() • is_*() • defined() • call_user_func() • call_user_func_array() • Only in global scope or for fully qualified calls namespace foo; echo strlen($str); This is definitely strlen()!
  • 73.
    Virtual machine –global registers zend_execute_data* execute_data; const zend_op* opline;
  • 74.
    Virtual machine –global registers register zend_execute_data* execute_data __asm__("%r14"); register const zend_op* opline __asm__("%r15");
  • 75.
    Virtual machine –global registers register zend_execute_data* execute_data __asm__("%r14"); register const zend_op* opline __asm__("%r15"); • Registers reserved in VM code
  • 76.
    Virtual machine –global registers register zend_execute_data* execute_data __asm__("%r14"); register const zend_op* opline __asm__("%r15"); • Registers reserved in VM code • Avoid reloading from executor_globals / execute_data
  • 77.
    Virtual machine –global registers register zend_execute_data* execute_data __asm__("%r14"); register const zend_op* opline __asm__("%r15"); • Registers reserved in VM code • Avoid reloading from executor_globals / execute_data • Avoid save/restore during calls
  • 78.
  • 79.
  • 80.
    Opcache • File cache •Alternative (or addition) to SHM
  • 81.
    Opcache • File cache •Alternative (or addition) to SHM • Shared hosting? PHP restart / cache reset?
  • 82.
    Opcache • File cache •Alternative (or addition) to SHM • Shared hosting? PHP restart / cache reset? • Time for 500 sequential WP 4.1 requests SHM 3 s File cache 6 s No cache 24 s
  • 83.
  • 84.
    Opcache • Huge Pages •Code segment of PHP binary remapped into huge pages • Reduces iTLB misses
  • 85.
    Opcache • Huge Pages •Code segment of PHP binary remapped into huge pages • Reduces iTLB misses CPU L2L1I …
  • 86.
    Opcache • Huge Pages •Code segment of PHP binary remapped into huge pages • Reduces iTLB misses CPU L2L1I L1 iTLB 4K … L2 TLB
  • 87.
    Opcache • Huge Pages •Code segment of PHP binary remapped into huge pages • Reduces iTLB misses CPU L2L1I L1 iTLB 4K L1 iTLB 2M … L2 TLB
  • 88.