Upgrade to Pro — share decks privately, control downloads, hide ads and more …

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.

Nicolas Grekas

April 12, 2018
Tweet

More Decks by Nicolas Grekas

Other Decks in Technology

Transcript

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

    View Slide

  2. View Slide

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

    View Slide

  4. @nicolasgrekas

    View Slide

  5. live.symfony.com

    View Slide

  6. View Slide

  7. • Born in 1995 – v7 end of 2016
    • 870,000 C lines of code
    • Distributed leadership
    The PHP engine

    View Slide

  8. • Since 2011 – v4 end of 2017
    • PHP ^7.1
    • 98 packages
    • 1.5B downloads
    Symfony

    View Slide

  9. • Code infrastructure since Drupal 8
    • Now at Symfony v3.4
    • Deprecation policy and code
    • Time-based releasing process
    Symfony in Drupal

    View Slide

  10. blog.jpauli.tech
    nikic.github.io

    View Slide

  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

    View Slide

  12. View Slide

  13. spl_autoload_register(
    Composer\Autoload\ClassLoader)
    Implement more in userland

    View Slide

  14. Cache

    View Slide

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

    View Slide

  16. • realpath_cache_size=1M
    • clearstatcache()
    • Compiled RegExps
    • OPcache
    What does PHP cache?

    View Slide

  17. OPcache?

    View Slide

  18. Steps to execute a script
    index.php
    Lexing + parsing
    AST
    opcodes
    Compiling
    Executing
    result

    View Slide

  19. First steps are immutable
    index.php
    Lexing + parsing
    AST
    opcodes
    Compiling
    Executing
    result
    Shared
    memory*
    *append-only

    View Slide

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

    View Slide

  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

    View Slide

  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

    View Slide

  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

    View Slide

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

    View Slide

  25. Compile time inlining
    https://github.com/symfony/symfony/pull/25854

    View Slide

  26. Runtime-resolved identifiers are
    cached in the (local) opcode array
    Don’t « \ » all function calls
    Stick to the short list

    View Slide

  27. Let’s split the container in one file per service
    PHP 7 is slow… at compiling
    https://github.com/symfony/symfony/pull/23678

    View Slide

  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

    View Slide

  29. Interned strings and
    immutable arrays
    stay in shared memory
    Mind opcache.interned_strings_buffer

    View Slide

  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

    View Slide

  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

    View Slide

  32. • AbstractRecursivePass
    • ClassLoader
    • VarCloner
    $cache[$k][$v] = [$k => $v];
    Not triggering copy-on-write

    View Slide

  33. What else can be slow?

    View Slide

  34. Bypassing the autoloader

    View Slide

  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

    View Slide

  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

    View Slide

  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

    View Slide

  38. http://www.phpbenchmarks.com/en/comparator/frameworks.html

    View Slide

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

    View Slide

  40. View Slide

  41. Conclusion
    • Wow PHP 7
    • Source ideas in PHP’s C
    • Use only in tight loops
    • Never stop measuring

    View Slide

  42. View Slide

  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

    View Slide

  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

    View Slide