Upload
nikita-popov
View
9.206
Download
0
Embed Size (px)
Citation preview
PHP 7 releaseNov 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
CPU4ns
L2
256 KB
L1D
1ns 32KB
Memory optimization
• Reduce number of allocations
• Reduce memory usage• Memory access has high latency
CPU L312ns
a few MB4ns
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 MB4ns
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 MB4ns
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 youhave
What youwant
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 youhave
What youwant
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 allocations1 level of indirection
40 bytes
no allocationsno 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 allocations2 levels of indirection
40 bytes
1 allocation1 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 42ASSIGN $b 24ADD $a $b ~2ECHO ~2RETURN 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 42ASSIGN $b 24ADD $a $b ~2ECHO ~2RETURN 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 42ASSIGN $b 24ADD $a $b ~0ECHO ~0RETURN 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 1SEND_VAL 2DO_FCALL foo
RECV $aRECV $bADD $a $b ~0RETURN ~0
{main}
foo()
Virtual machine – stack management (PHP 5)function foo($a, $b) {
return $a + $b;}foo(1, 2);
SEND_VAL 1SEND_VAL 2DO_FCALL foo
RECV $aRECV $bADD $a $b ~0RETURN ~0
{main}
foo()
…
VM stack
Virtual machine – stack management (PHP 5)function foo($a, $b) {
return $a + $b;}foo(1, 2);
SEND_VAL 1SEND_VAL 2DO_FCALL foo
RECV $aRECV $bADD $a $b ~0RETURN ~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 1SEND_VAL 2DO_FCALL foo
RECV $aRECV $bADD $a $b ~0RETURN ~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 1SEND_VAL 2DO_FCALL foo
RECV $aRECV $bADD $a $b ~0RETURN ~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 1SEND_VAL 2DO_FCALL foo
RECV $aRECV $bADD $a $b ~0RETURN ~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 fooSEND_VAL 1SEND_VAL 2DO_FCALL
RECV $aRECV $bADD $a $b ~0RETURN ~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 fooSEND_VAL 1SEND_VAL 2DO_FCALL
RECV $aRECV $bADD $a $b ~0RETURN ~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 fooSEND_VAL 1SEND_VAL 2DO_FCALL
RECV $aRECV $bADD $a $b ~0RETURN ~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 fooSEND_VAL 1SEND_VAL 2DO_FCALL
RECV $aRECV $bADD $a $b ~0RETURN ~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 fooSEND_VAL 1SEND_VAL 2DO_FCALL
RECV $aRECV $bADD $a $b ~0RETURN ~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 foo\strlen()?
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