Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.
Performances
considerations
with PHP 7
Hi
 Julien PAULI
 SensioLabs tech team (Blackfire - PHP)
 Programming with PHP since early 2000s
 Today working as Uni...
What we'll cover together
 PHP 7 new engine design
 What has changed inside PHP from PHP 5 ?
 PHP 7 new compiler
 Comp...
The PHP language
 Born in 1995
 Fully written using the C language
 Today
 822,000 C lines of code
 dozens of contrib...
PHP VERSIONS SURVEY
PHP code compilation
PHP 7 new compiler
 PHP 7 compiler is now based on an AST
 It has been fully rewritten, and can compute much
more things...
PHP 7 optimized compiled functions
namespace Foo;
class Bar
{
public function hello($str)
{
return "Hello" . strlen($str);...
PHP 7 optimized compiled functions
namespace Foo;
class Bar
{
public function hello($str)
{
return "Hello" . strlen($str);...
Namespaced function calls
 We have proven that the performance difference is
really tiny on real use cases.
namespace Foo...
PHP 7 optimized compiled functions
$b = 'foo';
echo strlen($b);
L3 #0 ASSIGN $b "foo"
L5 #1 STRLEN $b ~1
L5 #2 ECHO ~1
ech...
PHP 7 new compiler
 PHP 7 compiler is usually slower than PHP 5's
 It optimizes more things
 It must walk an AST
 It i...
PHP 7 compiler optim example, static arrays
 Arrays containg keys/vals that are static/litteral
 Such arrays are fully r...
Static arrays in PHP 5
 A lot of runtime is eaten to construct the same
array again and again
$a = ['bar', 'baz', 'foo', ...
Static arrays in PHP 7
 No runtime impact (but compile-time)
 You'd better use OPCache
$a = ['bar', 'baz', 'foo', 34, [4...
PHP 7 new references mechanism
 In PHP 5, ref mismatching a function call triggered a
full zval copy the engine
 In PHP ...
PHP 7 new references mechanism
 In PHP 7, the deep copy is postponed until COW
breakage
 If no COW breakage, then no cop...
PHP 7 optimizations
from internal
Optimizing CPU time
 Latency Numbers Every Programmer Should Know
 http://lwn.net/Articles/250967/
 http://www.eecs.ber...
Optimizing CPU cache efficiency
 If we can reduce payload size, the CPU will use its
caches more often
 CPU caches prefe...
PHP 7 cache efficiency
 If we can reduce payload size, the CPU will use its
caches more often
PHP 7.1.4-dev (debug)
128,8...
PHP 7 optimizations
 Every variable in PHP is coded on a zval struct
 This struct has been reorganized in PHP 7
 Narrow...
PHP 5 variables
value
refcount is_ref
type
gc_info
dval
str_val* str_len
hashtable*
object*
lval
ast*
zval
zval_value
...
...
PHP 7 variables
value
type
internal_int
dval
zend_string*
object*
lval
...
zval
zval_value
...
...
HashTable
16 bytes
$a
z...
PHP 5 vs PHP 7 variable design
 zval container no longer stores GC infos
 No more need to heap allocate a zval *
 Very ...
New Memory Allocator
 PHP 7 has a fully new heap memory allocator
 Zend Memory Manager
 It now uses several allocator p...
PHP 7 new hashtables
PHP 7 hashtables
 It has been fully rewritten, and reworked
 Nothing to say from PHP userland POV
 Except perhaps for t...
Packed arrays
Packed arrays
 If your keys are integer only (no string key)
 If your keys are constantly increasing
 No matter if they...
Packed arrays example
const N = 1024 * 1023;
for ($i=0; $i<N; $i++) {
$tab[] = random_bytes(3);
}
echo memory_get_usage();...
Packed arrays conditions (recalled)
 Do NOT use string keys
 Always use increasing integer-based keys
 Contiguous or no...
HashTables in PHP 5
 Each element needs
 4 pointer indirections
 72 bytes for a bucket + 32 bytes for a zval
zval
zval ...
HashTables in PHP 7
 Each element needs
 2 pointer indirections
 32 bytes for a bucket
zval
bucket
HashTable
$a
zval
Ha...
HashTables in PHP 7 : go further
 http://jpauli.github.io/2016/04/08/hashtables.html
Strings
$a = "bar";
String management
 In PHP 5, strings don't have their own structure
 String management is hard
 Leads to many strings d...
Strings in PHP
char * str
...
zval
gc_infos
int len
refcount is_ref zend_string *
...
zval
...
hash
gc_infos
char str[1]si...
Strings in PHP 5
 $a = "foo";
3 0X00007FFFF7F8C708
foo0
Strings in PHP 7
 $a = "foo";
foo0
C struct hack
3
memory border
Strings tip
 Don't forget to use OPCache
 OPCache shares interned strings buffer between
processes
 Don't forget to siz...
Encapsed strings
Encapsed string optimisation
 Encapsed string are double-quoted strings that get
parsed
 They need to be analyzed for va...
Encapsed string in PHP 5
$a = "foo and $b and $c";
3 0 E > ADD_STRING ~0 'foo+and+'
1 ADD_VAR ~0 ~0, !1
2 ADD_STRING ~0 ~0...
Encapsed string optimisation in PHP 7
 PHP 7 uses a "rope", and only reallocates memory
once, at the end
 https://en.wik...
Encapsed strings in PHP 7
$a = "foo and $b and $c";
L3 #0 ROPE_INIT "foo and " ~1
L3 #1 ROPE_ADD ~1 $b ~1
L3 #2 ROPE_ADD ~...
So ?
 So you'd better use encapsed strings
 Than concatenations
$a = "foo and $b and $c";
$a = 'foo and ' . $b . ' and '...
Future ?
Future of PHP
 PHP 7 branch keeps optimizing things
 PHP 7 branch keep preparing the massive JIT engine
move that should...
Happy PHP 7 ing
Thank you for listening
Upcoming SlideShare
Loading in …5
×

Symfony live 2017_php7_performances

1,085 views

Published on

Symfony live 2017_php7_performances

Published in: Internet
  • Hey guys! Who wants to chat with me? More photos with me here 👉 http://www.bit.ly/katekoxx
       Reply 
    Are you sure you want to  Yes  No
    Your message goes here
  • J'ai été vraiment impréssionné par votre maitrise. Votre présentation à la Symfony Live Paris était vraiment géniale quand on souhaite découvrir ce que PHP cache sous son capot.
       Reply 
    Are you sure you want to  Yes  No
    Your message goes here

Symfony live 2017_php7_performances

  1. 1. Performances considerations with PHP 7
  2. 2. Hi  Julien PAULI  SensioLabs tech team (Blackfire - PHP)  Programming with PHP since early 2000s  Today working as Unix system programmer (C)  PHP Internals programmer/contributor  PHP 5.5 & 5.6 Release Manager  @julienpauli  Tech blog at http://jpauli.github.io  jpauli@php.net
  3. 3. What we'll cover together  PHP 7 new engine design  What has changed inside PHP from PHP 5 ?  PHP 7 new compiler  Compiler optimizations  PHP 7 new references mechanism  PHP 7 new Hashtables (PHP arrays)  PHP 7 new strings management
  4. 4. The PHP language  Born in 1995  Fully written using the C language  Today  822,000 C lines of code  dozens of contributors around the world
  5. 5. PHP VERSIONS SURVEY
  6. 6. PHP code compilation
  7. 7. PHP 7 new compiler  PHP 7 compiler is now based on an AST  It has been fully rewritten, and can compute much more things at compile time  Every hash of every litteral string f.e  Resolves every static/litteral expression  Optimizes some function calls when result is known at compile time  defined(), strlen(), cufa(), is_{type}(), assert(), chr(), ord()  Don't use namespaced calls but native_calls()
  8. 8. PHP 7 optimized compiled functions namespace Foo; class Bar { public function hello($str) { return "Hello" . strlen($str); } } L7 #0 RECV 1 $str L9 #1 INIT_NS_FCALL_BY_NAME "Foostrlen" L9 #2 SEND_VAR_EX $str 1 L9 #3 DO_FCALL @0 L9 #4 CONCAT "Hello" @0 ~1 L9 #5 RETURN ~1
  9. 9. PHP 7 optimized compiled functions namespace Foo; class Bar { public function hello($str) { return "Hello" . strlen($str); } } L7 #0 RECV 1 $str L9 #1 STRLEN $str ~0 L9 #2 CONCAT "Hello" ~0 ~1 L9 #3 RETURN ~1 L10 #4 RETURN null
  10. 10. Namespaced function calls  We have proven that the performance difference is really tiny on real use cases. namespace Foo; class Bar { public function hello($str) { return "Hello" . strlen($str); } } namespace Foo; class Bar { public function hello($str) { return "Hello" . strlen($str); } } VS
  11. 11. PHP 7 optimized compiled functions $b = 'foo'; echo strlen($b); L3 #0 ASSIGN $b "foo" L5 #1 STRLEN $b ~1 L5 #2 ECHO ~1 echo strlen('foo'); L1 #0 ECHO 3  Dynamic arg  Static arg
  12. 12. PHP 7 new compiler  PHP 7 compiler is usually slower than PHP 5's  It optimizes more things  It must walk an AST  It is globally more complex  It benefits from a better design  It is hookable through PHP extensions  Use OPCache to not suffer from compile time
  13. 13. PHP 7 compiler optim example, static arrays  Arrays containg keys/vals that are static/litteral  Such arrays are fully resolved at compile time  They involve no runtime work at all const FOO = ['bar', 'baz', 'foo', 34, [42, 'bar'=>'baz']];
  14. 14. Static arrays in PHP 5  A lot of runtime is eaten to construct the same array again and again $a = ['bar', 'baz', 'foo', 34, [42, 'bar'=>'baz']]; 3 0 E > INIT_ARRAY ~0 'bar' 1 ADD_ARRAY_ELEMENT ~0 'baz' 2 ADD_ARRAY_ELEMENT ~0 'foo' 3 ADD_ARRAY_ELEMENT ~0 34 4 INIT_ARRAY ~1 42 5 ADD_ARRAY_ELEMENT ~1 'baz', 'bar' 6 ADD_ARRAY_ELEMENT ~0 ~1 7 ASSIGN !0, ~0
  15. 15. Static arrays in PHP 7  No runtime impact (but compile-time)  You'd better use OPCache $a = ['bar', 'baz', 'foo', 34, [42, 'bar'=>'baz']]; L3 #0 ASSIGN $a array(5)
  16. 16. PHP 7 new references mechanism  In PHP 5, ref mismatching a function call triggered a full zval copy the engine  In PHP 7, the deep copy is postponed until COW breakage function foo($arg) { } $a = 'foo'; $b = &$a; foo($a); /* full copy of the argument */
  17. 17. PHP 7 new references mechanism  In PHP 7, the deep copy is postponed until COW breakage  If no COW breakage, then no copy happens at all function foo($arg) { $arg = 'bar'; } /* full copy of the variable */ $a = 'foo'; $b = &$a; foo($a); $a = ['foo', 42, ['bar' , new stdclass], 'baz']; $b = &$a; if (count($a) == 8) { /* no zval copy here */ }
  18. 18. PHP 7 optimizations from internal
  19. 19. Optimizing CPU time  Latency Numbers Every Programmer Should Know  http://lwn.net/Articles/250967/  http://www.eecs.berkeley.edu/~rcs/research/interactive _latency.html 2016 numbers (may vary with chip) --------------------------------------------------- L1 cache reference 1 ns Branch mispredict 3 ns L2 cache reference 4 ns 4x L1 cache L3 cache reference 12 ns 3X L2 cache, 12x L1 cache Main memory reference 100 ns 25x L2 cache, 100x L1 cache SSD random read 16,000 ns HDD random read(seek) 200,000,000 ns
  20. 20. Optimizing CPU cache efficiency  If we can reduce payload size, the CPU will use its caches more often  CPU caches prefetch data on a "line" basis  Improve data locality to improve cache efficiency  https://software.intel.com/en-us/articles/optimize-data- structures-and-memory-access-patterns-to-improve- data-locality  That means in C  Reduce number of pointer indirections  Stick data together (struct hacks, struct merges)  Use smaller data sizes
  21. 21. PHP 7 cache efficiency  If we can reduce payload size, the CPU will use its caches more often PHP 7.1.4-dev (debug) 128,883666 task-clock (msec) 9 context-switches 0 cpu-migrations 1 768 page-faults 340 930 642 cycles 810 206 077 instructions 100 639 058 branches 187 132 branch-misses 0,131802866 seconds time elapsed PHP 5.6.31-dev (debug) 730,824226 task-clock (msec) 92 context-switches 1 cpu-migrations 74 691 page-faults 2 030 928 993 cycles 3 766 048 098 instructions 506 047 488 branches 356 931 branch-misses 0,773863158 seconds time elapsed
  22. 22. PHP 7 optimizations  Every variable in PHP is coded on a zval struct  This struct has been reorganized in PHP 7  Narrowed / shrinked  separated  Hence, every variable usage in PHP 7 is more optimized than in PHP 5
  23. 23. PHP 5 variables value refcount is_ref type gc_info dval str_val* str_len hashtable* object* lval ast* zval zval_value ... ... HashTable 32 bytes $a 8 bytes zval * XX bytes  40 bytes + complex value size  2 indirections
  24. 24. PHP 7 variables value type internal_int dval zend_string* object* lval ... zval zval_value ... ... HashTable 16 bytes $a zval XX bytes  16 bytes + complex value size  1 indirection hashtable* gc_infos refcount infosflags gc_infos
  25. 25. PHP 5 vs PHP 7 variable design  zval container no longer stores GC infos  No more need to heap allocate a zval *  Very less pressure on the heap allocator  GC infos stored into each complex types  each complex type may now be shared  In PHP 5, we had to share the zval containing them  PHP 7 variables are much more CPU cache efficient
  26. 26. New Memory Allocator  PHP 7 has a fully new heap memory allocator  Zend Memory Manager  It now uses several allocator pools  Huge  Medium  Small  ... for better efficiency  Uses mmap(), no more libc's malloc() overhead  May use Kernel Huge Pages if told to  Better CPU TLB usage
  27. 27. PHP 7 new hashtables
  28. 28. PHP 7 hashtables  It has been fully rewritten, and reworked  Nothing to say from PHP userland POV  Except perhaps for the packed array case
  29. 29. Packed arrays
  30. 30. Packed arrays  If your keys are integer only (no string key)  If your keys are constantly increasing  No matter if they don't follow each other with +1  Then you'll benefit from packed arrays optimization  Packed arrays will reduce memory size compared to "normal" array  Reduction of (table_size - 2) * 4 bytes  ~ 4Kb for a 1000 entry table  May be noticeable for BIG arrays
  31. 31. Packed arrays example const N = 1024 * 1023; for ($i=0; $i<N; $i++) { $tab[] = random_bytes(3); } echo memory_get_usage(); const N = 1024 * 1023; for ($i=0; $i<N; $i++) { $tab[] = random_bytes(3); } $tab['foo'] = 'bar'; echo memory_get_usage(); const N = 1024 * 1023; for ($i=0; $i<N; $i++) { $tab[] = random_bytes(3); } unset($tab[1000]); $tab[1000] = 1000; echo memory_get_usage(); ~67Mb ~71Mb ~71Mb
  32. 32. Packed arrays conditions (recalled)  Do NOT use string keys  Always use increasing integer-based keys  Contiguous or not is not important  If using the compiler, keep keys into the interval [0- table-size] , table-size being rounded to the upper power of two  For example, if you need lists , then you'll benefit from this optimisation
  33. 33. HashTables in PHP 5  Each element needs  4 pointer indirections  72 bytes for a bucket + 32 bytes for a zval zval zval * HashTable $a zval * HashTable* bucket * zval 64 bytes 72 bytesbucket
  34. 34. HashTables in PHP 7  Each element needs  2 pointer indirections  32 bytes for a bucket zval bucket HashTable $a zval HashTable* zval 56 bytes 32 bytes bucket*
  35. 35. HashTables in PHP 7 : go further  http://jpauli.github.io/2016/04/08/hashtables.html
  36. 36. Strings $a = "bar";
  37. 37. String management  In PHP 5, strings don't have their own structure  String management is hard  Leads to many strings duplication  And thus many memory access  In PHP 7, strings share the zend_string structure  They are refcounted, thus shareable  hashes are precomputed, often at compile time  struct hack is used to compact memory
  38. 38. Strings in PHP char * str ... zval gc_infos int len refcount is_ref zend_string * ... zval ... hash gc_infos char str[1]size_t len ... zend_string PHP 5 PHP 7
  39. 39. Strings in PHP 5  $a = "foo"; 3 0X00007FFFF7F8C708 foo0
  40. 40. Strings in PHP 7  $a = "foo"; foo0 C struct hack 3 memory border
  41. 41. Strings tip  Don't forget to use OPCache  OPCache shares interned strings buffer between processes  Don't forget to size interned strings buffer according to your needs  opcache.interned_strings_buffer interned string shared memory PHP master process PHP child #1 PHP child #2 PHP child #3
  42. 42. Encapsed strings
  43. 43. Encapsed string optimisation  Encapsed string are double-quoted strings that get parsed  They need to be analyzed for variables  PHP 5 used to reallocate the string at each step $a = "foo and $b and $c"; 3 0 E > ADD_STRING ~0 'foo+and+' 1 ADD_VAR ~0 ~0, !1 2 ADD_STRING ~0 ~0, '+and+' 3 ADD_VAR ~0 ~0, !2 4 ASSIGN !0, ~0 4 5 > RETURN 1
  44. 44. Encapsed string in PHP 5 $a = "foo and $b and $c"; 3 0 E > ADD_STRING ~0 'foo+and+' 1 ADD_VAR ~0 ~0, !1 2 ADD_STRING ~0 ~0, '+and+' 3 ADD_VAR ~0 ~0, !2 4 ASSIGN !0, ~0 4 5 > RETURN 1 foo and foo and b foo and b and foo and b and c  Lot of pressure on the allocator  Needs to find new chunk  At every new allocation  Browses through a free-chunk linked-list  Bad for performances $b = 'b'; $c = 'c';
  45. 45. Encapsed string optimisation in PHP 7  PHP 7 uses a "rope", and only reallocates memory once, at the end  https://en.wikipedia.org/wiki/Rope_(data_structure) $a = "foo and $b and $c"; L3 #0 ROPE_INIT "foo and " ~1 L3 #1 ROPE_ADD ~1 $b ~1 L3 #2 ROPE_ADD ~1 " and " ~1 L3 #3 ROPE_END ~1 $c ~0 L3 #4 ASSIGN $a ~0 L3 #5 RETURN 1
  46. 46. Encapsed strings in PHP 7 $a = "foo and $b and $c"; L3 #0 ROPE_INIT "foo and " ~1 L3 #1 ROPE_ADD ~1 $b ~1 L3 #2 ROPE_ADD ~1 " and " ~1 L3 #3 ROPE_END ~1 $c ~0 L3 #4 ASSIGN $a ~0 L3 #5 RETURN 1 foo and foo and b foo and b and foo and b and c foo and b and c INIT ADD ADD ADD END  Keep every piece of string as its own buffer  Stack them  At the end, merge them as one operation
  47. 47. So ?  So you'd better use encapsed strings  Than concatenations $a = "foo and $b and $c"; $a = 'foo and ' . $b . ' and ' . $c;
  48. 48. Future ?
  49. 49. Future of PHP  PHP 7 branch keeps optimizing things  PHP 7 branch keep preparing the massive JIT engine move that should happen for PHP 8  PHP 8 is not expected before 2020 at best  Try at first to migrate to PHP 7 branch  PHP 7.2 is on its way  Nov - Dec 2017  As usual, read wiki.php.net/rfc  PHP 5.6 will die end of 2017 , and PHP 5 branch as well
  50. 50. Happy PHP 7 ing
  51. 51. Thank you for listening

×