88

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

Embed Size (px)

Citation preview

Page 1: PHP 7 – What changed internally? (PHP Barcelona 2015)
Page 2: PHP 7 – What changed internally? (PHP Barcelona 2015)

PHP 7 releaseNov 12th

* if everything goes as planned

Page 3: PHP 7 – What changed internally? (PHP Barcelona 2015)

http://hhvm.com/blog/9293/lockdown-results-and-hhvm-performance

Page 4: PHP 7 – What changed internally? (PHP Barcelona 2015)

Memory optimization

Page 5: PHP 7 – What changed internally? (PHP Barcelona 2015)

Memory optimization

• Reduce number of allocations

Page 6: PHP 7 – What changed internally? (PHP Barcelona 2015)

Memory optimization

• Reduce number of allocations

Memory

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

Memory optimization

• Reduce number of allocations• PHP 5 spends 20% of CPU time in the allocator

Memory

Page 8: PHP 7 – What changed internally? (PHP Barcelona 2015)

Memory optimization

• Reduce number of allocations

• Reduce memory usage

Page 9: PHP 7 – What changed internally? (PHP Barcelona 2015)

Memory optimization

• Reduce number of allocations

• Reduce memory usage• Memory access has high latency

Page 10: PHP 7 – What changed internally? (PHP Barcelona 2015)

Memory optimization

• Reduce number of allocations

• Reduce memory usage• Memory access has high latency

CPU

Page 11: PHP 7 – What changed internally? (PHP Barcelona 2015)

Memory optimization

• Reduce number of allocations

• Reduce memory usage• Memory access has high latency

CPU L1D

1ns 32KB

Page 12: PHP 7 – What changed internally? (PHP Barcelona 2015)

Memory optimization

• Reduce number of allocations

• Reduce memory usage• Memory access has high latency

CPU4ns

L2

256 KB

L1D

1ns 32KB

Page 13: PHP 7 – What changed internally? (PHP Barcelona 2015)

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

Page 14: PHP 7 – What changed internally? (PHP Barcelona 2015)

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

Page 15: PHP 7 – What changed internally? (PHP Barcelona 2015)

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

Page 16: PHP 7 – What changed internally? (PHP Barcelona 2015)

Memory optimization

• Reduce number of allocations

• Reduce memory usage

• Reduce indirection

Page 17: PHP 7 – What changed internally? (PHP Barcelona 2015)

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

Page 18: PHP 7 – What changed internally? (PHP Barcelona 2015)

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

Page 19: PHP 7 – What changed internally? (PHP Barcelona 2015)

Zvals: PHP 5

• Zval = Type + Value

value

ty

zval

Page 20: PHP 7 – What changed internally? (PHP Barcelona 2015)

Zvals: PHP 5

• Zval = Type + Value

value

ty

zval

$a = 42;Code:

Page 21: PHP 7 – What changed internally? (PHP Barcelona 2015)

Zvals: PHP 5

• Zval = Type + Value

value = int(42)

ty

zval *zval

$a:

$a = 42;Code:

Page 22: PHP 7 – What changed internally? (PHP Barcelona 2015)

Zvals: PHP 5

• Zval = Type + Value

value (simple):

null, bool, int, float

ty

zval *zval

$a:

$a = 42;Code:

Page 23: PHP 7 – What changed internally? (PHP Barcelona 2015)

Zvals: PHP 5

• Zval = Type + Value

value (complex)

ty

zval *zval

$a:

Complex data structure:string, array, object

$a = [];Code:

Page 24: PHP 7 – What changed internally? (PHP Barcelona 2015)

Zvals: PHP 5

• Zval = Type + Value

value (complex)

ty

zval *zval

$a:

Complex data structure:string, array, object

$a = [];$b = $a;

Code:

Page 25: PHP 7 – What changed internally? (PHP Barcelona 2015)

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:

Page 26: PHP 7 – What changed internally? (PHP Barcelona 2015)

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:

Page 27: PHP 7 – What changed internally? (PHP Barcelona 2015)

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

Page 28: PHP 7 – What changed internally? (PHP Barcelona 2015)

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

Page 29: PHP 7 – What changed internally? (PHP Barcelona 2015)

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

Page 30: PHP 7 – What changed internally? (PHP Barcelona 2015)

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

Page 31: PHP 7 – What changed internally? (PHP Barcelona 2015)

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

Page 32: PHP 7 – What changed internally? (PHP Barcelona 2015)

val (char *)

len (int)

A B C \0

zval value:

PHP 5

Page 33: PHP 7 – What changed internally? (PHP Barcelona 2015)

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

Page 34: PHP 7 – What changed internally? (PHP Barcelona 2015)

[0]: (empty)

[1]: (empty)

[2]: (empty)

[3]: (empty)

hash()

“xyz”

Arrays: PHP 5

Page 35: PHP 7 – What changed internally? (PHP Barcelona 2015)

[0]: (empty)

[1]:

[2]: (empty)

[3]: (empty)

hash()

“xyz”

data

key “xyz”

Arrays: PHP 5

Page 36: PHP 7 – What changed internally? (PHP Barcelona 2015)

[0]: (empty)

[1]:

[2]: (empty)

[3]:

“foo”

data

key “foo”

hash()

“xyz”

data

key “xyz”

Arrays: PHP 5

Page 37: PHP 7 – What changed internally? (PHP Barcelona 2015)

