ipc 2013 - high performance php with hiphop
TRANSCRIPT
Steve Kamerman | ScientiaMobile, Inc.High-Performance PHP with HipHopCo-Founder / Software Architect
2008 - Facebook's Challenge
Explosive growth
Need more servers!
Bottleneck: Page generation
20% of PHP time was in native code
Why is PHP so slow?
Symbol table lookups
No static binding
Dynamic typing
Share-Nothing-Architecture
2008-2010 HipHop for PHP is born
400 Billion PHP-generated pageviews per month!
Facebook invents HipHop for PHP
Deployed system-wide in 2010
154k/second, or 154/sec per server on 1000 servers
HPHPc
Research &
Development
HHVM
HipHop for PHP
What is HipHop for PHP?
Multi-threaded web server + PHP runtime
HPHPc: PHP -> C++ translator
HHVM: PHP virtual machine with JIT compiler
Typically 2x 5x speed increase over stock PHP + APC
HipHop for PHP Compiler (HPHPc)
Translates PHP code into C++
Dynamic typing makes this difficult
Function parity lacking
Long compilation time
Literally translated PHP code into human-readable C++, preserving class names
At Facebook, PHP and C++ are common languages, so this works well
Many versions of each function may be generated with different parameter types to optimized code
Compilation at Facebook took 20min (across 100 machines)
Our Experience
Created WURFL Cloud REST API
Evaluated HPHPc
Improved Latency
Stability issues
Architecture
InternetHAProxy
Load Balancer
(primary)HAProxy
Load Balancer
(secondary)
WURFL NodeApacheHPHPcMemcachedMySQLWURFL NodeApacheHPHPcMemcachedMySQLWURFL NodeApacheHPHPcMemcachedMySQLWURFL NodeApacheHPHPcMemcachedMySQL
Codebase Updates
http://www.github.com/kamermans/HAProxyAPI
Facebook was customer
Reduced latency from 20ms (Apache) to 2m
Peak traffic over 1500 req/sec, load tested at over 10k req/sec per serverCode rebuild took almost 10 minutes per server
HPHP and Apache shared the same document root
Compilation of HPHP itself was painful! Super-specific dependencies
Next-Gen HipHop: HHVM
Virtual Machine
Better PHP Support
JIT Compiler
Bytecode Survives Restart
How HHVM works
InternetHHVM
Web ServerGenerate
BytecodeJIT Compile
Run Native
Code
Run Bytecode
HHVM vs HPHPc Performance
https://github.com/facebook/hhvm/blob/master/hphp/doc/ir.specification
http://www.hhvm.com/blog/875/wow-hhvm-is-fast-too-bad-it-doesnt-run-my-code
Optimizing PHP for HHVM
Type InferencePHP Gotcha: core function fail with
(bool)false
HHVM Upgrades primitives
Use strict comparison
Don't care about type strict comparison?
You should. Trust me.
var_export("true" == true); // true
var_export("false" == true); // true
var_export("true" == (bool)"false"); // true
var_export(strpos("Steve Kamerman", "Kamerman") == true); //
true
var_export(strpos("Steve Kamerman", "Steve") == true); //
false
$test = "31 is too old!";
var_export(31 == $test); // true
var_export("31.0" == 31); // true
var_export("031" == 031); // false
var_export(31.0 == 31); // true
var_export($test += 1); // 32
Avoid global scope
Code in the global scope is interpreted since it is (nearly) impossible to type-track
Even wrapping global code helps:
class foo{public static function bar(){
$something = "test";
echo $something;
}}foo::bar();Better approach: dont write crappy code!
Unique Classes, Functions, Constants
HHVM supports namespaces use them!
MyApp\Bar and MyApp\Foo\Bar are not ambiguous
Avoid dynamic constants:
define("MY_CONST", $foo? "foo": "bar");
I can almost picture a feature request for undefine() and redefine()
If they are truly constant, use const
Better approach: don't use define()
namespace MyApp; class Config {
const MY_CONST = "I'm real constant";
private static $storage = array(
"PSEUDO_CONSTANT" => "What did you call me?",
);
public static function get($name) {
if (!array_key_exists($name, self::$storage)) {
throw new \Exception(__CLASS__." property [$name] does not
exist");
}
return self::$storage[$name];
}
}
echo Config::MY_CONST."\n";
echo Config::get("PSEUDO_CONSTANT")."\n";
Avoid dynamic variables
If you are using this syntax, there is a better way to solve the
problem:
$foo = "Wow, this hurts my brain!";
$var_name = "foo";
echo $$var_name;
extract() and compact() are sometimes used more legitimately
(ex: view rendering), but avoid them
If you need get_defined_vars() for non-testing code, you need to rewrite it before someone sees it :)
Declare class properties
They should be declared anyway
$foo = new stdClass();
echo $foo->bar; // PHP Notice: Undefined property
Getters are optimized
Perfomance Gain
Less than 5%, but still good practice
Sub-optimal functions still work, even eval() and goto!
http://php.net/manual/en/control-structures.goto.php
Repo.Authoritative Mode
Pre-Analyze files
PHP files assumed unchanged
Delete cache manually
To use:
Analyze:hhvm --hphp --target hhbc --input-list