Getting the most out of the PHP 7 engine - the example of Symfony

Getting the most out of the PHP 7 engine - the example of Symfony

PHP 7.0 is already history. But do you know how to take full advantage of it? If the engine is faster on all operations in general, some of them are particularly optimized. With PHP 5, you may have taken some habits that are no longer topical to write faster code? I propose to review with you the various optimization techniques implemented in Symfony, which make the v4 the fastest ever published. This will be an opportunity to twist the puzzle around a few preconceived ideas, and give you a few more for the day when you'll try to squeeze the last few milliseconds out of this intensive loop. Benchmark in support of course.

6baa34bc1e5c347b1003f6abe8691de1?s=128

Nicolas Grekas

April 12, 2018
Tweet

Transcript

  1. Getting the most out of the PHP 7 engine -

    the example of
  2. None
  3. Getting the most out of the PHP 7 engine -

    the example of
  4. @nicolasgrekas

  5. live.symfony.com

  6. None
  7. • Born in 1995 – v7 end of 2016 •

    870,000 C lines of code • Distributed leadership The PHP engine
  8. • Since 2011 – v4 end of 2017 • PHP

    ^7.1 • 98 packages • 1.5B downloads Symfony
  9. • Code infrastructure since Drupal 8 • Now at Symfony

    v3.4 • Deprecation policy and code • Time-based releasing process Symfony in Drupal
  10. blog.jpauli.tech nikic.github.io

  11. Synchronous and parallel Master Child 1 Child 2 Child n

    index.php index.php index.php index.php index.php index.php PHP’s memory manager insulates each scripts
  12. None
  13. spl_autoload_register( Composer\Autoload\ClassLoader) Implement more in userland

  14. Cache

  15. Persistent memory pools Master Child n index.php index.php index.php Process

    memory Shared memory
  16. • realpath_cache_size=1M • clearstatcache() • Compiled RegExps • OPcache What

    does PHP cache?
  17. OPcache?

  18. Steps to execute a script index.php Lexing + parsing AST

    opcodes Compiling Executing result
  19. First steps are immutable index.php Lexing + parsing AST opcodes

    Compiling Executing result Shared memory* *append-only
  20. Compile time optimizations AST opcodes Compiling Shared memory • Compile-time

    evaluation 'foo'."bar" • Dead-code elimination if (false) {…}
  21. Compile time optimizations AST opcodes Compiling Shared memory • Compile-time

    evaluation 'foo'."bar" • Dead-code elimination if (false) {…} • Interned strings "foobar" len=6 hash=Ox1234 • Immutable arrays [123, ["ab" => 34]] len=2 len=1
  22. Compile time optimizations AST opcodes Compiling Shared memory • Compile-time

    evaluation 'foo'."bar" • Dead-code elimination if (false) {…} • Interned strings "foobar" len=6 hash=Ox1234 • Immutable arrays [123, ["ab" => 34]] len=2 len=1
  23. • Works for constants 'cli' === PHP_SAPI • Works for

    some native functions 1 === count([123]) • Needs fully-qualified identifiers namespace App; \count([123]); Compile time evaluation
  24. namespace App; is_array($a); \is_array($a); Compile time inlining https://github.com/FriendsOfPHP/PHP-CS-Fixer/issues/3048 strlen(), is_{type}(),

    {type}val() casts, defined(), chr(), ord(), call_user_function(), call_user_function_array(), get_class(), get_called_class(), gettype(), count(), in_array(), array_slice(), func_num_args(), func_get_args(), function_exists(), is_callable(), extension_loaded(), constant(), dirname()
  25. Compile time inlining https://github.com/symfony/symfony/pull/25854

  26. Runtime-resolved identifiers are cached in the (local) opcode array Don’t

    « \ » all function calls Stick to the short list
  27. Let’s split the container in one file per service PHP

    7 is slow… at compiling https://github.com/symfony/symfony/pull/23678
  28. • Loading opcodes is really fast • Still takes time

    and memory • « require » is also really fast opcodes move from shared memory to process’ https://github.com/symfony/symfony/pull/23678
  29. Interned strings and immutable arrays stay in shared memory Mind

    opcache.interned_strings_buffer
  30. Leveraging shared memory https://blog.blackfire.io/speeding-up-autoloading-on-php-5-6-7-0-for-everyone.html https://blog.blackfire.io/php-7-performance-improvements-immutable-arrays.html

  31. • Shared memory is read-only $a = […]; $a[0] =

    123; • Duplication happens on « write » $a = "abc"; $b = $a; $b .= "ghi"; (by the way, scalars are free, and declared properties make objects very compact) https://blog.blackfire.io/php-7-performance-improvements-ints-floats-free.html ❤ Copy-on-write
  32. • AbstractRecursivePass • ClassLoader • VarCloner $cache[$k][$v] = [$k =>

    $v]; Not triggering copy-on-write
  33. What else can be slow?

  34. Bypassing the autoloader

  35. • gc_collect_cycles() autotriggered past 10k objects • gc_mem_caches() PHP7 memory

    manager is lazy • Much improved in PHP 7.3 PHP garbage collector
  36. • Coalesce operator A ?? B vs isset(A) ? A

    : B https://github.com/symfony/symfony/pull/26161 • Ropes for encapsed strings "$a and $b" vs $a." and ".$b https://blog.blackfire.io/php-7-performance-improvements-encapsed-strings-optimization.html • Packed arrays (incrementing keys only) https://blog.blackfire.io/php-7-performance-improvements-packed-arrays.html • Class constants can be slow https://github.com/symfony/symfony/pull/25474 - https://github.com/twigphp/Twig/pull/2636 More goodies
  37. • Reference mismatches are gone https://blog.blackfire.io/php-7-performance-improvements-references-mismatch.html • Copy-on-write is not

    triggered by (string)/(array) cast • Since PHP 7.2, « switch » statements use a hashmap • JIT is actively worked on for PHP 8 (no ETA) Even more goodies
  38. http://www.phpbenchmarks.com/en/comparator/frameworks.html

  39. https://rawgit.com/kocsismate/php-di-container-benchmarks/master/var/benchmark.html

  40. None
  41. Conclusion • Wow PHP 7 • Source ideas in PHP’s

    C • Use only in tight loops • Never stop measuring
  42. None
  43. Join us for contribution sprints Friday, April 13, 2018 9:00-18:00

    Room: 103 Mentored Core sprint First time sprinter workshop General sprint #drupalsprint 9:00-12:00 Room: 101 9:00-18:00 Room: 104
  44. What did you think? Locate this session at the DrupalCon

    Nashville website: http://nashville2018.drupal.org/schedule Take the Survey! https://www.surveymonkey.com/r/nashiville