[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

Page 38: PHP 7 – What changed internally? (PHP Barcelona 2015)

[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

Page 39: PHP 7 – What changed internally? (PHP Barcelona 2015)

[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

Page 40: PHP 7 – What changed internally? (PHP Barcelona 2015)

[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

Page 41: PHP 7 – What changed internally? (PHP Barcelona 2015)

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

Page 42: PHP 7 – What changed internally? (PHP Barcelona 2015)

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

Page 43: PHP 7 – What changed internally? (PHP Barcelona 2015)

Immutable arrays

$arrays = [];for ($i = 0; $i < 1000000; ++$i) {

$arrays[] = [1, 2, 3, 4, 5, 6, 7, 8];}

Page 44: PHP 7 – What changed internally? (PHP Barcelona 2015)

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

Page 45: PHP 7 – What changed internally? (PHP Barcelona 2015)

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

Page 46: PHP 7 – What changed internally? (PHP Barcelona 2015)

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

Page 47: PHP 7 – What changed internally? (PHP Barcelona 2015)

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

Page 48: PHP 7 – What changed internally? (PHP Barcelona 2015)

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

Page 49: PHP 7 – What changed internally? (PHP Barcelona 2015)

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

Page 50: PHP 7 – What changed internally? (PHP Barcelona 2015)

Integers

• long zend_long

• 64-bit integers on LLP64 platforms (= Windows)

Page 51: PHP 7 – What changed internally? (PHP Barcelona 2015)

AST

<?php$a = 42;$b = 24;echo $a + $b;

Page 52: PHP 7 – What changed internally? (PHP Barcelona 2015)

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

Page 53: PHP 7 – What changed internally? (PHP Barcelona 2015)

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

Page 54: PHP 7 – What changed internally? (PHP Barcelona 2015)

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

Page 55: PHP 7 – What changed internally? (PHP Barcelona 2015)

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

Page 56: PHP 7 – What changed internally? (PHP Barcelona 2015)

Virtual machine

Page 57: PHP 7 – What changed internally? (PHP Barcelona 2015)

Virtual machine – stack management (PHP 5)function foo($a, $b) {

return $a + $b;}foo(1, 2);

Page 58: PHP 7 – What changed internally? (PHP Barcelona 2015)

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

Page 59: PHP 7 – What changed internally? (PHP Barcelona 2015)

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

Page 60: PHP 7 – What changed internally? (PHP Barcelona 2015)

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]

Page 61: PHP 7 – What changed internally? (PHP Barcelona 2015)

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

Page 62: PHP 7 – What changed internally? (PHP Barcelona 2015)

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

Page 63: PHP 7 – What changed internally? (PHP Barcelona 2015)

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

Page 64: PHP 7 – What changed internally? (PHP Barcelona 2015)

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

Page 65: PHP 7 – What changed internally? (PHP Barcelona 2015)

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

Page 66: PHP 7 – What changed internally? (PHP Barcelona 2015)

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

Page 67: PHP 7 – What changed internally? (PHP Barcelona 2015)

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

Page 68: PHP 7 – What changed internally? (PHP Barcelona 2015)

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

Page 69: PHP 7 – What changed internally? (PHP Barcelona 2015)

Virtual machine – inlined internal functions

• Functions with custom opcodes:• strlen()

• is_*()

• defined()

• call_user_func()

• call_user_func_array()

Page 70: PHP 7 – What changed internally? (PHP Barcelona 2015)

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

Page 71: PHP 7 – What changed internally? (PHP Barcelona 2015)

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()?

Page 72: PHP 7 – What changed internally? (PHP Barcelona 2015)

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()!

Page 73: PHP 7 – What changed internally? (PHP Barcelona 2015)

Virtual machine – global registers

zend_execute_data* execute_data;const zend_op* opline;

Page 74: PHP 7 – What changed internally? (PHP Barcelona 2015)

Virtual machine – global registers

register zend_execute_data* execute_data __asm__("%r14");register const zend_op* opline __asm__("%r15");

Page 75: PHP 7 – What changed internally? (PHP Barcelona 2015)

Virtual machine – global registers

register zend_execute_data* execute_data __asm__("%r14");register const zend_op* opline __asm__("%r15");

• Registers reserved in VM code

Page 76: PHP 7 – What changed internally? (PHP Barcelona 2015)

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

Page 77: PHP 7 – What changed internally? (PHP Barcelona 2015)

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

Page 78: PHP 7 – What changed internally? (PHP Barcelona 2015)

Opcache

Page 79: PHP 7 – What changed internally? (PHP Barcelona 2015)

Opcache

• File cache

Page 80: PHP 7 – What changed internally? (PHP Barcelona 2015)

Opcache

• File cache• Alternative (or addition) to SHM

Page 81: PHP 7 – What changed internally? (PHP Barcelona 2015)

Opcache

• File cache• Alternative (or addition) to SHM

• Shared hosting? PHP restart / cache reset?

Page 82: PHP 7 – What changed internally? (PHP Barcelona 2015)

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

Page 83: PHP 7 – What changed internally? (PHP Barcelona 2015)

Opcache

• Huge Pages

Page 84: PHP 7 – What changed internally? (PHP Barcelona 2015)

Opcache

• Huge Pages• Code segment of PHP binary remapped into huge pages

• Reduces iTLB misses

Page 85: PHP 7 – What changed internally? (PHP Barcelona 2015)

Opcache

• Huge Pages• Code segment of PHP binary remapped into huge pages

• Reduces iTLB misses

CPU L2L1I …

Page 86: PHP 7 – What changed internally? (PHP Barcelona 2015)

Opcache

• Huge Pages• Code segment of PHP binary remapped into huge pages

• Reduces iTLB misses

CPU L2L1I

L1 iTLB 4K

L2 TLB

Page 87: PHP 7 – What changed internally? (PHP Barcelona 2015)

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

Page 88: PHP 7 – What changed internally? (PHP Barcelona 2015)

@nikita_ppv

[email protected]

https://joind.in/talk/view/15865