InspiringCon14: ElePHPants on speed: Running TYPO3 Flow on HipHop VM

InspiringCon14: ElePHPants on speed: Running TYPO3 Flow on HipHop VM

License: CC BY-SA

The rise of increasingly complex PHP frameworks and applications in the past few years has also changed the requirements that are put on the performance of the PHP interpreter itself – a field in which PHP as an interpreted language has always had a conceptual disadvantage in comparison to compiled languages.

A common approach to optimize the performance of PHP applications is the use of opcode caches like APC or OpCache, which cache the interpreter-generated byte code. A different solution is provided by HipHop VM, which implements a just-in-time compiler that translates PHP code into native machine code.

This talk aims at exploring if and how the current state of HHVM can be used to run TYPO3 Flow applications like TYPO3 Neos, what limitations need to be considered and what performance gains can be achieved in comparison to the traditional Zend Engine in conjunction with various opcode caches.

2b68bc93708466a655a4c60458dc7955?s=128

Martin Helmich

March 28, 2014
Tweet

Transcript

  1. ElePHPants on speed Running TYPO3 Flow on HipHop VM Inspiring

    Conference, March 28th 2014 Martin Helmich, Mittwald CM Service m.helmich@mittwald.de Photo: George Lamson, CC BY-NC-SA http://www.flickr.com/photos/lamsongf/6415913075/
  2. YOUR SPEAKER Martin Helmich Software architect at Mittwald TYPO3 addicted

    since 2004 Caffeine addicted since 2007
  3. Sebastian Bergmann, CC BY-SA http://www.flickr.com/photos/sebastian_bergmann/2337231691/

  4. Lexing Parsing Compilation Execution PHP execution, traditional

  5. <?php ! $locations = [ 0 => "Kolbermoor", 1 =>

    "Espelkamp", 2 => "Las Vegas" ]; ! $currentLoc = 0; $currentLocName = $locations[$currentLoc]; ! if ($currentLoc === 2) { $greeting = "%s, baby!"; } else { $greeting = "Hello %s!"; } ! echo sprintf($greeting, $currentLocName) . "\n"; Lexing Parsing Compilat Executio
  6. T_OPEN_TAG T_VARIABLE T_LNUMBER T_DOUBLE_ ARROW T_CONSTANT_ENCAPSED_STRING T_IF T_ELSE T_ECHO T_STRING

    Lexing Parsing Compilat Executio <?php ! $locations = [ 0 => "Kolbermoor", 1 => "Espelkamp", 2 => "Las Vegas" ]; ! $currentLoc = 0; $currentLocName = $locations[$currentLoc]; ! if ($currentLoc === 2) { $greeting = "%s, baby!"; } else { $greeting = "Hello %s!"; } ! echo sprintf($greeting, $currentLocName) . "\n";
  7. Lexing Parsing Compilat Executio Variable assignment Array constructor Array accessor

    Constant Conditional statement Boolean expression Function call Print statement <?php ! $locations = [ 0 => "Kolbermoor", 1 => "Espelkamp", 2 => "Las Vegas" ]; ! $currentLoc = 0; $currentLocName = $locations[$currentLoc]; ! if ($currentLoc === 2) { $greeting = "%s, baby!"; } else { $greeting = "Hello %s!"; } ! echo sprintf($greeting, $currentLocName) . "\n";
  8. Lexing Parsing Compilat Executio compiled vars: !0 = $locations, !1

    = $currentLocationId, !2 = $currentLocationName, !3 = $greetingTemplate line # * op fetch ext return operands ---------------------------------------------------------------- 4 0 > EXT_STMT 1 INIT_ARRAY ~0 'Kolbermoor', 0 5 2 ADD_ARRAY_ELEMENT ~0 'Espelkamp', 1 7 3 ADD_ARRAY_ELEMENT ~0 'Las+Vegas', 2 4 ASSIGN !0, ~0 9 5 EXT_STMT 6 ASSIGN !1, 0 10 7 EXT_STMT 8 FETCH_DIM_R $3 !0, !1 9 ASSIGN !2, $3 12 10 EXT_STMT 11 IS_IDENTICAL ~5 !1, 2 12 > JMPZ ~5, ->16 13 13 > EXT_STMT 14 ASSIGN !3, '%25s%2C+baby%21' 14 15 > JMP ->18 15 16 > EXT_STMT 17 ASSIGN !3, 'Hello+%25s%21' 18 18 > EXT_STMT 19 EXT_FCALL_BEGIN 20 SEND_VAR !3 21 SEND_VAR !2 22 DO_FCALL 2 $8 'sprintf' 23 EXT_FCALL_END 24 CONCAT ~9 $8, '%0A' 25 ECHO ~9 19 26 > RETURN 1 !
  9. Lexing Parsing Compilat Executio

  10. Lexing Parsing Compilation Execution PHP execution, traditional

  11. Lexing Parsing Compilation Execution Opcode Cache PHP opcodes PHP execution,

    opcode cache opcodes executed by PHP interpreter
  12. Lexing Parsing Compilation Execution HipHop bytecode JIT compiler HipHop intermediate

    representation Code repository x86-64/arm machine code PHP execution, HipHop VM executed as native machine code AST https://www.facebook.com/notes/facebook-engineering/the-hiphop-virtual-machine/10150415177928920 http://www.hhvm.com/blog/2027/faster-and-cheaper-the-evolution-of-the-hhvm-jit
  13. $whatAmI = "Dynamic typization is great!"; ! if ($whatAmI >

    0) { $whatAmI = [ "But in many PHP programs,", "this is not excessively used." ]; } else { $whatAmI = FALSE; }
  14. <?php ! $locations = [ 0 => "Kolbermoor", 1 =>

    "Espelkamp", 2 => "Las Vegas" ]; ! $currentLoc = 0; $currentLocName = $locations[$currentLoc]; ! if ($currentLoc === 2) { $greeting = "%s, baby!"; } else { $greeting = "Hello %s!"; } ! echo sprintf($greeting, $currentLocName) . "\n"; Array of strings Integer String
  15. How to install wget -O - http://dl.hhvm.com/conf/hhvm.gpg.key | apt-key add

    - echo deb http://dl.hhvm.com/debian wheezy main | tee /etc/apt/sources.list.d/hhvm.list sudo apt-get update sudo apt-get install hhvm https://github.com/facebook/hhvm/wiki/Prebuilt-Packages-on-Debian-7
  16. None
  17. Running TYPO3 Flow on HHVM

  18. One does not simply run TYPO3 Flow on HHVM. Flore

    Allemandou, CC BY-NC-SA http://www.flickr.com/photos/flore_frmoz/5031037626/
  19. None
  20. None
  21. TYPO3.Flow/Classes/.../Core/Bootstrap.php ---|+++++++ TYPO3.Flow/Classes/.../Error/ErrorHandler.php -|+ TYPO3.Flow/Classes/.../Http/Headers.php |+++++ TYPO3.Flow/Classes/.../Mvc/Routing/ObjectPathMappingRepository.php -----|++++ TYPO3.Flow/Classes/.../Object/Configuration/ConfigurationArgument.php --|++++++++

    TYPO3.Flow/Classes/.../Object/Configuration/ConfigurationProperty.php --|++++++++ TYPO3.Flow/Classes/.../Package/Package.php -|+ TYPO3.Flow/Classes/.../Security/AccountRepository.php -----|++++ TYPO3.Flow/Classes/.../Security/Policy/Role.php -|+++++ TYPO3.Flow/Classes/.../Security/Policy/RoleRepository.php -----|+++++++ TYPO3.Flow/Classes/.../Utility/Unicode/TextIterator.php -|+++++ TYPO3.Party/Classes/TYPO3/Party/Domain/Repository/PartyRepository.php -|+++ doctrine/dbal/lib/.../Driver/PDOConnection.php |+++++++++++++++++++++++++++++++++++++++ doctrine/dbal/lib/.../Driver/PDOStatement.php -|+++++++++++++++++++++++++++++++++++++++ Web/index.php |++ TYPO3.Media/Classes/.../Domain/Model/Image.php -|++++ TYPO3.Media/Classes/.../Domain/Model/ImageVariant.php -|++++ TYPO3.Setup/Classes/.../Core/BasicRequirements.php -| TYPO3.Setup/Classes/.../Core/RequestHandler.php |+++ TYPO3.TYPO3CR/Classes/.../Migration/Command/NodeCommandController.php -|+++++ imagine/imagine/lib/.../Filter/Basic/Resize.php --|++ imagine/imagine/lib/.../Filter/Basic/Thumbnail.php --|++ Doctrine issue #372 (https://github.com/doctrine/dbal/pull/373), backported to 2.3 Hacks around various HHVM glitches
  22. TYPO3 Flow 2.1 Unit tests, PHP 5.5 Tests: 4186, Assertions:

    10145, Failures: 1, Incomplete: 1, Skipped: 95 Unit tests, HHVM (with compatibility patches) Tests: 4186, Assertions: 10057, Failures: 14, Errors: 21, Incomplete: 1, Skipped: 95 99,98 % 99,14 %
  23. Configuration/Production.hdf Server { SourceRoot = /var/www/my-flow-site/Web DefaultDocument = index.php Port

    = 9000 ThreadCount = 100 }
 
 Eval { Jit = true } ! VirtualHost { my-flow-site { Pattern = .* ServerVariables { FLOW_REWRITEURLS = 1 FLOW_CONTEXT = Production }
  24. Server { SourceRoot = /var/www/my-flow-site/Web DefaultDocument = index.php Port =

    9000 ThreadCount = 100 }
 
 Eval { Jit = true } ! VirtualHost { my-flow-site { Pattern = .* ServerVariables { FLOW_REWRITEURLS = 1 FLOW_CONTEXT = Production } RewriteRules { persistentresources { pattern = ^/?(_Resources/Persistent/.{40})/.+(\..+) to = $1$2 } ! index { pattern = ^(.*) to = index.php/$1 qsa = true } } } } ! StaticFile { Extensions { css = text/css js = text/javascript png = image/png jpg = image/jpeg } }
  25. TYPO3: Flow: core: phpBinaryPathAndFilename: /usr/bin/hhvm subRequestPhpIniPathAndFilename: false Configuration/Settings.yaml (configured for

    speed) Use HHVM on sub-requests, too for even more performance. Nico Kaiser, CC BY http://www.flickr.com/photos/nicokaiser/6070496071/
  26. TYPO3: Flow: core: phpBinaryPathAndFilename: /usr/bin/php subRequestPhpIniPathAndFilename: /etc/php5/cli/php.ini Always specify a

    php.ini or “false”. Automatic detection will fail. Configuration/Settings.yaml (configured conservatively)
  27. Start it > FLOW_CONTEXT=PRODUCTION hhvm -m server -c Configuration/Production.hdf

  28. None
  29. 0 20 40 60 80 Concurrency 50 100 150 200

    250 300 350 400 450 500 PHP (Apache+opcache) HHVM (standalone) HHVM (FCGI+Apache) HHVM (FCGI+nginx) Requests per second TYPO3 Neos 1.0.2, production mode, with HHVM patches
  30. 0 4 8 12 16 Concurrency 50 100 150 200

    250 300 350 400 450 500 PHP (Apache+opcache) HHVM (standalone) HHVM (FCGI+Apache) HHVM (FCGI+nginx) Response times TYPO3 Neos 1.0.2, production mode, with HHVM patches
  31. 91 % 93,25 % 95,5 % 97,75 % 100 %

    Concurrency 50 100 150 200 250 300 350 400 450 500 PHP (Apache+opcache) HHVM (standalone) HHVM (FCGI+Apache) HHVM (FCGI+nginx) Availability TYPO3 Neos 1.0.2, production mode, with HHVM patches
  32. Don't forget! Always enable production mode!

  33. > composer create-project \ mittwald-typo3/neos-hhvm-distribution > composer create-project \ mittwald-typo3/flow-hhvm-distribution

    Contribute: https://github.com/mittwald/flow-hhvm
  34. > composer create-project \ mittwald-typo3/neos-hhvm-distribution Apply compatibility patches Adjust configuration

    Create appropriate HDF configuration file What does it do?
  35. HHVM FastCGI Static files nginx

  36. Use HHVM as FastCGI backend Server { Type = fastcgi

    FileSocket = /var/run/hhvm.sock SourceRoot = /var/www/my-flow-site/Web DefaultDocument = index.php ThreadCount = 100 } configuration.hdf
  37. Use HHVM as FastCGI backend ProxyPassMatch ^/_Resources ! ProxyPass /

    fcgi://127.0.0.1:9000/var/www/flow/Web/ Apache configuration location /_Resources { try_files $uri; } ! location / { fastcgi_pass 127.0.0.1:9000; fastcgi_index index.php; fastcgi_param SCRIPT_FILENAME /var/www/flow/Web/$fastcgi_script_name; include fastcgi_params; } Nginx configuration
  38. Tobias Schlitt, CC-BY-NC-SA http://www.flickr.com/photos/tobiasschlitt/2644905363/

  39. Duncan

  40. Reading The HipHop virtual machine https://www.facebook.com/notes/facebook-engineering/the-hiphop-virtual-machine/10150415177928920 ! Faster and cheaper:

    The evolution of the HHVM JIT http://www.hhvm.com/blog/2027/faster-and-cheaper-the-evolution-of-the-hhvm-jit ! HHVM runtime options https://github.com/facebook/hhvm/wiki/Runtime-options ! Running HHVM as FastCGI server https://github.com/facebook/hhvm/wiki/FastCGI ! HipHop bytecode specification https://github.com/facebook/hhvm/blob/master/hphp/doc/bytecode.specification ! HipHop intermediate representation specification https://github.com/facebook/hhvm/blob/master/hphp/doc/ir.specification ! HHVM compatibility package for TYPO3 Flow and Neos https://github.com/mittwald/flow-hhvm ! Alla breve: Serverlasten halbieren mit dem PHP-zu-C++-Konverter HipHop c't, 23/2010, p. 180