The Secret of PHP7’s Performance
@Laruence
SELF INTRODUCTION
‣ Author of Yaf, Yar, Yac, Yaconf, Taint Projects
‣ Maintainer of Opcache, Msgpack, PHP-Lua Projects
‣ PHP core developer since 2011
‣ Zend consultant since 2013
‣ PHP7 core developer
‣ Chief software architect at lianjia since 2015
PHP BRIEF INTRO
‣ Created in 1994 by Rasmus Lerdorf
‣ 20+ years programming language
‣ Most popular web service program language
‣ PHP7 is released at 3 Dec 2015
‣ Latest version is PHP7.0.7
PHP7
‣ Improved Performance: PHP 7 is up to twice as fast as PHP 5.6
‣ Significantly reduced memory usage
‣ Abstract syntax tree
‣ Consistent 64-bit support
‣ Improved exception hierarchy
‣ Many fatal errrors converted to exceptions
‣ The null coalescing operator (??)
‣ Return & Scalar type declarations
‣ Anonymous slasses
‣ ….
PHP7
‣ 100 % performance improved in various apps
‣ Which optimization is most responsible?
‣ …………………………………………………..
JUST-IN-TIME COMPILER
‣ Once upon a time
‣ There comes HHVM
‣ Performance really matters
‣ A secret project in Zend
‣ Based on opcache of PHP5.5
‣ Invisible performance change in wordpress
‣ Why?
https://github.com/zendtech/php-src/tree/zend-jit
WORDPRESS PROFILING (PHP5.5)
‣ Wordpress:
‣ Typical PHP real-life application
‣ Callgrind:
‣ 28% CPU time is spent on Zend VM
‣ 25% CPU time is spent on Memory
‣ Top one is _zend_mm_alloct_int
Callgrind result on wordpress home page
WORDPRESS PROFILING (PHP5.5)
‣ We have too many allocations
‣ Thoughts:
‣ _strndup
‣ HashTable
‣ MAKE_STD_ZVAL
__mm_alloc_init callers graph (part)
`MEMORY` IS THE KEY
‣ `Memory` is the bootle-neck(25%)
‣ High memory usage
‣ High cache misses
‣ High TLB misses
‣ High page faults
‣ Too many allocation
‣ More CPU time
‣ Increase iTLB miss
‣ Increase branch-miss
‣ High level memory indirection
‣ Increase cache misses
Cache hierarchy latency
INSPECT ZVAL
‣ Total 24 bytes
‣ Value uses 16 bytes
‣ Thoughts:
‣ Most types use 8 bytes
‣ String uses 12 bytes
‣ Only Object uses 16 bytes
‣ Only a little types are ref
630
BOOL/LONG/DOUBLE/ARRAY/RES
refcount type
0
1
2
is_ref
630
STRING
refcount type
0
1
2
is_ref
LEN
630
OBJECT
refcount type
0
1
2
is_ref
Scalar types
String Object
INSPECT ZVAL
‣ Not only 24 bytes
‣ GC info(for GC): Added 16 bytes
‣ Block info(for MM): Added 8 bytes
‣ Total 48 bytes
‣ Thoughts:
‣ Only array and object need gc info
‣ Block info?
‣ Stack allocating?
‣ New MM?
ZVAL size
630
zvalue_value
refcount type
0
1
2
is_ref
block_info
3
4
PROFILING WP
‣ String is the most used type
‣ Object is only used in 2%
‣ 40% types only used 8 bytes in zval.value
‣ Only 15% types are GC cared
‣ ~10% is reference type
‣ Thoughts:
‣ String needs to be optimized
‣ We don’t needs unified `zval`
‣ Reducing zval’s size should be possible
NULL 2798 4%
Bool 11894 17%
Double 6 ..
Long 4134 6%
Resource 25 ..
Array 8709 13%
Object 1582 2%
String 37564 56%
Types in one WP lifecycle
BRAND NEW ZVAL
‣ Total 16 bytes
‣ Copy instead of refcount for basic types
‣ Refcount is not against zval anymore
‣ External struct is used for complex types
‣ values can not be stored in size_t mem
‣ refcount
‣ gc_info
‣ value flags
ZVAL in PHP7
value
type u2flags
0 8 32 63
BRAND NEW ZVAL
‣ Total 16 bytes
‣ Copy instead of refcount for basic types
‣ Refcount is not against zval anymore
‣ External struct is used for complex types
‣ values can not be stored in size_t mem
‣ refcount
‣ gc_info
‣ value flags
ZVAL in PHP7
value
type u2flags
0 8 32 63
IS_LONG
BRAND NEW ZVAL
‣ Total 16 bytes
‣ Copy instead of refcount for basic types
‣ Refcount is not against zval anymore
‣ External struct is used for complex types
‣ values can not be stored in size_t mem
‣ refcount
‣ gc_info
‣ value flags
ZVAL in PHP7
value
type u2flags
0 8 32 63
IS_LONG Can be kept in 64 bytes?
BRAND NEW ZVAL
‣ Total 16 bytes
‣ Copy instead of refcount for basic types
‣ Refcount is not against zval anymore
‣ External struct is used for complex types
‣ values can not be stored in size_t mem
‣ refcount
‣ gc_info
‣ value flags
ZVAL in PHP7
value
type u2flags
0 8 32 63
IS_LONG
BRAND NEW ZVAL
‣ Total 16 bytes
‣ Copy instead of refcount for basic types
‣ Refcount is not against zval anymore
‣ External struct is used for complex types
‣ values can not be stored in size_t mem
‣ refcount
‣ gc_info
‣ value flags
ZVAL in PHP7
value
type u2flags
0 8 32 63
IS_LONG
BRAND NEW ZVAL
‣ Total 16 bytes
‣ Copy instead of refcount for basic types
‣ Refcount is not against zval anymore
‣ External struct is used for complex types
‣ values can not be stored in size_t mem
‣ refcount
‣ gc_info
‣ value flags
ZVAL in PHP7
value
type u2flags
0 8 32 63
BRAND NEW ZVAL
‣ Total 16 bytes
‣ Copy instead of refcount for basic types
‣ Refcount is not against zval anymore
‣ External struct is used for complex types
‣ values can not be stored in size_t mem
‣ refcount
‣ gc_info
‣ value flags
ZVAL in PHP7
value
type u2flags
0 8 32 63
IS_STRING
BRAND NEW ZVAL
‣ Total 16 bytes
‣ Copy instead of refcount for basic types
‣ Refcount is not against zval anymore
‣ External struct is used for complex types
‣ values can not be stored in size_t mem
‣ refcount
‣ gc_info
‣ value flags
ZVAL in PHP7
value
type u2flags
0 8 32 63
IS_STRING Can be kept in 64 bytes?
BRAND NEW ZVAL
‣ Total 16 bytes
‣ Copy instead of refcount for basic types
‣ Refcount is not against zval anymore
‣ External struct is used for complex types
‣ values can not be stored in size_t mem
‣ refcount
‣ gc_info
‣ value flags
ZVAL in PHP7
value
type u2flags
0 8 32 63
IS_STRING
BRAND NEW ZVAL
‣ Total 16 bytes
‣ Copy instead of refcount for basic types
‣ Refcount is not against zval anymore
‣ External struct is used for complex types
‣ values can not be stored in size_t mem
‣ refcount
‣ gc_info
‣ value flags
ZVAL in PHP7
0 32 6348
IS_STRING/IS_ARRAY/IS_OBJECT/IS_RESROUCE/...
refcount gc_infotype flags
value
type u2flags
0 8 32 63
IS_STRING
BRAND NEW ZVAL
‣ Total 16 bytes
‣ Copy instead of refcount for basic types
‣ Refcount is not against zval anymore
‣ External struct is used for complex types
‣ values can not be stored in size_t mem
‣ refcount
‣ gc_info
‣ value flags
ZVAL in PHP7
0 32 6348
IS_STRING/IS_ARRAY/IS_OBJECT/IS_RESROUCE/...
refcount gc_infotype flags
value
type u2flags
0 8 32 63
IS_STRING
BRAND NEW ZVAL
‣ Total 16 bytes
‣ Copy instead of refcount for basic types
‣ Refcount is not against zval anymore
‣ External struct is used for complex types
‣ values can not be stored in size_t mem
‣ refcount
‣ gc_info
‣ value flags
ZVAL in PHP7
0 32 6348
IS_STRING/IS_ARRAY/IS_OBJECT/IS_RESROUCE/...
refcount gc_infotype flags
value
type u2flags
0 8 32 63
IS_STRING
Address
ZEND STRING
‣ Most used type in real world
‣ PHP5
‣ C string
‣ int length
‣ Hash value needs to be calculated every time
‣ Interned string is distinguished by address
‣ PHP7
‣ Brand new type: zend_string
‣ Size length
‣ Hash value is kept after being calculated
‣ Interned string is distinguished by flags
‣ COW instead of copying
zend_string
0 32 6348
unsigned long hash_value
refcount gc_infotype flags
size_t string_len
char[1] val
INSPECT HASHTABLE
‣ Total 72 bytes
‣ typeof bucket->pData is void **
‣ Thoughts:
‣ In most cases, zval are stored
‣ Reduce memory usage
‣ Reduce memory indirection
‣ pListNext
‣ HashTable -> Bucket
‣ Bucket -> ZVAL ** (void **)
HashTable struct
HashTable
nTableMasknTableSize
0 8 32 63
pInternalPointer
nNumOfElem
nNextFreeElement
Bucket *
pListHead
pListTail
arBuckets
pDestructor
Bucket *
Bucket *
.......
Bucket
hashval
nKeyLength
pDataPtr
pData
pListNext
pListPrev
pNext
pLast
arKey
Bucket
hashval
nKeyLength
pDataPtr
pData(void **)
pListNext
pListPrev
pNext
pLast
arKey
zval
zval**
ZEND ARRAY
‣ Total 56 bytes
‣ Key is zend_string
‣ Less memory indirection
‣ Bucket.val
‣ Bucket.val.zval
‣ Buckets are allocated together
zend_array struct
zend_array
refcounted
0 8 32 63
u
arData
idx
idx
Bucket 0
nTableMask
nNumUsed nNumOfElem
nTableSize InternalPointer
pNextFreeElement
pDestructor
.......
hashval
key
zval
Bucket 1
hashval
key
zval
Bucket 2 ......
ILLUSTRATION PHP5
ILLUSTRATION PHP5
$a = 5
Symbol Table
$azval **
ILLUSTRATION PHP5
$a = 5
Symbol Table
$azval **
ILLUSTRATION PHP5
$a = 5
Symbol Table
$azval **
5
L 0
ILLUSTRATION PHP5
$a = 5
Symbol Table
$azval **
5
L 0
ILLUSTRATION PHP5
$a = 5
ref = 1
Symbol Table
$azval **
5
L 0
ILLUSTRATION PHP5
$a = 5
ref = 1
$b = $a
Symbol Table
$azval **
5
L 0
ILLUSTRATION PHP5
$a = 5
ref = 1
$b = $a
$b
Symbol Table
$azval **
5
L 0
ILLUSTRATION PHP5
$a = 5
ref = 1
$b = $a
$b
Symbol Table
$azval **
5
L 0
ILLUSTRATION PHP5
$a = 5
$b = $a
$b
Symbol Table
$azval **
5
L 0
ILLUSTRATION PHP5
$a = 5
$b = $a
$b
ref = 2
Symbol Table
$azval **
5
L 0
ILLUSTRATION PHP5
$a = 5
$b = $a
$b
ref = 2
$m = “PHP5”
Symbol Table
$azval **
5
L 0
ILLUSTRATION PHP5
$a = 5
$b = $a
$b
ref = 2
$m = “PHP5”
$m
Symbol Table
$azval **
5
L 0
ILLUSTRATION PHP5
$a = 5
$b = $a
$b
ref = 2
$m = “PHP5”
$m
Symbol Table
$azval **
0x7ffff7fd1848
S 0
4
0x7ffff7fd1848
5
L 0
ILLUSTRATION PHP5
$a = 5
$b = $a
$b
ref = 2
$m = “PHP5”
$m
Symbol Table
$azval **
0x7ffff7fd1848
S 0
4
0x7ffff7fd1848
5
L 0
ILLUSTRATION PHP5
$a = 5
$b = $a
$b
ref = 2
$m = “PHP5”
$m
ref = 1
Symbol Table
$azval **
0x7ffff7fd1848
S 0
4
0x7ffff7fd1848
5
L 0
ILLUSTRATION PHP5
$a = 5
$b = $a
$b
ref = 2
$m = “PHP5”
$m
ref = 1
$n = $m
Symbol Table
$azval **
0x7ffff7fd1848
S 0
4
0x7ffff7fd1848
5
L 0
ILLUSTRATION PHP5
$a = 5
$b = $a
$b
ref = 2
$m = “PHP5”
$m
ref = 1
$n = $m
$n
Symbol Table
$azval **
0x7ffff7fd1848
S 0
4
0x7ffff7fd1848
5
L 0
ILLUSTRATION PHP5
$a = 5
$b = $a
$b
ref = 2
$m = “PHP5”
$m
ref = 1
$n = $m
$n
Symbol Table
$azval **
0x7ffff7fd1848
S 0
4
0x7ffff7fd1848
5
L 0
ILLUSTRATION PHP5
$a = 5
$b = $a
$b
ref = 2
$m = “PHP5”
$m
$n = $m
$n
Symbol Table
$azval **
0x7ffff7fd1848
S 0
4
0x7ffff7fd1848
5
L 0
ILLUSTRATION PHP5
$a = 5
$b = $a
$b
ref = 2
$m = “PHP5”
$m
$n = $m
$n
ref = 2
Symbol Table
$azval **
0x7ffff7fd1848
S 0
4
0x7ffff7fd1848
5
L 0
ILLUSTRATION PHP5
$a = 5
$b = $a
$b
ref = 2
$m = “PHP5”
$m
$n = $m
$n
ref = 2
$l = &$n
Symbol Table
$azval **
0x7ffff7fd1848
S 0
4
0x7ffff7fd1848
5
L 0
ILLUSTRATION PHP5
$a = 5
$b = $a
$b
ref = 2
$m = “PHP5”
$m
$n = $m
$n
ref = 2
$l = &$n
$l
Symbol Table
$azval **
0x7ffff7fd1848
S 0
4
0x7ffff7fd1848
5
L 0
ILLUSTRATION PHP5
$a = 5
$b = $a
$b
ref = 2
$m = “PHP5”
$m
$n = $m
$n
ref = 2
$l = &$n
$l
Symbol Table
$azval **
0x7ffff7fd1848
S 0
4
0x7ffff7fd1848
5
L 0
ILLUSTRATION PHP5
$a = 5
$b = $a
$b
ref = 2
$m = “PHP5”
$m
$n = $m
$n
ref = 2
$l = &$n
$l
0x7ffff7fd18e0
S 1
4
0x7ffff7fd18e0
Symbol Table
$azval **
0x7ffff7fd1848
S 0
4
0x7ffff7fd1848
5
L 0
ILLUSTRATION PHP5
$a = 5
$b = $a
$b
ref = 2
$m = “PHP5”
$m
$n = $m
$n
$l = &$n
$l
0x7ffff7fd18e0
S 1
4
0x7ffff7fd18e0
Symbol Table
$azval **
0x7ffff7fd1848
S 0
4
0x7ffff7fd1848
5
L 0
ILLUSTRATION PHP5
$a = 5
$b = $a
$b
ref = 2
$m = “PHP5”
$m
$n = $m
$n
$l = &$n
$l
0x7ffff7fd18e0
S 1
4
0x7ffff7fd18e0
Symbol Table
$azval **
0x7ffff7fd1848
S 0
4
0x7ffff7fd1848
5
L 0
ILLUSTRATION PHP5
$a = 5
$b = $a
$b
ref = 2
$m = “PHP5”
$m
$n = $m
$n
$l = &$n
$l
0x7ffff7fd18e0
S 1
4
0x7ffff7fd18e0
Symbol Table
$azval **
0x7ffff7fd1848
S 0
4
0x7ffff7fd1848
5
L 0
ILLUSTRATION PHP5
$a = 5
$b = $a
$b
ref = 2
$m = “PHP5”
$m
$n = $m
$n
$l = &$n
$l
0x7ffff7fd18e0
S 1
4
0x7ffff7fd18e0
ref = 1
Symbol Table
$azval **
0x7ffff7fd1848
S 0
4
0x7ffff7fd1848
5
L 0
ILLUSTRATION PHP5
$a = 5
$b = $a
$b
ref = 2
$m = “PHP5”
$m
$n = $m
$n
$l = &$n
$l
0x7ffff7fd18e0
S 1
4
0x7ffff7fd18e0
ref = 1 ref = 2
ILLUSTRATION PHP7
ILLUSTRATION PHP7
$a = 7
Symbol Table
$a
7
L
zval
ILLUSTRATION PHP7
$a = 7
Symbol Table
$a
7
L
zval
ILLUSTRATION PHP7
$a = 7
$b = $a
Symbol Table
$a
7
L
zval
ILLUSTRATION PHP7
$a = 7
$b = $a
$b
Symbol Table
$a
7
L
zval
ILLUSTRATION PHP7
$a = 7
$b = $a
$b
7
Symbol Table
$a
7
L
zval
ILLUSTRATION PHP7
$a = 7
$b = $a
$b
7
L
Symbol Table
$a
7
L
zval
ILLUSTRATION PHP7
$a = 7
$b = $a
$b
7
L
$m = “PHP7”
Symbol Table
$a
7
L
zval
ILLUSTRATION PHP7
$a = 7
$b = $a
$b
7
L
$m = “PHP7”
$m
Symbol Table
$a
7
L
zval
ILLUSTRATION PHP7
$a = 7
$b = $a
$b
7
L
$m = “PHP7”
$m
0x7ffff7fd18e0
Symbol Table
$a
7
L
zval
ILLUSTRATION PHP7
$a = 7
$b = $a
$b
7
L
$m = “PHP7”
$m
0x7ffff7fd18e0
S
Symbol Table
$a
7
L
zval
ILLUSTRATION PHP7
$a = 7
$b = $a
$b
7
L
$m = “PHP7”
$m
0x7ffff7fd18e0
S
hash = 3245185675147665086
S
4
'P', 'H', 'P', '0'
0x7ffff7fd18e0
zend_string
Symbol Table
$a
7
L
zval
ILLUSTRATION PHP7
$a = 7
$b = $a
$b
7
L
$m = “PHP7”
$m
0x7ffff7fd18e0
S
hash = 3245185675147665086
S
4
'P', 'H', 'P', '0'
0x7ffff7fd18e0
zend_string
Symbol Table
$a
7
L
zval
ILLUSTRATION PHP7
$a = 7
$b = $a
$b
7
L
$m = “PHP7”
$m
0x7ffff7fd18e0
S
ref=1
hash = 3245185675147665086
S
4
'P', 'H', 'P', '0'
0x7ffff7fd18e0
zend_string
Symbol Table
$a
7
L
zval
ILLUSTRATION PHP7
$a = 7
$b = $a
$b
7
L
$m = “PHP7”
$m
0x7ffff7fd18e0
S
ref=1
$n = $m
hash = 3245185675147665086
S
4
'P', 'H', 'P', '0'
0x7ffff7fd18e0
zend_string
Symbol Table
$a
7
L
zval
ILLUSTRATION PHP7
$a = 7
$b = $a
$b
7
L
$m = “PHP7”
$m
0x7ffff7fd18e0
S
ref=1
$n = $m
$n
hash = 3245185675147665086
S
4
'P', 'H', 'P', '0'
0x7ffff7fd18e0
zend_string
Symbol Table
$a
7
L
zval
ILLUSTRATION PHP7
$a = 7
$b = $a
$b
7
L
$m = “PHP7”
$m
0x7ffff7fd18e0
S
ref=1
$n = $m
$n
0x7ffff7fd18e0
hash = 3245185675147665086
S
4
'P', 'H', 'P', '0'
0x7ffff7fd18e0
zend_string
Symbol Table
$a
7
L
zval
ILLUSTRATION PHP7
$a = 7
$b = $a
$b
7
L
$m = “PHP7”
$m
0x7ffff7fd18e0
S
ref=1
$n = $m
$n
0x7ffff7fd18e0
S
hash = 3245185675147665086
S
4
'P', 'H', 'P', '0'
0x7ffff7fd18e0
zend_string
Symbol Table
$a
7
L
zval
ILLUSTRATION PHP7
$a = 7
$b = $a
$b
7
L
$m = “PHP7”
$m
0x7ffff7fd18e0
S
ref=1
$n = $m
$n
0x7ffff7fd18e0
S
hash = 3245185675147665086
S
4
'P', 'H', 'P', '0'
0x7ffff7fd18e0
zend_string
Symbol Table
$a
7
L
zval
ILLUSTRATION PHP7
$a = 7
$b = $a
$b
7
L
$m = “PHP7”
$m
0x7ffff7fd18e0
S
$n = $m
$n
0x7ffff7fd18e0
S
hash = 3245185675147665086
S
4
'P', 'H', 'P', '0'
0x7ffff7fd18e0
zend_string
Symbol Table
$a
7
L
zval
ILLUSTRATION PHP7
$a = 7
$b = $a
$b
7
L
$m = “PHP7”
$m
0x7ffff7fd18e0
S
$n = $m
$n
0x7ffff7fd18e0
S
ref=2
hash = 3245185675147665086
S
4
'P', 'H', 'P', '0'
0x7ffff7fd18e0
zend_string
Symbol Table
$a
7
L
zval
ILLUSTRATION PHP7
$a = 7
$b = $a
$b
7
L
$m = “PHP7”
$m
0x7ffff7fd18e0
S
$n = $m
$n
0x7ffff7fd18e0
S
ref=2
$l = &$n
hash = 3245185675147665086
S
4
'P', 'H', 'P', '0'
0x7ffff7fd18e0
zend_string
Symbol Table
$a
7
L
zval
ILLUSTRATION PHP7
$a = 7
$b = $a
$b
7
L
$m = “PHP7”
$m
0x7ffff7fd18e0
S
$n = $m
$n
0x7ffff7fd18e0
S
ref=2
$l = &$n
$l
hash = 3245185675147665086
S
4
'P', 'H', 'P', '0'
0x7ffff7fd18e0
zend_string
Symbol Table
$a
7
L
zval
ILLUSTRATION PHP7
$a = 7
$b = $a
$b
7
L
$m = “PHP7”
$m
0x7ffff7fd18e0
S
$n = $m
$n
0x7ffff7fd18e0
S
ref=2
$l = &$n
$l
0x7ffff7fd1000
hash = 3245185675147665086
S
4
'P', 'H', 'P', '0'
0x7ffff7fd18e0
zend_string
Symbol Table
$a
7
L
zval
ILLUSTRATION PHP7
$a = 7
$b = $a
$b
7
L
$m = “PHP7”
$m
0x7ffff7fd18e0
S
$n = $m
$n
0x7ffff7fd18e0
S
ref=2
$l = &$n
$l
0x7ffff7fd1000
R
hash = 3245185675147665086
S
4
'P', 'H', 'P', '0'
0x7ffff7fd18e0
zend_string
Symbol Table
$a
7
L
zval
ILLUSTRATION PHP7
$a = 7
$b = $a
$b
7
L
$m = “PHP7”
$m
0x7ffff7fd18e0
S
$n = $m
$n
0x7ffff7fd18e0
S
ref=2
$l = &$n
$l
0x7ffff7fd1000
R
hash = 3245185675147665086
S
4
'P', 'H', 'P', '0'
0x7ffff7fd18e0
zend_string
R
0x7ffff7fd18e0
S 1
4
zend_reference
Symbol Table
$a
7
L
zval
ILLUSTRATION PHP7
$a = 7
$b = $a
$b
7
L
$m = “PHP7”
$m
0x7ffff7fd18e0
S
$n = $m
$n
0x7ffff7fd18e0
S
ref=2
$l = &$n
$l
0x7ffff7fd1000
R
hash = 3245185675147665086
S
4
'P', 'H', 'P', '0'
0x7ffff7fd18e0
zend_string
R
0x7ffff7fd18e0
S 1
4
zend_reference
Symbol Table
$a
7
L
zval
ILLUSTRATION PHP7
$a = 7
$b = $a
$b
7
L
$m = “PHP7”
$m
0x7ffff7fd18e0
S
$n = $m
$n
0x7ffff7fd18e0
S
ref=2
$l = &$n
$l
0x7ffff7fd1000
R
hash = 3245185675147665086
S
4
'P', 'H', 'P', '0'
0x7ffff7fd18e0
zend_string
R
0x7ffff7fd18e0
S 1
4
zend_reference
Symbol Table
$a
7
L
zval
ILLUSTRATION PHP7
$a = 7
$b = $a
$b
7
L
$m = “PHP7”
$m
0x7ffff7fd18e0
S
$n = $m
$n
0x7ffff7fd18e0
S
ref=2
$l = &$n
$l
0x7ffff7fd1000
R
ref=1
hash = 3245185675147665086
S
4
'P', 'H', 'P', '0'
0x7ffff7fd18e0
zend_string
R
0x7ffff7fd18e0
S 1
4
zend_reference
Symbol Table
$a
7
L
zval
ILLUSTRATION PHP7
$a = 7
$b = $a
$b
7
L
$m = “PHP7”
$m
0x7ffff7fd18e0
S
$n = $m
$n
0x7ffff7fd18e0
ref=2
$l = &$n
$l
0x7ffff7fd1000
R
ref=1
hash = 3245185675147665086
S
4
'P', 'H', 'P', '0'
0x7ffff7fd18e0
zend_string
R
0x7ffff7fd18e0
S 1
4
zend_reference
Symbol Table
$a
7
L
zval
ILLUSTRATION PHP7
$a = 7
$b = $a
$b
7
L
$m = “PHP7”
$m
0x7ffff7fd18e0
S
$n = $m
$n
0x7ffff7fd18e0
ref=2
$l = &$n
$l
0x7ffff7fd1000
R
ref=1
R
hash = 3245185675147665086
S
4
'P', 'H', 'P', '0'
0x7ffff7fd18e0
zend_string
R
0x7ffff7fd18e0
S 1
4
zend_reference
Symbol Table
$a
7
L
zval
ILLUSTRATION PHP7
$a = 7
$b = $a
$b
7
L
$m = “PHP7”
$m
0x7ffff7fd18e0
S
$n = $m
$n
ref=2
$l = &$n
$l
0x7ffff7fd1000
R
ref=1
R
hash = 3245185675147665086
S
4
'P', 'H', 'P', '0'
0x7ffff7fd18e0
zend_string
R
0x7ffff7fd18e0
S 1
4
zend_reference
Symbol Table
$a
7
L
zval
ILLUSTRATION PHP7
$a = 7
$b = $a
$b
7
L
$m = “PHP7”
$m
0x7ffff7fd18e0
S
$n = $m
$n
ref=2
$l = &$n
$l
0x7ffff7fd1000
R
ref=1
R
0x7ffff7fd1000
hash = 3245185675147665086
S
4
'P', 'H', 'P', '0'
0x7ffff7fd18e0
zend_string
R
0x7ffff7fd18e0
S 1
4
zend_reference
Symbol Table
$a
7
L
zval
ILLUSTRATION PHP7
$a = 7
$b = $a
$b
7
L
$m = “PHP7”
$m
0x7ffff7fd18e0
S
$n = $m
$n
ref=2
$l = &$n
$l
0x7ffff7fd1000
R
ref=1
R
0x7ffff7fd1000
hash = 3245185675147665086
S
4
'P', 'H', 'P', '0'
0x7ffff7fd18e0
zend_string
R
0x7ffff7fd18e0
S 1
4
zend_reference
Symbol Table
$a
7
L
zval
ILLUSTRATION PHP7
$a = 7
$b = $a
$b
7
L
$m = “PHP7”
$m
0x7ffff7fd18e0
S
$n = $m
$n
ref=2
$l = &$n
$l
0x7ffff7fd1000
R
ref=1
R
0x7ffff7fd1000
hash = 3245185675147665086
S
4
'P', 'H', 'P', '0'
0x7ffff7fd18e0
zend_string
R
0x7ffff7fd18e0
S 1
4
zend_reference
Symbol Table
$a
7
L
zval
ILLUSTRATION PHP7
$a = 7
$b = $a
$b
7
L
$m = “PHP7”
$m
0x7ffff7fd18e0
S
$n = $m
$n
ref=2
$l = &$n
$l
0x7ffff7fd1000
RR
0x7ffff7fd1000
hash = 3245185675147665086
S
4
'P', 'H', 'P', '0'
0x7ffff7fd18e0
zend_string
R
0x7ffff7fd18e0
S 1
4
zend_reference
Symbol Table
$a
7
L
zval
ILLUSTRATION PHP7
$a = 7
$b = $a
$b
7
L
$m = “PHP7”
$m
0x7ffff7fd18e0
S
$n = $m
$n
ref=2
$l = &$n
$l
0x7ffff7fd1000
R
ref=2
R
0x7ffff7fd1000
ILLUSTRATION PHP5
ILLUSTRATION PHP5
$arr = range(0, 5)
foreach($arr as $val) {
}
ILLUSTRATION PHP5
$arr = range(0, 5)
foreach($arr as $val) {
}
HashTable
78
6
5
Bucket *
pListHead
pListTail
arBuckets
pDestructor
Bucket *
Bucket *
.......
Bucket
0
0
pData
pListNext
arKey = NULL
Bucket
1
0
pData
pListNext
arKey = NULL
Bucket
2
0
pData
pListNext
arKey = NULL
ILLUSTRATION PHP5
$arr = range(0, 5)
foreach($arr as $val) {
}
HashTable
78
6
5
Bucket *
pListHead
pListTail
arBuckets
pDestructor
Bucket *
Bucket *
.......
Bucket
0
0
pData
pListNext
arKey = NULL
Bucket
1
0
pData
pListNext
arKey = NULL
Bucket
2
0
pData
pListNext
arKey = NULL
ILLUSTRATION PHP5
$arr = range(0, 5)
foreach($arr as $val) {
}
HashTable
78
6
5
Bucket *
pListHead
pListTail
arBuckets
pDestructor
Bucket *
Bucket *
.......
Bucket
0
0
pData
pListNext
arKey = NULL
Bucket
1
0
pData
pListNext
arKey = NULL
Bucket
2
0
pData
pListNext
arKey = NULL
ILLUSTRATION PHP5
$arr = range(0, 5)
foreach($arr as $val) {
}
HashTable
78
6
5
Bucket *
pListHead
pListTail
arBuckets
pDestructor
Bucket *
Bucket *
.......
Bucket
0
0
pData
pListNext
arKey = NULL
Bucket
1
0
pData
pListNext
arKey = NULL
Bucket
2
0
pData
pListNext
arKey = NULL
ILLUSTRATION PHP5
$arr = range(0, 5)
foreach($arr as $val) {
}
HashTable
78
6
5
Bucket *
pListHead
pListTail
arBuckets
pDestructor
Bucket *
Bucket *
.......
Bucket
0
0
pData
pListNext
arKey = NULL
Bucket
1
0
pData
pListNext
arKey = NULL
Bucket
2
0
pData
pListNext
arKey = NULL
zval **
ILLUSTRATION PHP5
$arr = range(0, 5)
foreach($arr as $val) {
}
HashTable
78
6
5
Bucket *
pListHead
pListTail
arBuckets
pDestructor
Bucket *
Bucket *
.......
Bucket
0
0
pData
pListNext
arKey = NULL
Bucket
1
0
pData
pListNext
arKey = NULL
Bucket
2
0
pData
pListNext
arKey = NULL
zval **
zval *
ILLUSTRATION PHP5
$arr = range(0, 5)
foreach($arr as $val) {
}
HashTable
78
6
5
Bucket *
pListHead
pListTail
arBuckets
pDestructor
Bucket *
Bucket *
.......
Bucket
0
0
pData
pListNext
arKey = NULL
Bucket
1
0
pData
pListNext
arKey = NULL
Bucket
2
0
pData
pListNext
arKey = NULL
zval **zval *
ILLUSTRATION PHP5
$arr = range(0, 5)
foreach($arr as $val) {
}
HashTable
78
6
5
Bucket *
pListHead
pListTail
arBuckets
pDestructor
Bucket *
Bucket *
.......
Bucket
0
0
pData
pListNext
arKey = NULL
Bucket
1
0
pData
pListNext
arKey = NULL
Bucket
2
0
pData
pListNext
arKey = NULL
zval **zval *
0
ILLUSTRATION PHP5
$arr = range(0, 5)
foreach($arr as $val) {
}
HashTable
78
6
5
Bucket *
pListHead
pListTail
arBuckets
pDestructor
Bucket *
Bucket *
.......
Bucket
0
0
pData
pListNext
arKey = NULL
Bucket
1
0
pData
pListNext
arKey = NULL
Bucket
2
0
pData
pListNext
arKey = NULL
zval **zval *0
ILLUSTRATION PHP5
$arr = range(0, 5)
foreach($arr as $val) {
}
HashTable
78
6
5
Bucket *
pListHead
pListTail
arBuckets
pDestructor
Bucket *
Bucket *
.......
Bucket
0
0
pData
pListNext
arKey = NULL
Bucket
1
0
pData
pListNext
arKey = NULL
Bucket
2
0
pData
pListNext
arKey = NULL
zval **zval *0
ILLUSTRATION PHP5
$arr = range(0, 5)
foreach($arr as $val) {
}
HashTable
78
6
5
Bucket *
pListHead
pListTail
arBuckets
pDestructor
Bucket *
Bucket *
.......
Bucket
0
0
pData
pListNext
arKey = NULL
Bucket
1
0
pData
pListNext
arKey = NULL
Bucket
2
0
pData
pListNext
arKey = NULL
zval **zval *0 zval **
ILLUSTRATION PHP5
$arr = range(0, 5)
foreach($arr as $val) {
}
HashTable
78
6
5
Bucket *
pListHead
pListTail
arBuckets
pDestructor
Bucket *
Bucket *
.......
Bucket
0
0
pData
pListNext
arKey = NULL
Bucket
1
0
pData
pListNext
arKey = NULL
Bucket
2
0
pData
pListNext
arKey = NULL
zval **zval *0 zval **
zval *
ILLUSTRATION PHP5
$arr = range(0, 5)
foreach($arr as $val) {
}
HashTable
78
6
5
Bucket *
pListHead
pListTail
arBuckets
pDestructor
Bucket *
Bucket *
.......
Bucket
0
0
pData
pListNext
arKey = NULL
Bucket
1
0
pData
pListNext
arKey = NULL
Bucket
2
0
pData
pListNext
arKey = NULL
zval **zval *0 zval **zval *
ILLUSTRATION PHP5
$arr = range(0, 5)
foreach($arr as $val) {
}
HashTable
78
6
5
Bucket *
pListHead
pListTail
arBuckets
pDestructor
Bucket *
Bucket *
.......
Bucket
0
0
pData
pListNext
arKey = NULL
Bucket
1
0
pData
pListNext
arKey = NULL
Bucket
2
0
pData
pListNext
arKey = NULL
zval **zval *0 zval **zval *
1
ILLUSTRATION PHP5
$arr = range(0, 5)
foreach($arr as $val) {
}
HashTable
78
6
5
Bucket *
pListHead
pListTail
arBuckets
pDestructor
Bucket *
Bucket *
.......
Bucket
0
0
pData
pListNext
arKey = NULL
Bucket
1
0
pData
pListNext
arKey = NULL
Bucket
2
0
pData
pListNext
arKey = NULL
zval **zval *0 zval **zval *1
ILLUSTRATION PHP5
$arr = range(0, 5)
foreach($arr as $val) {
}
HashTable
78
6
5
Bucket *
pListHead
pListTail
arBuckets
pDestructor
Bucket *
Bucket *
.......
Bucket
0
0
pData
pListNext
arKey = NULL
Bucket
1
0
pData
pListNext
arKey = NULL
Bucket
2
0
pData
pListNext
arKey = NULL
zval **zval *0 zval **zval *1
ILLUSTRATION PHP7
ILLUSTRATION PHP7
$arr = range(0, 7)
foreach($arr as $val) {
}
refcount = 1 0H 0
7NaN
Bucket *arData
8 8
Zend Array
0
zval(0)
L
1
zval(1)
L
2
zval(2)
L
ILLUSTRATION PHP7
$arr = range(0, 7)
foreach($arr as $val) {
}
refcount = 1 0H 0
7NaN
Bucket *arData
8 8
Zend Array
0
zval(0)
L
1
zval(1)
L
2
zval(2)
L
ILLUSTRATION PHP7
$arr = range(0, 7)
foreach($arr as $val) {
}
refcount = 1 0H 0
7NaN
Bucket *arData
8 8
Zend Array
0
zval(0)
L
1
zval(1)
L
2
zval(2)
L
ILLUSTRATION PHP7
$arr = range(0, 7)
foreach($arr as $val) {
}
refcount = 1 0H 0
7NaN
Bucket *arData
8 8
Zend Array
0
zval(0)
L
1
zval(1)
L
2
zval(2)
L
ILLUSTRATION PHP7
$arr = range(0, 7)
foreach($arr as $val) {
}
refcount = 1 0H 0
7NaN
Bucket *arData
8 8
Zend Array
0
zval(0)
L
1
zval(1)
L
2
zval(2)
L
ILLUSTRATION PHP7
$arr = range(0, 7)
foreach($arr as $val) {
}
refcount = 1 0H 0
7NaN
Bucket *arData
8 8
Zend Array
0
zval(0)
L
1
zval(1)
L
2
zval(2)
L
ILLUSTRATION PHP7
$arr = range(0, 7)
foreach($arr as $val) {
}
THERE COMES TROUBLES
THERE COMES TROUBLES
function func() {
$a = 1;
$b = "a";
$$b = 2; //build symbol table
var_dump($a);
}
THERE COMES TROUBLES
function func() {
$a = 1;
$b = "a";
$$b = 2; //build symbol table
var_dump($a);
}
This is not a problem in PHP5
Symbol Table
$a $bzval **
Compiled vars
0($a) "a"($b)
1
L 0
zval **
zval
THERE COMES TROUBLES
function func() {
$a = 1;
$b = "a";
$$b = 2; //build symbol table
var_dump($a);
}
This is not a problem in PHP5
Symbol Table
$a $bzval **
Compiled vars
0($a) "a"($b)
1
L 0
zval **
zval
THERE COMES TROUBLES
function func() {
$a = 1;
$b = "a";
$$b = 2; //build symbol table
var_dump($a);
}
This is not a problem in PHP5
But this is a problem now
THERE COMES TROUBLES
function func() {
$a = 1;
$b = "a";
$$b = 2; //build symbol table
var_dump($a);
}
This is not a problem in PHP5
But this is a problem now
THERE COMES TROUBLES
function func() {
$a = 1;
$b = "a";
$$b = 2; //build symbol table
var_dump($a);
}
This is not a problem in PHP5
But this is a problem now
Symbol Table
$a
1
L
$b
"a"
S
zval
Compiled vars
0($a)
1
L
1($b)
"a"
S
zval
THERE COMES TROUBLES
function func() {
$a = 1;
$b = "a";
$$b = 2; //build symbol table
var_dump($a);
}
This is not a problem in PHP5
But this is a problem now
Symbol Table
$a
1
L
$b
"a"
S
zval
Compiled vars
0($a)
1
L
1($b)
"a"
S
zval
0xfffeee00
THERE COMES TROUBLES
function func() {
$a = 1;
$b = "a";
$$b = 2; //build symbol table
var_dump($a);
}
This is not a problem in PHP5
But this is a problem now
Symbol Table
$a
1
L
$b
"a"
S
zval
Compiled vars
0($a)
1
L
1($b)
"a"
S
zval
0xfffeee00
THERE COMES TROUBLES
function func() {
$a = 1;
$b = "a";
$$b = 2; //build symbol table
var_dump($a);
}
This is not a problem in PHP5
But this is a problem now
Symbol Table
$a
1
L
$b
"a"
S
zval
Compiled vars
0($a)
1
L
1($b)
"a"
S
zval
0xfffeee00
INDIRECT
THERE COMES TROUBLES
function func() {
$a = 1;
$b = "a";
$$b = 2; //build symbol table
var_dump($a);
}
This is not a problem in PHP5
But this is a problem now
Symbol Table
$a
1
L
$b
"a"
S
zval
Compiled vars
0($a)
1
L
1($b)
"a"
S
zval
0xfffeee00
INDIRECT
This is why IS_INDRECT was born
‣ 2M(4M) Page Size
‣ Not swappable
‣ Reduce TLB misses
‣ 64 * 4k = 256K
‣ 8 * 2M = 16M
‣ size php binary(o2) text size ~= 10M
‣ opcache.huge_code_pages(iTLB)
‣ shared memory(dTLB)
‣ regular memory(dTLB)
‣ Hugepage is not always good:
‣ SIGBUS on OOM after fork
‣ Hugepage on NUMA
Huge Pages
Translation Lookaside Buffer
VAddress TLB
0x7fff0100 0xbee100
0x7fffe100 0xbee200
0x7fff0000 0xbee300
VAddress PAddress
L2 TLB
0x7fff0100 0xbee100
0x7fffe100 0xbee200
0x7fff0000 0xbee300
VAddress PAddress
RAM
Page Table
PAddress
MISS MISS
Limited size
>60ns1ns 4ns
Wordpresss homepage 100 runs PHP5.5 iTLB stat PHP7 (with huge_code_page) iTLB stat
‣ New memory manager
‣ Memory is allocated in pages
‣ Pages are fixed sizes in one chunk
‣ Chunk is 2M aligned
‣ Block info is unnecessary anymore:
‣ Chunk = Address & ~(2M - 1)
‣ Page = Address & (2M - 1)
‣ efree_size
‣ Similar size mem are probably allocated nearly
PHP7 MM
PHP7 memory manager
Chunk
Heap
prev
huge_list
main_chunk
free_slot
next
free_pages
free_map
pages
map
Chunk
prev
next
free_pages
free_map
pages
map
FRUN
LRUN
> 3072
SRUN
8
16
24
32
40
...
512
....
3072
Huge
>~2M
0 1 2 29
2M Aligned
‣ Basically
‣ Memory is reduced almost by half
‣ Cache misses is significant reduced
‣ TLB misses is significant reduced
‣ Memory indirection is significant reduced
`MEMORY` IS THE KEY
‣ Zend VM refactor
‣ Supper global registers
‣ Huge Pages
‣ File based opcache
‣ No refcount for scalar types
‣ Function calling convention improved
‣ zvals are always pre-allcocated or allocated in stack(no more MAKE_STD_ZVAL and ALLOC_ZVAL)
‣ Faster string comparing also
‣ New HashTable iteration AP
‣ Array duplication optimization
‣ PGO supported
‣ Reference-counting instead of copying
‣ call_user_function(_array) => ZEND_INIT_USER_CALL
‣ Is_int/string/array/* etc => ZEND_TYPE_CHECK
‣ strlen => ZEND_STRLEN
‣ defined => ZEND+DEFINED
‣ Faster sorting algo
‣ Immutable array
‣ Fast arguments parsing API
‣ Optimized strings concatenation.
‣ ………
‣ ……..
NOT ONLY, BUT ALSO (TL;DR)
PHP7 PROFILING
‣ 100% performance increased
‣ 60% IR reduced
‣ 40% memory usage reduced
‣ 20% branches reduced
‣ 15% iTLB misse reduced
‣ What a great life :)
PHP7 PERFORMANCE NEXT
‣ PHP 7.1
‣ DFA optimization
‣ Type inference
‣ Type specific opcode handlers
‣ Faster static vars binding
‣ Dozens small improvements
‣ 30% performance improvement in bench.php already
‣ Significant performance improvement in reallife application
‣ Alpha will be released in July 2016
Q&A

The secret of PHP7's Performance

  • 1.
    The Secret ofPHP7’s Performance @Laruence
  • 2.
    SELF INTRODUCTION ‣ Authorof Yaf, Yar, Yac, Yaconf, Taint Projects ‣ Maintainer of Opcache, Msgpack, PHP-Lua Projects ‣ PHP core developer since 2011 ‣ Zend consultant since 2013 ‣ PHP7 core developer ‣ Chief software architect at lianjia since 2015
  • 3.
    PHP BRIEF INTRO ‣Created in 1994 by Rasmus Lerdorf ‣ 20+ years programming language ‣ Most popular web service program language ‣ PHP7 is released at 3 Dec 2015 ‣ Latest version is PHP7.0.7
  • 4.
    PHP7 ‣ Improved Performance:PHP 7 is up to twice as fast as PHP 5.6 ‣ Significantly reduced memory usage ‣ Abstract syntax tree ‣ Consistent 64-bit support ‣ Improved exception hierarchy ‣ Many fatal errrors converted to exceptions ‣ The null coalescing operator (??) ‣ Return & Scalar type declarations ‣ Anonymous slasses ‣ ….
  • 5.
    PHP7 ‣ 100 %performance improved in various apps ‣ Which optimization is most responsible? ‣ …………………………………………………..
  • 6.
    JUST-IN-TIME COMPILER ‣ Onceupon a time ‣ There comes HHVM ‣ Performance really matters ‣ A secret project in Zend ‣ Based on opcache of PHP5.5 ‣ Invisible performance change in wordpress ‣ Why? https://github.com/zendtech/php-src/tree/zend-jit
  • 7.
    WORDPRESS PROFILING (PHP5.5) ‣Wordpress: ‣ Typical PHP real-life application ‣ Callgrind: ‣ 28% CPU time is spent on Zend VM ‣ 25% CPU time is spent on Memory ‣ Top one is _zend_mm_alloct_int Callgrind result on wordpress home page
  • 8.
    WORDPRESS PROFILING (PHP5.5) ‣We have too many allocations ‣ Thoughts: ‣ _strndup ‣ HashTable ‣ MAKE_STD_ZVAL __mm_alloc_init callers graph (part)
  • 9.
    `MEMORY` IS THEKEY ‣ `Memory` is the bootle-neck(25%) ‣ High memory usage ‣ High cache misses ‣ High TLB misses ‣ High page faults ‣ Too many allocation ‣ More CPU time ‣ Increase iTLB miss ‣ Increase branch-miss ‣ High level memory indirection ‣ Increase cache misses Cache hierarchy latency
  • 10.
    INSPECT ZVAL ‣ Total24 bytes ‣ Value uses 16 bytes ‣ Thoughts: ‣ Most types use 8 bytes ‣ String uses 12 bytes ‣ Only Object uses 16 bytes ‣ Only a little types are ref 630 BOOL/LONG/DOUBLE/ARRAY/RES refcount type 0 1 2 is_ref 630 STRING refcount type 0 1 2 is_ref LEN 630 OBJECT refcount type 0 1 2 is_ref Scalar types String Object
  • 11.
    INSPECT ZVAL ‣ Notonly 24 bytes ‣ GC info(for GC): Added 16 bytes ‣ Block info(for MM): Added 8 bytes ‣ Total 48 bytes ‣ Thoughts: ‣ Only array and object need gc info ‣ Block info? ‣ Stack allocating? ‣ New MM? ZVAL size 630 zvalue_value refcount type 0 1 2 is_ref block_info 3 4
  • 12.
    PROFILING WP ‣ Stringis the most used type ‣ Object is only used in 2% ‣ 40% types only used 8 bytes in zval.value ‣ Only 15% types are GC cared ‣ ~10% is reference type ‣ Thoughts: ‣ String needs to be optimized ‣ We don’t needs unified `zval` ‣ Reducing zval’s size should be possible NULL 2798 4% Bool 11894 17% Double 6 .. Long 4134 6% Resource 25 .. Array 8709 13% Object 1582 2% String 37564 56% Types in one WP lifecycle
  • 13.
    BRAND NEW ZVAL ‣Total 16 bytes ‣ Copy instead of refcount for basic types ‣ Refcount is not against zval anymore ‣ External struct is used for complex types ‣ values can not be stored in size_t mem ‣ refcount ‣ gc_info ‣ value flags ZVAL in PHP7 value type u2flags 0 8 32 63
  • 14.
    BRAND NEW ZVAL ‣Total 16 bytes ‣ Copy instead of refcount for basic types ‣ Refcount is not against zval anymore ‣ External struct is used for complex types ‣ values can not be stored in size_t mem ‣ refcount ‣ gc_info ‣ value flags ZVAL in PHP7 value type u2flags 0 8 32 63 IS_LONG
  • 15.
    BRAND NEW ZVAL ‣Total 16 bytes ‣ Copy instead of refcount for basic types ‣ Refcount is not against zval anymore ‣ External struct is used for complex types ‣ values can not be stored in size_t mem ‣ refcount ‣ gc_info ‣ value flags ZVAL in PHP7 value type u2flags 0 8 32 63 IS_LONG Can be kept in 64 bytes?
  • 16.
    BRAND NEW ZVAL ‣Total 16 bytes ‣ Copy instead of refcount for basic types ‣ Refcount is not against zval anymore ‣ External struct is used for complex types ‣ values can not be stored in size_t mem ‣ refcount ‣ gc_info ‣ value flags ZVAL in PHP7 value type u2flags 0 8 32 63 IS_LONG
  • 17.
    BRAND NEW ZVAL ‣Total 16 bytes ‣ Copy instead of refcount for basic types ‣ Refcount is not against zval anymore ‣ External struct is used for complex types ‣ values can not be stored in size_t mem ‣ refcount ‣ gc_info ‣ value flags ZVAL in PHP7 value type u2flags 0 8 32 63 IS_LONG
  • 18.
    BRAND NEW ZVAL ‣Total 16 bytes ‣ Copy instead of refcount for basic types ‣ Refcount is not against zval anymore ‣ External struct is used for complex types ‣ values can not be stored in size_t mem ‣ refcount ‣ gc_info ‣ value flags ZVAL in PHP7 value type u2flags 0 8 32 63
  • 19.
    BRAND NEW ZVAL ‣Total 16 bytes ‣ Copy instead of refcount for basic types ‣ Refcount is not against zval anymore ‣ External struct is used for complex types ‣ values can not be stored in size_t mem ‣ refcount ‣ gc_info ‣ value flags ZVAL in PHP7 value type u2flags 0 8 32 63 IS_STRING
  • 20.
    BRAND NEW ZVAL ‣Total 16 bytes ‣ Copy instead of refcount for basic types ‣ Refcount is not against zval anymore ‣ External struct is used for complex types ‣ values can not be stored in size_t mem ‣ refcount ‣ gc_info ‣ value flags ZVAL in PHP7 value type u2flags 0 8 32 63 IS_STRING Can be kept in 64 bytes?
  • 21.
    BRAND NEW ZVAL ‣Total 16 bytes ‣ Copy instead of refcount for basic types ‣ Refcount is not against zval anymore ‣ External struct is used for complex types ‣ values can not be stored in size_t mem ‣ refcount ‣ gc_info ‣ value flags ZVAL in PHP7 value type u2flags 0 8 32 63 IS_STRING
  • 22.
    BRAND NEW ZVAL ‣Total 16 bytes ‣ Copy instead of refcount for basic types ‣ Refcount is not against zval anymore ‣ External struct is used for complex types ‣ values can not be stored in size_t mem ‣ refcount ‣ gc_info ‣ value flags ZVAL in PHP7 0 32 6348 IS_STRING/IS_ARRAY/IS_OBJECT/IS_RESROUCE/... refcount gc_infotype flags value type u2flags 0 8 32 63 IS_STRING
  • 23.
    BRAND NEW ZVAL ‣Total 16 bytes ‣ Copy instead of refcount for basic types ‣ Refcount is not against zval anymore ‣ External struct is used for complex types ‣ values can not be stored in size_t mem ‣ refcount ‣ gc_info ‣ value flags ZVAL in PHP7 0 32 6348 IS_STRING/IS_ARRAY/IS_OBJECT/IS_RESROUCE/... refcount gc_infotype flags value type u2flags 0 8 32 63 IS_STRING
  • 24.
    BRAND NEW ZVAL ‣Total 16 bytes ‣ Copy instead of refcount for basic types ‣ Refcount is not against zval anymore ‣ External struct is used for complex types ‣ values can not be stored in size_t mem ‣ refcount ‣ gc_info ‣ value flags ZVAL in PHP7 0 32 6348 IS_STRING/IS_ARRAY/IS_OBJECT/IS_RESROUCE/... refcount gc_infotype flags value type u2flags 0 8 32 63 IS_STRING Address
  • 25.
    ZEND STRING ‣ Mostused type in real world ‣ PHP5 ‣ C string ‣ int length ‣ Hash value needs to be calculated every time ‣ Interned string is distinguished by address ‣ PHP7 ‣ Brand new type: zend_string ‣ Size length ‣ Hash value is kept after being calculated ‣ Interned string is distinguished by flags ‣ COW instead of copying zend_string 0 32 6348 unsigned long hash_value refcount gc_infotype flags size_t string_len char[1] val
  • 26.
    INSPECT HASHTABLE ‣ Total72 bytes ‣ typeof bucket->pData is void ** ‣ Thoughts: ‣ In most cases, zval are stored ‣ Reduce memory usage ‣ Reduce memory indirection ‣ pListNext ‣ HashTable -> Bucket ‣ Bucket -> ZVAL ** (void **) HashTable struct HashTable nTableMasknTableSize 0 8 32 63 pInternalPointer nNumOfElem nNextFreeElement Bucket * pListHead pListTail arBuckets pDestructor Bucket * Bucket * ....... Bucket hashval nKeyLength pDataPtr pData pListNext pListPrev pNext pLast arKey Bucket hashval nKeyLength pDataPtr pData(void **) pListNext pListPrev pNext pLast arKey zval zval**
  • 27.
    ZEND ARRAY ‣ Total56 bytes ‣ Key is zend_string ‣ Less memory indirection ‣ Bucket.val ‣ Bucket.val.zval ‣ Buckets are allocated together zend_array struct zend_array refcounted 0 8 32 63 u arData idx idx Bucket 0 nTableMask nNumUsed nNumOfElem nTableSize InternalPointer pNextFreeElement pDestructor ....... hashval key zval Bucket 1 hashval key zval Bucket 2 ......
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
    Symbol Table $azval ** 5 L0 ILLUSTRATION PHP5 $a = 5
  • 33.
    Symbol Table $azval ** 5 L0 ILLUSTRATION PHP5 $a = 5 ref = 1
  • 34.
    Symbol Table $azval ** 5 L0 ILLUSTRATION PHP5 $a = 5 ref = 1 $b = $a
  • 35.
    Symbol Table $azval ** 5 L0 ILLUSTRATION PHP5 $a = 5 ref = 1 $b = $a $b
  • 36.
    Symbol Table $azval ** 5 L0 ILLUSTRATION PHP5 $a = 5 ref = 1 $b = $a $b
  • 37.
    Symbol Table $azval ** 5 L0 ILLUSTRATION PHP5 $a = 5 $b = $a $b
  • 38.
    Symbol Table $azval ** 5 L0 ILLUSTRATION PHP5 $a = 5 $b = $a $b ref = 2
  • 39.
    Symbol Table $azval ** 5 L0 ILLUSTRATION PHP5 $a = 5 $b = $a $b ref = 2 $m = “PHP5”
  • 40.
    Symbol Table $azval ** 5 L0 ILLUSTRATION PHP5 $a = 5 $b = $a $b ref = 2 $m = “PHP5” $m
  • 41.
    Symbol Table $azval ** 5 L0 ILLUSTRATION PHP5 $a = 5 $b = $a $b ref = 2 $m = “PHP5” $m
  • 42.
    Symbol Table $azval ** 0x7ffff7fd1848 S0 4 0x7ffff7fd1848 5 L 0 ILLUSTRATION PHP5 $a = 5 $b = $a $b ref = 2 $m = “PHP5” $m
  • 43.
    Symbol Table $azval ** 0x7ffff7fd1848 S0 4 0x7ffff7fd1848 5 L 0 ILLUSTRATION PHP5 $a = 5 $b = $a $b ref = 2 $m = “PHP5” $m ref = 1
  • 44.
    Symbol Table $azval ** 0x7ffff7fd1848 S0 4 0x7ffff7fd1848 5 L 0 ILLUSTRATION PHP5 $a = 5 $b = $a $b ref = 2 $m = “PHP5” $m ref = 1 $n = $m
  • 45.
    Symbol Table $azval ** 0x7ffff7fd1848 S0 4 0x7ffff7fd1848 5 L 0 ILLUSTRATION PHP5 $a = 5 $b = $a $b ref = 2 $m = “PHP5” $m ref = 1 $n = $m $n
  • 46.
    Symbol Table $azval ** 0x7ffff7fd1848 S0 4 0x7ffff7fd1848 5 L 0 ILLUSTRATION PHP5 $a = 5 $b = $a $b ref = 2 $m = “PHP5” $m ref = 1 $n = $m $n
  • 47.
    Symbol Table $azval ** 0x7ffff7fd1848 S0 4 0x7ffff7fd1848 5 L 0 ILLUSTRATION PHP5 $a = 5 $b = $a $b ref = 2 $m = “PHP5” $m $n = $m $n
  • 48.
    Symbol Table $azval ** 0x7ffff7fd1848 S0 4 0x7ffff7fd1848 5 L 0 ILLUSTRATION PHP5 $a = 5 $b = $a $b ref = 2 $m = “PHP5” $m $n = $m $n ref = 2
  • 49.
    Symbol Table $azval ** 0x7ffff7fd1848 S0 4 0x7ffff7fd1848 5 L 0 ILLUSTRATION PHP5 $a = 5 $b = $a $b ref = 2 $m = “PHP5” $m $n = $m $n ref = 2 $l = &$n
  • 50.
    Symbol Table $azval ** 0x7ffff7fd1848 S0 4 0x7ffff7fd1848 5 L 0 ILLUSTRATION PHP5 $a = 5 $b = $a $b ref = 2 $m = “PHP5” $m $n = $m $n ref = 2 $l = &$n $l
  • 51.
    Symbol Table $azval ** 0x7ffff7fd1848 S0 4 0x7ffff7fd1848 5 L 0 ILLUSTRATION PHP5 $a = 5 $b = $a $b ref = 2 $m = “PHP5” $m $n = $m $n ref = 2 $l = &$n $l
  • 52.
    Symbol Table $azval ** 0x7ffff7fd1848 S0 4 0x7ffff7fd1848 5 L 0 ILLUSTRATION PHP5 $a = 5 $b = $a $b ref = 2 $m = “PHP5” $m $n = $m $n ref = 2 $l = &$n $l 0x7ffff7fd18e0 S 1 4 0x7ffff7fd18e0
  • 53.
    Symbol Table $azval ** 0x7ffff7fd1848 S0 4 0x7ffff7fd1848 5 L 0 ILLUSTRATION PHP5 $a = 5 $b = $a $b ref = 2 $m = “PHP5” $m $n = $m $n $l = &$n $l 0x7ffff7fd18e0 S 1 4 0x7ffff7fd18e0
  • 54.
    Symbol Table $azval ** 0x7ffff7fd1848 S0 4 0x7ffff7fd1848 5 L 0 ILLUSTRATION PHP5 $a = 5 $b = $a $b ref = 2 $m = “PHP5” $m $n = $m $n $l = &$n $l 0x7ffff7fd18e0 S 1 4 0x7ffff7fd18e0
  • 55.
    Symbol Table $azval ** 0x7ffff7fd1848 S0 4 0x7ffff7fd1848 5 L 0 ILLUSTRATION PHP5 $a = 5 $b = $a $b ref = 2 $m = “PHP5” $m $n = $m $n $l = &$n $l 0x7ffff7fd18e0 S 1 4 0x7ffff7fd18e0
  • 56.
    Symbol Table $azval ** 0x7ffff7fd1848 S0 4 0x7ffff7fd1848 5 L 0 ILLUSTRATION PHP5 $a = 5 $b = $a $b ref = 2 $m = “PHP5” $m $n = $m $n $l = &$n $l 0x7ffff7fd18e0 S 1 4 0x7ffff7fd18e0 ref = 1
  • 57.
    Symbol Table $azval ** 0x7ffff7fd1848 S0 4 0x7ffff7fd1848 5 L 0 ILLUSTRATION PHP5 $a = 5 $b = $a $b ref = 2 $m = “PHP5” $m $n = $m $n $l = &$n $l 0x7ffff7fd18e0 S 1 4 0x7ffff7fd18e0 ref = 1 ref = 2
  • 58.
  • 59.
  • 60.
  • 61.
  • 62.
  • 63.
  • 64.
  • 65.
    Symbol Table $a 7 L zval ILLUSTRATION PHP7 $a= 7 $b = $a $b 7 L $m = “PHP7”
  • 66.
    Symbol Table $a 7 L zval ILLUSTRATION PHP7 $a= 7 $b = $a $b 7 L $m = “PHP7” $m
  • 67.
    Symbol Table $a 7 L zval ILLUSTRATION PHP7 $a= 7 $b = $a $b 7 L $m = “PHP7” $m 0x7ffff7fd18e0
  • 68.
    Symbol Table $a 7 L zval ILLUSTRATION PHP7 $a= 7 $b = $a $b 7 L $m = “PHP7” $m 0x7ffff7fd18e0 S
  • 69.
    Symbol Table $a 7 L zval ILLUSTRATION PHP7 $a= 7 $b = $a $b 7 L $m = “PHP7” $m 0x7ffff7fd18e0 S
  • 70.
    hash = 3245185675147665086 S 4 'P','H', 'P', '0' 0x7ffff7fd18e0 zend_string Symbol Table $a 7 L zval ILLUSTRATION PHP7 $a = 7 $b = $a $b 7 L $m = “PHP7” $m 0x7ffff7fd18e0 S
  • 71.
    hash = 3245185675147665086 S 4 'P','H', 'P', '0' 0x7ffff7fd18e0 zend_string Symbol Table $a 7 L zval ILLUSTRATION PHP7 $a = 7 $b = $a $b 7 L $m = “PHP7” $m 0x7ffff7fd18e0 S ref=1
  • 72.
    hash = 3245185675147665086 S 4 'P','H', 'P', '0' 0x7ffff7fd18e0 zend_string Symbol Table $a 7 L zval ILLUSTRATION PHP7 $a = 7 $b = $a $b 7 L $m = “PHP7” $m 0x7ffff7fd18e0 S ref=1 $n = $m
  • 73.
    hash = 3245185675147665086 S 4 'P','H', 'P', '0' 0x7ffff7fd18e0 zend_string Symbol Table $a 7 L zval ILLUSTRATION PHP7 $a = 7 $b = $a $b 7 L $m = “PHP7” $m 0x7ffff7fd18e0 S ref=1 $n = $m $n
  • 74.
    hash = 3245185675147665086 S 4 'P','H', 'P', '0' 0x7ffff7fd18e0 zend_string Symbol Table $a 7 L zval ILLUSTRATION PHP7 $a = 7 $b = $a $b 7 L $m = “PHP7” $m 0x7ffff7fd18e0 S ref=1 $n = $m $n 0x7ffff7fd18e0
  • 75.
    hash = 3245185675147665086 S 4 'P','H', 'P', '0' 0x7ffff7fd18e0 zend_string Symbol Table $a 7 L zval ILLUSTRATION PHP7 $a = 7 $b = $a $b 7 L $m = “PHP7” $m 0x7ffff7fd18e0 S ref=1 $n = $m $n 0x7ffff7fd18e0 S
  • 76.
    hash = 3245185675147665086 S 4 'P','H', 'P', '0' 0x7ffff7fd18e0 zend_string Symbol Table $a 7 L zval ILLUSTRATION PHP7 $a = 7 $b = $a $b 7 L $m = “PHP7” $m 0x7ffff7fd18e0 S ref=1 $n = $m $n 0x7ffff7fd18e0 S
  • 77.
    hash = 3245185675147665086 S 4 'P','H', 'P', '0' 0x7ffff7fd18e0 zend_string Symbol Table $a 7 L zval ILLUSTRATION PHP7 $a = 7 $b = $a $b 7 L $m = “PHP7” $m 0x7ffff7fd18e0 S $n = $m $n 0x7ffff7fd18e0 S
  • 78.
    hash = 3245185675147665086 S 4 'P','H', 'P', '0' 0x7ffff7fd18e0 zend_string Symbol Table $a 7 L zval ILLUSTRATION PHP7 $a = 7 $b = $a $b 7 L $m = “PHP7” $m 0x7ffff7fd18e0 S $n = $m $n 0x7ffff7fd18e0 S ref=2
  • 79.
    hash = 3245185675147665086 S 4 'P','H', 'P', '0' 0x7ffff7fd18e0 zend_string Symbol Table $a 7 L zval ILLUSTRATION PHP7 $a = 7 $b = $a $b 7 L $m = “PHP7” $m 0x7ffff7fd18e0 S $n = $m $n 0x7ffff7fd18e0 S ref=2 $l = &$n
  • 80.
    hash = 3245185675147665086 S 4 'P','H', 'P', '0' 0x7ffff7fd18e0 zend_string Symbol Table $a 7 L zval ILLUSTRATION PHP7 $a = 7 $b = $a $b 7 L $m = “PHP7” $m 0x7ffff7fd18e0 S $n = $m $n 0x7ffff7fd18e0 S ref=2 $l = &$n $l
  • 81.
    hash = 3245185675147665086 S 4 'P','H', 'P', '0' 0x7ffff7fd18e0 zend_string Symbol Table $a 7 L zval ILLUSTRATION PHP7 $a = 7 $b = $a $b 7 L $m = “PHP7” $m 0x7ffff7fd18e0 S $n = $m $n 0x7ffff7fd18e0 S ref=2 $l = &$n $l 0x7ffff7fd1000
  • 82.
    hash = 3245185675147665086 S 4 'P','H', 'P', '0' 0x7ffff7fd18e0 zend_string Symbol Table $a 7 L zval ILLUSTRATION PHP7 $a = 7 $b = $a $b 7 L $m = “PHP7” $m 0x7ffff7fd18e0 S $n = $m $n 0x7ffff7fd18e0 S ref=2 $l = &$n $l 0x7ffff7fd1000 R
  • 83.
    hash = 3245185675147665086 S 4 'P','H', 'P', '0' 0x7ffff7fd18e0 zend_string Symbol Table $a 7 L zval ILLUSTRATION PHP7 $a = 7 $b = $a $b 7 L $m = “PHP7” $m 0x7ffff7fd18e0 S $n = $m $n 0x7ffff7fd18e0 S ref=2 $l = &$n $l 0x7ffff7fd1000 R
  • 84.
    hash = 3245185675147665086 S 4 'P','H', 'P', '0' 0x7ffff7fd18e0 zend_string R 0x7ffff7fd18e0 S 1 4 zend_reference Symbol Table $a 7 L zval ILLUSTRATION PHP7 $a = 7 $b = $a $b 7 L $m = “PHP7” $m 0x7ffff7fd18e0 S $n = $m $n 0x7ffff7fd18e0 S ref=2 $l = &$n $l 0x7ffff7fd1000 R
  • 85.
    hash = 3245185675147665086 S 4 'P','H', 'P', '0' 0x7ffff7fd18e0 zend_string R 0x7ffff7fd18e0 S 1 4 zend_reference Symbol Table $a 7 L zval ILLUSTRATION PHP7 $a = 7 $b = $a $b 7 L $m = “PHP7” $m 0x7ffff7fd18e0 S $n = $m $n 0x7ffff7fd18e0 S ref=2 $l = &$n $l 0x7ffff7fd1000 R
  • 86.
    hash = 3245185675147665086 S 4 'P','H', 'P', '0' 0x7ffff7fd18e0 zend_string R 0x7ffff7fd18e0 S 1 4 zend_reference Symbol Table $a 7 L zval ILLUSTRATION PHP7 $a = 7 $b = $a $b 7 L $m = “PHP7” $m 0x7ffff7fd18e0 S $n = $m $n 0x7ffff7fd18e0 S ref=2 $l = &$n $l 0x7ffff7fd1000 R ref=1
  • 87.
    hash = 3245185675147665086 S 4 'P','H', 'P', '0' 0x7ffff7fd18e0 zend_string R 0x7ffff7fd18e0 S 1 4 zend_reference Symbol Table $a 7 L zval ILLUSTRATION PHP7 $a = 7 $b = $a $b 7 L $m = “PHP7” $m 0x7ffff7fd18e0 S $n = $m $n 0x7ffff7fd18e0 ref=2 $l = &$n $l 0x7ffff7fd1000 R ref=1
  • 88.
    hash = 3245185675147665086 S 4 'P','H', 'P', '0' 0x7ffff7fd18e0 zend_string R 0x7ffff7fd18e0 S 1 4 zend_reference Symbol Table $a 7 L zval ILLUSTRATION PHP7 $a = 7 $b = $a $b 7 L $m = “PHP7” $m 0x7ffff7fd18e0 S $n = $m $n 0x7ffff7fd18e0 ref=2 $l = &$n $l 0x7ffff7fd1000 R ref=1 R
  • 89.
    hash = 3245185675147665086 S 4 'P','H', 'P', '0' 0x7ffff7fd18e0 zend_string R 0x7ffff7fd18e0 S 1 4 zend_reference Symbol Table $a 7 L zval ILLUSTRATION PHP7 $a = 7 $b = $a $b 7 L $m = “PHP7” $m 0x7ffff7fd18e0 S $n = $m $n ref=2 $l = &$n $l 0x7ffff7fd1000 R ref=1 R
  • 90.
    hash = 3245185675147665086 S 4 'P','H', 'P', '0' 0x7ffff7fd18e0 zend_string R 0x7ffff7fd18e0 S 1 4 zend_reference Symbol Table $a 7 L zval ILLUSTRATION PHP7 $a = 7 $b = $a $b 7 L $m = “PHP7” $m 0x7ffff7fd18e0 S $n = $m $n ref=2 $l = &$n $l 0x7ffff7fd1000 R ref=1 R 0x7ffff7fd1000
  • 91.
    hash = 3245185675147665086 S 4 'P','H', 'P', '0' 0x7ffff7fd18e0 zend_string R 0x7ffff7fd18e0 S 1 4 zend_reference Symbol Table $a 7 L zval ILLUSTRATION PHP7 $a = 7 $b = $a $b 7 L $m = “PHP7” $m 0x7ffff7fd18e0 S $n = $m $n ref=2 $l = &$n $l 0x7ffff7fd1000 R ref=1 R 0x7ffff7fd1000
  • 92.
    hash = 3245185675147665086 S 4 'P','H', 'P', '0' 0x7ffff7fd18e0 zend_string R 0x7ffff7fd18e0 S 1 4 zend_reference Symbol Table $a 7 L zval ILLUSTRATION PHP7 $a = 7 $b = $a $b 7 L $m = “PHP7” $m 0x7ffff7fd18e0 S $n = $m $n ref=2 $l = &$n $l 0x7ffff7fd1000 R ref=1 R 0x7ffff7fd1000
  • 93.
    hash = 3245185675147665086 S 4 'P','H', 'P', '0' 0x7ffff7fd18e0 zend_string R 0x7ffff7fd18e0 S 1 4 zend_reference Symbol Table $a 7 L zval ILLUSTRATION PHP7 $a = 7 $b = $a $b 7 L $m = “PHP7” $m 0x7ffff7fd18e0 S $n = $m $n ref=2 $l = &$n $l 0x7ffff7fd1000 RR 0x7ffff7fd1000
  • 94.
    hash = 3245185675147665086 S 4 'P','H', 'P', '0' 0x7ffff7fd18e0 zend_string R 0x7ffff7fd18e0 S 1 4 zend_reference Symbol Table $a 7 L zval ILLUSTRATION PHP7 $a = 7 $b = $a $b 7 L $m = “PHP7” $m 0x7ffff7fd18e0 S $n = $m $n ref=2 $l = &$n $l 0x7ffff7fd1000 R ref=2 R 0x7ffff7fd1000
  • 95.
  • 96.
    ILLUSTRATION PHP5 $arr =range(0, 5) foreach($arr as $val) { }
  • 97.
    ILLUSTRATION PHP5 $arr =range(0, 5) foreach($arr as $val) { } HashTable 78 6 5 Bucket * pListHead pListTail arBuckets pDestructor Bucket * Bucket * ....... Bucket 0 0 pData pListNext arKey = NULL Bucket 1 0 pData pListNext arKey = NULL Bucket 2 0 pData pListNext arKey = NULL
  • 98.
    ILLUSTRATION PHP5 $arr =range(0, 5) foreach($arr as $val) { } HashTable 78 6 5 Bucket * pListHead pListTail arBuckets pDestructor Bucket * Bucket * ....... Bucket 0 0 pData pListNext arKey = NULL Bucket 1 0 pData pListNext arKey = NULL Bucket 2 0 pData pListNext arKey = NULL
  • 99.
    ILLUSTRATION PHP5 $arr =range(0, 5) foreach($arr as $val) { } HashTable 78 6 5 Bucket * pListHead pListTail arBuckets pDestructor Bucket * Bucket * ....... Bucket 0 0 pData pListNext arKey = NULL Bucket 1 0 pData pListNext arKey = NULL Bucket 2 0 pData pListNext arKey = NULL
  • 100.
    ILLUSTRATION PHP5 $arr =range(0, 5) foreach($arr as $val) { } HashTable 78 6 5 Bucket * pListHead pListTail arBuckets pDestructor Bucket * Bucket * ....... Bucket 0 0 pData pListNext arKey = NULL Bucket 1 0 pData pListNext arKey = NULL Bucket 2 0 pData pListNext arKey = NULL
  • 101.
    ILLUSTRATION PHP5 $arr =range(0, 5) foreach($arr as $val) { } HashTable 78 6 5 Bucket * pListHead pListTail arBuckets pDestructor Bucket * Bucket * ....... Bucket 0 0 pData pListNext arKey = NULL Bucket 1 0 pData pListNext arKey = NULL Bucket 2 0 pData pListNext arKey = NULL zval **
  • 102.
    ILLUSTRATION PHP5 $arr =range(0, 5) foreach($arr as $val) { } HashTable 78 6 5 Bucket * pListHead pListTail arBuckets pDestructor Bucket * Bucket * ....... Bucket 0 0 pData pListNext arKey = NULL Bucket 1 0 pData pListNext arKey = NULL Bucket 2 0 pData pListNext arKey = NULL zval ** zval *
  • 103.
    ILLUSTRATION PHP5 $arr =range(0, 5) foreach($arr as $val) { } HashTable 78 6 5 Bucket * pListHead pListTail arBuckets pDestructor Bucket * Bucket * ....... Bucket 0 0 pData pListNext arKey = NULL Bucket 1 0 pData pListNext arKey = NULL Bucket 2 0 pData pListNext arKey = NULL zval **zval *
  • 104.
    ILLUSTRATION PHP5 $arr =range(0, 5) foreach($arr as $val) { } HashTable 78 6 5 Bucket * pListHead pListTail arBuckets pDestructor Bucket * Bucket * ....... Bucket 0 0 pData pListNext arKey = NULL Bucket 1 0 pData pListNext arKey = NULL Bucket 2 0 pData pListNext arKey = NULL zval **zval * 0
  • 105.
    ILLUSTRATION PHP5 $arr =range(0, 5) foreach($arr as $val) { } HashTable 78 6 5 Bucket * pListHead pListTail arBuckets pDestructor Bucket * Bucket * ....... Bucket 0 0 pData pListNext arKey = NULL Bucket 1 0 pData pListNext arKey = NULL Bucket 2 0 pData pListNext arKey = NULL zval **zval *0
  • 106.
    ILLUSTRATION PHP5 $arr =range(0, 5) foreach($arr as $val) { } HashTable 78 6 5 Bucket * pListHead pListTail arBuckets pDestructor Bucket * Bucket * ....... Bucket 0 0 pData pListNext arKey = NULL Bucket 1 0 pData pListNext arKey = NULL Bucket 2 0 pData pListNext arKey = NULL zval **zval *0
  • 107.
    ILLUSTRATION PHP5 $arr =range(0, 5) foreach($arr as $val) { } HashTable 78 6 5 Bucket * pListHead pListTail arBuckets pDestructor Bucket * Bucket * ....... Bucket 0 0 pData pListNext arKey = NULL Bucket 1 0 pData pListNext arKey = NULL Bucket 2 0 pData pListNext arKey = NULL zval **zval *0 zval **
  • 108.
    ILLUSTRATION PHP5 $arr =range(0, 5) foreach($arr as $val) { } HashTable 78 6 5 Bucket * pListHead pListTail arBuckets pDestructor Bucket * Bucket * ....... Bucket 0 0 pData pListNext arKey = NULL Bucket 1 0 pData pListNext arKey = NULL Bucket 2 0 pData pListNext arKey = NULL zval **zval *0 zval ** zval *
  • 109.
    ILLUSTRATION PHP5 $arr =range(0, 5) foreach($arr as $val) { } HashTable 78 6 5 Bucket * pListHead pListTail arBuckets pDestructor Bucket * Bucket * ....... Bucket 0 0 pData pListNext arKey = NULL Bucket 1 0 pData pListNext arKey = NULL Bucket 2 0 pData pListNext arKey = NULL zval **zval *0 zval **zval *
  • 110.
    ILLUSTRATION PHP5 $arr =range(0, 5) foreach($arr as $val) { } HashTable 78 6 5 Bucket * pListHead pListTail arBuckets pDestructor Bucket * Bucket * ....... Bucket 0 0 pData pListNext arKey = NULL Bucket 1 0 pData pListNext arKey = NULL Bucket 2 0 pData pListNext arKey = NULL zval **zval *0 zval **zval * 1
  • 111.
    ILLUSTRATION PHP5 $arr =range(0, 5) foreach($arr as $val) { } HashTable 78 6 5 Bucket * pListHead pListTail arBuckets pDestructor Bucket * Bucket * ....... Bucket 0 0 pData pListNext arKey = NULL Bucket 1 0 pData pListNext arKey = NULL Bucket 2 0 pData pListNext arKey = NULL zval **zval *0 zval **zval *1
  • 112.
    ILLUSTRATION PHP5 $arr =range(0, 5) foreach($arr as $val) { } HashTable 78 6 5 Bucket * pListHead pListTail arBuckets pDestructor Bucket * Bucket * ....... Bucket 0 0 pData pListNext arKey = NULL Bucket 1 0 pData pListNext arKey = NULL Bucket 2 0 pData pListNext arKey = NULL zval **zval *0 zval **zval *1
  • 113.
  • 114.
    ILLUSTRATION PHP7 $arr =range(0, 7) foreach($arr as $val) { }
  • 115.
    refcount = 10H 0 7NaN Bucket *arData 8 8 Zend Array 0 zval(0) L 1 zval(1) L 2 zval(2) L ILLUSTRATION PHP7 $arr = range(0, 7) foreach($arr as $val) { }
  • 116.
    refcount = 10H 0 7NaN Bucket *arData 8 8 Zend Array 0 zval(0) L 1 zval(1) L 2 zval(2) L ILLUSTRATION PHP7 $arr = range(0, 7) foreach($arr as $val) { }
  • 117.
    refcount = 10H 0 7NaN Bucket *arData 8 8 Zend Array 0 zval(0) L 1 zval(1) L 2 zval(2) L ILLUSTRATION PHP7 $arr = range(0, 7) foreach($arr as $val) { }
  • 118.
    refcount = 10H 0 7NaN Bucket *arData 8 8 Zend Array 0 zval(0) L 1 zval(1) L 2 zval(2) L ILLUSTRATION PHP7 $arr = range(0, 7) foreach($arr as $val) { }
  • 119.
    refcount = 10H 0 7NaN Bucket *arData 8 8 Zend Array 0 zval(0) L 1 zval(1) L 2 zval(2) L ILLUSTRATION PHP7 $arr = range(0, 7) foreach($arr as $val) { }
  • 120.
    refcount = 10H 0 7NaN Bucket *arData 8 8 Zend Array 0 zval(0) L 1 zval(1) L 2 zval(2) L ILLUSTRATION PHP7 $arr = range(0, 7) foreach($arr as $val) { }
  • 121.
  • 122.
    THERE COMES TROUBLES functionfunc() { $a = 1; $b = "a"; $$b = 2; //build symbol table var_dump($a); }
  • 123.
    THERE COMES TROUBLES functionfunc() { $a = 1; $b = "a"; $$b = 2; //build symbol table var_dump($a); } This is not a problem in PHP5
  • 124.
    Symbol Table $a $bzval** Compiled vars 0($a) "a"($b) 1 L 0 zval ** zval THERE COMES TROUBLES function func() { $a = 1; $b = "a"; $$b = 2; //build symbol table var_dump($a); } This is not a problem in PHP5
  • 125.
    Symbol Table $a $bzval** Compiled vars 0($a) "a"($b) 1 L 0 zval ** zval THERE COMES TROUBLES function func() { $a = 1; $b = "a"; $$b = 2; //build symbol table var_dump($a); } This is not a problem in PHP5 But this is a problem now
  • 126.
    THERE COMES TROUBLES functionfunc() { $a = 1; $b = "a"; $$b = 2; //build symbol table var_dump($a); } This is not a problem in PHP5 But this is a problem now
  • 127.
    THERE COMES TROUBLES functionfunc() { $a = 1; $b = "a"; $$b = 2; //build symbol table var_dump($a); } This is not a problem in PHP5 But this is a problem now Symbol Table $a 1 L $b "a" S zval Compiled vars 0($a) 1 L 1($b) "a" S zval
  • 128.
    THERE COMES TROUBLES functionfunc() { $a = 1; $b = "a"; $$b = 2; //build symbol table var_dump($a); } This is not a problem in PHP5 But this is a problem now Symbol Table $a 1 L $b "a" S zval Compiled vars 0($a) 1 L 1($b) "a" S zval 0xfffeee00
  • 129.
    THERE COMES TROUBLES functionfunc() { $a = 1; $b = "a"; $$b = 2; //build symbol table var_dump($a); } This is not a problem in PHP5 But this is a problem now Symbol Table $a 1 L $b "a" S zval Compiled vars 0($a) 1 L 1($b) "a" S zval 0xfffeee00
  • 130.
    THERE COMES TROUBLES functionfunc() { $a = 1; $b = "a"; $$b = 2; //build symbol table var_dump($a); } This is not a problem in PHP5 But this is a problem now Symbol Table $a 1 L $b "a" S zval Compiled vars 0($a) 1 L 1($b) "a" S zval 0xfffeee00 INDIRECT
  • 131.
    THERE COMES TROUBLES functionfunc() { $a = 1; $b = "a"; $$b = 2; //build symbol table var_dump($a); } This is not a problem in PHP5 But this is a problem now Symbol Table $a 1 L $b "a" S zval Compiled vars 0($a) 1 L 1($b) "a" S zval 0xfffeee00 INDIRECT This is why IS_INDRECT was born
  • 132.
    ‣ 2M(4M) PageSize ‣ Not swappable ‣ Reduce TLB misses ‣ 64 * 4k = 256K ‣ 8 * 2M = 16M ‣ size php binary(o2) text size ~= 10M ‣ opcache.huge_code_pages(iTLB) ‣ shared memory(dTLB) ‣ regular memory(dTLB) ‣ Hugepage is not always good: ‣ SIGBUS on OOM after fork ‣ Hugepage on NUMA Huge Pages Translation Lookaside Buffer VAddress TLB 0x7fff0100 0xbee100 0x7fffe100 0xbee200 0x7fff0000 0xbee300 VAddress PAddress L2 TLB 0x7fff0100 0xbee100 0x7fffe100 0xbee200 0x7fff0000 0xbee300 VAddress PAddress RAM Page Table PAddress MISS MISS Limited size >60ns1ns 4ns Wordpresss homepage 100 runs PHP5.5 iTLB stat PHP7 (with huge_code_page) iTLB stat
  • 133.
    ‣ New memorymanager ‣ Memory is allocated in pages ‣ Pages are fixed sizes in one chunk ‣ Chunk is 2M aligned ‣ Block info is unnecessary anymore: ‣ Chunk = Address & ~(2M - 1) ‣ Page = Address & (2M - 1) ‣ efree_size ‣ Similar size mem are probably allocated nearly PHP7 MM PHP7 memory manager Chunk Heap prev huge_list main_chunk free_slot next free_pages free_map pages map Chunk prev next free_pages free_map pages map FRUN LRUN > 3072 SRUN 8 16 24 32 40 ... 512 .... 3072 Huge >~2M 0 1 2 29 2M Aligned
  • 134.
    ‣ Basically ‣ Memoryis reduced almost by half ‣ Cache misses is significant reduced ‣ TLB misses is significant reduced ‣ Memory indirection is significant reduced `MEMORY` IS THE KEY
  • 135.
    ‣ Zend VMrefactor ‣ Supper global registers ‣ Huge Pages ‣ File based opcache ‣ No refcount for scalar types ‣ Function calling convention improved ‣ zvals are always pre-allcocated or allocated in stack(no more MAKE_STD_ZVAL and ALLOC_ZVAL) ‣ Faster string comparing also ‣ New HashTable iteration AP ‣ Array duplication optimization ‣ PGO supported ‣ Reference-counting instead of copying ‣ call_user_function(_array) => ZEND_INIT_USER_CALL ‣ Is_int/string/array/* etc => ZEND_TYPE_CHECK ‣ strlen => ZEND_STRLEN ‣ defined => ZEND+DEFINED ‣ Faster sorting algo ‣ Immutable array ‣ Fast arguments parsing API ‣ Optimized strings concatenation. ‣ ……… ‣ …….. NOT ONLY, BUT ALSO (TL;DR)
  • 136.
    PHP7 PROFILING ‣ 100%performance increased ‣ 60% IR reduced ‣ 40% memory usage reduced ‣ 20% branches reduced ‣ 15% iTLB misse reduced ‣ What a great life :)
  • 137.
    PHP7 PERFORMANCE NEXT ‣PHP 7.1 ‣ DFA optimization ‣ Type inference ‣ Type specific opcode handlers ‣ Faster static vars binding ‣ Dozens small improvements ‣ 30% performance improvement in bench.php already ‣ Significant performance improvement in reallife application ‣ Alpha will be released in July 2016
  • 138.