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

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.

Martin Helmich

March 28, 2014
Tweet

More Decks by Martin Helmich

Other Decks in Programming

Transcript

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

    Conference, March 28th 2014 Martin Helmich, Mittwald CM Service [email protected] Photo: George Lamson, CC BY-NC-SA http://www.flickr.com/photos/lamsongf/6415913075/
  2. <?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
  3. 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";
  4. 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";
  5. 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 !
  6. Lexing Parsing Compilation Execution Opcode Cache PHP opcodes PHP execution,

    opcode cache opcodes executed by PHP interpreter
  7. 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
  8. $whatAmI = "Dynamic typization is great!"; ! if ($whatAmI >

    0) { $whatAmI = [ "But in many PHP programs,", "this is not excessively used." ]; } else { $whatAmI = FALSE; }
  9. <?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
  10. 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
  11. One does not simply run TYPO3 Flow on HHVM. Flore

    Allemandou, CC BY-NC-SA http://www.flickr.com/photos/flore_frmoz/5031037626/
  12. 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
  13. 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 %
  14. 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 }
  15. 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 } }
  16. 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/
  17. 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)
  18. 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
  19. 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
  20. 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
  21. 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
  22. 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
  23. 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