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

HipHop Virtual Machine (HHVM) for PHP and The h...

HipHop Virtual Machine (HHVM) for PHP and The hack language

A talk about HHVM and Hack at the Webtuesday Zurich on 8 April 2014.

Christian Stocker

April 08, 2014
Tweet

Other Decks in Programming

Transcript

  1. Agile Web Development Liip.ch ! – Zürich, 2014 HIPHOP VIRTUAL

    MACHINE (HHVM) FOR PHP AND THE HACK LANGUAGE Webtuesday, 8. April 2014
  2. AGENDA - HHVM - The Engine - Hack - The

    Language ! - If you have questions during the talk, just ask (or at the end)
  3. ABOUT ME AND WHY I TALK ABOUT HHVM - Partner

    at Liip - @chregu on Twi!er (and almost everywhere else) - PHP “Core” developer (when I was young ;) ) ! - I work together with a Liip team on a big project for the Migros - We use HHVM on that project in production
  4. HHVM - WHAT IS IT - HHVM = HipHop Virtual

    Machine - A PHP Virtual Machine wri!en by Facebook - Goal: Make it much faster than “Zend” PHP - And be compatible to PHP (one way at least) - Language additions to PHP, called Hack - Open sourced in late 2011 (PHP License) - Mainly wri!en in C++, PHP and OCaml
  5. HHVM - THE (SHORT) HISTORY - In 2008, Facebook startet

    with HPHP - A PHP to C++ compiler => HPHPc - Compiling to a (huge) binary - Up to 6x faster than Zend PHP - Also: HPHi (for local dev) and HPHPd (for debugging) - Deprecated in 2013 ! - HHVM began in 2010 - Bytecode compiler, then JIT to native code - Full support of PHP 5.4
  6. HHVM - TODAY - Drop in replacement for PHP-FPM via

    fast-cgi - Version at 3.0.1 - Supports many PHP frameworks out of the box (see h!p:// hhvm.com/frameworks) - Supports many extension (new ones since 3.0 for example XSLT, imagick and mysqli) - Hack is documented - Quite easily installable on Debian based systems - Runs anywhere which is 64-bit x86 linux (on os x kind of, Windows and ARM support is coming)
  7. HHVM - INSTALLATION - DEBIAN deb http://dl.hhvm.com/ubuntu saucy main apt-get

    update apt-get install hhvm /etc/init.d/hhvm start ! and in nginx config ! location ~ \.php$ {! fastcgi_pass 127.0.0.1:9000;! fastcgi_index index.php;! fastcgi_param SCRIPT_FILENAME! /var/www$fastcgi_script_name;! include fastcgi_param;! }
  8. HHVM - INSTALLATION - SUSE # this is needed for

    everything ! export ABI=64 export LD_LIBRARY_PATH=/srv/www/vhosts/api/hhvm/lib64:/srv/www/vhosts/api/hhvm/lib:$LD_LIBRARY_PATH export PATH=/srv/www/vhosts/api/hhvm/bin/:$PATH export SRCFOLDER=/srv/www/vhosts/api/hhvm/src ! mkdir -p $SRCFOLDER cd $SRCFOLDER ! # INSTALL all the dependencies, you only have to do this once ! #CMAKE ! cd $SRCFOLDER wget http://www.cmake.org/files/v2.8/cmake-2.8.12.1.tar.gz tar -xzf cmake-2.8.12.1.tar.gz cd cmake ./configure --prefix=/srv/www/vhosts/api/hhvm/ make install ! #gmp ! cd $SRCFOLDER wget https://gmplib.org/download/gmp/gmp-5.1.3.tar.bz2 tar -xjf gmp-5.1.3.tar.bz2 cd gmp-5.1.3 ./configure --prefix=/srv/www/vhosts/api/hhvm/ make install ! #mpfr ! cd $SRCFOLDER wget http://www.mpfr.org/mpfr-current/mpfr-3.1.2.tar.bz2 cd mpfr-3.1.2 ./configure --prefix=/srv/www/vhosts/api/hhvm/ --with-gmp=/srv/www/vhosts/api/hhvm/ make install ! #mpc ! cd $SRCFOLDER wget http://www.multiprecision.org/mpc/download/mpc-1.0.1.tar.gz cd mpc-1.0.1 ./configure --prefix=/srv/www/vhosts/api/hhvm/ --with-gmp=/srv/www/vhosts/api/hhvm/ make install ! ! ! !
  9. HHVM - INSTALLATION - SUSE #isl ! cd $SRCFOLDER wget

    http://isl.gforge.inria.fr/isl-0.12.tar.bz2 tar -xjf isl-0.12.tar.bz2 cd isl-0.12 ./configure --prefix=/srv/www/vhosts/api/hhvm/ --with-gmp-prefix=/srv/www/vhosts/api/hhvm/ make install ! #GCC ! cd $SRCFOLDER wget ftp://ftp.gwdg.de/pub/misc/gcc/releases/gcc-4.8.2/gcc-4.8.2.tar.bz2 tar -xjf gcc-4.8.2.tar.bz2 cd gcc-4.8.2 ./configure --prefix=/srv/www/vhosts/api/hhvm/ --with-isl=/srv/www/vhosts/api/hhvm --with-gmp=/srv/www/vhosts/api/hhvm/ --with-mpc=/srv/www/vhosts/api/hhvm/ mpfr=/srv/www/vhosts/api/hhvm/ make install ! #bzip ! cd $SRCFOLDER cd bzip2-1.0.6 ./configure --prefix=/srv/www/vhosts/api/hhvm/ make -f Makefile-libbz2_so make install PREFIX=/srv/www/vhosts/api/hhvm/ cd .. #python (needed for boost) ! cd $SRCFOLDER wget http://www.python.org/ftp/python/2.6.9/Python-2.6.9.tgz tar -xzf Python-2.6.9.tgz cd Python-2.6.9 ./configure --prefix=/srv/www/vhosts/api/hhvm/ --enable-shared make install ! #boost ! cd $SRCFOLDER wget http://sourceforge.net/projects/boost/files/boost/1.55.0/boost_1_55_0.tar.bz2/download tar -xjf boost_1_55_0.tar.bz2 cd boost_1_55_0 ls ./bootstrap.sh --with-python=/srv/www/vhosts/api/hhvm/bin/python --prefix=/srv/www/vhosts/api/hhvm ./b2 ./bjam --layout=system install ! ! !
  10. HHVM - INSTALLATION - SUSE #libevent ! cd $SRCFOLDER wget

    https://github.com/downloads/libevent/libevent/libevent-1.4.14b-stable.tar.gz tar -xzf libevent-1.4.14b-stable.tar.gz cd libevent-1.4.14b-stable cat ../hhvm/hphp/third_party/libevent-1.4.14.fb-changes.diff | patch -p1 ./autogen.sh autoreconf --force --install ./configure --prefix=/srv/www/vhosts/api/hhvm/ make make install ! #libcurl ! cd $SRCFOLDER mkdir /srv/www/vhosts/api/hhvm/etc/curlssl wget -O /srv/www/vhosts/api/hhvm/etc/curlssl/cacert.pem http://curl.haxx.se/ca/cacert.pem wget http://curl.haxx.se/download/curl-7.36.0.tar.gz tar -xzf curl-7.36.0.tar.gz cd curl-7.36.0 ./configure --prefix=/srv/www/vhosts/api/hhvm/ --with-ca-bundle=/srv/www/vhosts/api/hhvm/etc/curlssl/cacert.pem make make install ! #google glog ! cd $SRCFOLDER wget https://google-glog.googlecode.com/files/glog-0.3.3.tar.gz tar -xzf glog-0.3.3.tar.gz cd glog-0.3.3 ./configure --prefix=/srv/www/vhosts/api/hhvm/ make make install ! #memcached ! cd $SRCFOLDER wget http://www.memcached.org/files/memcached-1.4.16.tar.gz tar -xzf memcached-1.4.16.tar.gz ./configure --prefix=/srv/www/vhosts/api/hhvm/ make make install ! ! ! ! ! !
  11. HHVM - INSTALLATION - SUSE #libmemcached (1.0.17 doesn't work) !

    cd $SRCFOLDER wget https://launchpad.net/libmemcached/1.0/1.0.16/+download/libmemcached-1.0.16.tar.gz tar -xzf libmemcached-1.0.16.tar.gz cd libmemcached-1.0.16 ./configure --prefix=/srv/www/vhosts/api/hhvm/ --with-memcached=/srv/www/vhosts/api/hhvm/bin/memcached make make install ! #jemalloc ! cd $SRCFOLDER wget http://www.canonware.com/download/jemalloc/jemalloc-3.4.1.tar.bz2 tar -xjf jemalloc-3.4.1.tar.bz2 cd jemalloc-3.4.1 ./configure --prefix=/srv/www/vhosts/api/hhvm/ make make install ! #tbb ! cd $SRCFOLDER wget --no-check-certificate https://www.threadingbuildingblocks.org/sites/default/files/software_releases/source/tbb42_20131118oss_src.tgz tar -xzf tbb42_20131118oss_src.tgz cd tbb42_20131118oss make mkdir -p /srv/www/vhosts/api/hhvm/include/serial cp -a include/serial/* /srv/www/vhosts/api/hhvm/include/serial/ mkdir -p /srv/www/vhosts/api/hhvm/include/tbb cp -a include/tbb/* /srv/www/vhosts/api/hhvm/include/tbb/ cp build/linux_intel64_gcc_cc4.8.2_libc_kernel3.0.82_release/libtbb.so.2 /srv/www/vhosts/api/hhvm/lib64/ ln -s /srv/www/vhosts/api/hhvm/lib64/libtbb.so.2 /srv/www/vhosts/api/hhvm/lib64/libtbb.so ! # mysql ! cd $SRCFOLDER wget http://dev.mysql.com/get/Downloads/MySQL-5.6/mysql-5.6.15.tar.gz tar -xzf mysql-5.6.15.tar.gz cd mysql-5.6.15 cmake . -DWITHOUT_SERVER=ON -DCMAKE_INSTALL_PREFIX=/srv/www/vhosts/api/hhvm make make install cd .. ! ! ! ! !
  12. HHVM - INSTALLATION - SUSE #gd ! cd $SRCFOLDER wget

    https://bitbucket.org/libgd/gd-libgd/downloads/libgd-2.1.0.tar.bz2 tar -xjf libgd-2.1.0.tar.bz2 cd libgd-2.1.0 ./configure --prefix=/srv/www/vhosts/api/hhvm/ make install ! #expat ! cd $SRCFOLDER wget http://downloads.sourceforge.net/project/expat/expat/2.1.0/expat-2.1.0.tar.gz tar -xzf expat-2.1.0.tar.gz cd expat-2.1.0 ./configure --prefix=/srv/www/vhosts/api/hhvm/ make install ! #icu ! cd $SRCFOLDER wget http://download.icu-project.org/files/icu4c/52.1/icu4c-52_1-src.tgz tar -xzf icu4c-52_1-src.tgz cd icu/source ./configure --prefix=/srv/www/vhosts/api/hhvm/make install ! #libmcrypt ! cd $SRCFOLDER wget http://downloads.sourceforge.net/project/mcrypt/Libmcrypt/2.5.8/libmcrypt-2.5.8.tar.bz2 tar -xjf libmcrypt-2.5.8.tar.bz2 cd libmcrypt-2.5.8 ./configure --prefix=/srv/www/vhosts/api/hhvm/ make make install ! #openssl ! cd $SRCFOLDER wget https://www.openssl.org/source/openssl-1.0.1g.tar.gz tar xzf openssl-1.0.1g.tar.gz cd openssl-1.0.1g ./config --prefix=/srv/www/vhosts/api/hhvm/ make make install ! ! ! !
  13. HHVM - INSTALLATION - SUSE #oniguruma ! cd $SRCFOLDER http://www.geocities.jp/kosako3/oniguruma/archive/onig-5.9.5.tar.gz

    tar -xzf onig-5.9.5.tar.gz cd onig-5.9.5 ./configure --prefix=/srv/www/vhosts/api/hhvm/ make make install ! #ldap ! cd $SRCFOLDER wget ftp://sunsite.cnlab-switch.ch/mirror/OpenLDAP/openldap-release/openldap-2.4.38.tgz tar -xzf openldap-2.4.38.tgz cd openldap-2.4.38 ./configure --prefix=/srv/www/vhosts/api/hhvm/ --disable-slapd --disable-bdb make make install ! #libedit ! cd $SRCFOLDER wget http://thrysoee.dk/editline/libedit-20130712-3.1.tar.gz tar -xzf libedit-20130712-3.1.tar.gz cd libedit-20130712-3.1 ./configure --prefix=/srv/www/vhosts/api/hhvm/ make install ! #libelf ! cd $SRCFOLDER wget http://www.mr511.de/software/libelf-0.8.9.tar.gz tar -xzf libelf-0.8.9.tar.gz cd libelf-0.8.9 ./configure --prefix=/srv/www/vhosts/api/hhvm/ make make install ! ! ! ! ! ! ! ! ! ! !
  14. HHVM - INSTALLATION - SUSE #dwarf ! cd $SRCFOLDER wget

    http://gentoo.skyfms.com/distfiles/libdwarf-20120410.tar.gz cd dwarf-20120410/libdwarf ./configure --prefix=/srv/www/vhosts/api/hhvm/ --enable-shared make cp libdwarf/libdwarf.a /srv/www/vhosts/api/hhvm/lib64/ cp libdwarf/libdwarf.h /srv/www/vhosts/api/hhvm/include/ cp libdwarf/dwarf.h /srv/www/vhosts/api/hhvm/include/ ! #cclient ! cd $SRCFOLDER wget ftp://ftp.cac.washington.edu/imap/imap-2007f.tar.gz cd imap-2007f make slx SSLTYPE=none cp -r c-client ../../include/ cp -r c-client/c-client.a ../../lib/libc-client4.a ! #attr ! cd $SRCFOLDER wget http://download.savannah.gnu.org/releases-noredirect/attr/attr-2.4.46.src.tar.gz tar -xzf attr-2.4.46.src.tar.gz cd attr-2.4.46 ./configure --prefix=/srv/www/vhosts/api/hhvm/ make install cp libattr/.libs/libattr.so ../../lib/ ! #libcap cd $SRCFOLDER wget ftp://ftp.de.debian.org/debian/pool/main/libc/libcap2/libcap2_2.22.orig.tar.gz tar -xzf libcap2_2.22.orig.tar.gz cd libcap-2.22/ export prefix=/srv/www/vhosts/api/hhvm/lib export LDFLAGS="-L /srv/www/vhosts/api/hhvm/lib" make make install ! #binutils ! cd $SRCFOLDER wget http://ftp.gnu.org/gnu/binutils/binutils-2.24.tar.bz2 tar -xjf binutils-2.24.tar.bz2 cd binutils-2.24 ./configure —prefix=/srv/www/vhosts/api/hhvm ! !
  15. HHVM - INSTALLATION - SUSE #libxslt ! cd $SRCFOLDER wget

    ftp://xmlsoft.org/libxslt/libxslt-1.1.28.tar.gz tar -xzf libxslt-1.1.28.tar.gz cd libxslt-1.1.28 ./configure --prefix=/srv/www/vhosts/api/hhvm make make install ! # imagick ! cd $SRCFOLDER wget http://mirror.checkdomain.de/imagemagick/ImageMagick-6.8.8-9.tar.gz tar -xf ImageMagick-6.8.8-9.tar.gz cd ImageMagick-6.8.8-9 make make install !
  16. HHVM - INSTALLATION - SUSE # since hhvm 3.0 we

    switched to fastcgi via nginx # nginx ! cd $SRCFOLDER wget http://nginx.org/download/nginx-1.4.7.tar.gz tar -xzf nginx-1.4.7.tar.gz cd nginx-1.4.7 ./configure --prefix=/srv/www/vhosts/api/hhvm --http-log-path=/srv/www/vhosts/api/shared/app/logs/nginx-access.log --error-log-path=/srv/www/vhosts/api/shar nginx-error.log --conf-path=/srv/www/vhosts/api/hhvm/etc/nginx/nginx.conf --pid-path=/srv/www/vhosts/api/pids/nginx.pid --http-fastcgi-temp-path=/srv/www/vh mkdir /srv/www/vhosts/api/hhvm/etc/nginx/ make make install ! # INSTALL all the depend ! #hhvm ! cd $SRCFOLDER git clone https://github.com/facebook/hhvm.git cd hhvm git submodule init git submodule update export HPHP_HOME=`/bin/pwd` ./configure -DCMAKE_PREFIX_PATH=/srv/www/vhosts/api/hhvm/ \ -DCMAKE_C_COMPILER=/srv/www/vhosts/api/hhvm/bin/gcc \ -DCMAKE_INCLUDE_PATH=/srv/www/vhosts/api/hhvm/include \ -DCMAKE_INSTALL_PREFIX=/srv/www/vhosts/api/hhvm/ \ -DLIBMAGICKWAND_INCLUDE_DIRS=/srv/www/vhosts/api/hhvm/include/ImageMagick-6 \ -DLIBMAGICKWAND_LIBRARIES=/srv/www/vhosts/api/hhvm/lib/libMagickWand-6.Q16.so # evt. noch # cmake -D HOTPROFILER:BOOL=ON . make install
  17. HHVM - INSTALLATION - SUSE PHEEEEW … (Maybe not everything

    was actually needed to built from source and SuSE would have provided it, but we were not the sysadmins ;))
  18. HHVM - PERFORMANCE - Is it actually much faster? -

    YES! - But of course it depends ! - Without JIT, it isn’t (in CLI for example) - JIT needs some warm up requests to find the hot paths - The more your scripts do, the more you gain.
  19. HHVM - PERFORMANCE TESTS - Done with siege on the

    servers of the Migros project - 16 CPU, 96 GB RAM, non virtualized - Symfony 2.4 as PHP Framework - Returns a JSON with product information - Retrieved from ElasticSearch (no SQL DB involved here) - Transformed with JMSSerializer ! - Tested with different concurrencies (2 - 80) - Tested against - PHP 5.3/apc with Apache Prefork - PHP 5.5/opcache with nginx - HHVM 3.0 with nginx
  20. HHVM - SOME CHARTS Get 1 Product from the API

    (a small request) requests per second 0 20 40 60 80 2 4 6 10 20 40 80 PHP 5.3/apache PHP 5.5/fpm HHVM 3.0 ms per request 0 450 900 1350 1800 2 4 6 10 20 40 80 PHP 5.3/apache PHP 5.5/fpm HHVM 3.0
  21. HHVM - SOME CHARTS Get 16 products from the API

    (a medium request) requests per second 0 13 26 39 52 2 4 6 10 20 40 80 PHP 5.3/apache PHP 5.5/fpm HHVM 3.0 ms per request 0 1000 2000 3000 4000 2 4 6 10 20 40 80 PHP 5.3/apache PHP 5.5/fpm HHVM 3.0
  22. HHVM - SOME CHARTS Get 50 products from the API

    (a large request) requests per second 0 7 14 21 28 2 4 6 10 20 40 80 PHP 5.3/apache PHP 5.5/fpm HHVM 3.0 ms per request 0 2250 4500 6750 9000 2 4 6 10 20 40 80 PHP 5.3/apache PHP 5.5/fpm HHVM 3.0
  23. HHVM - PERFORMANCE SUMMARY - HHVM is up to 3.5

    times faster than PHP 5.3 - HHVM is up to 2 times faster than PHP 5.5 - PHP 5.5 is up to 1.7 times faster than PHP 5.3 - HHVM scales a li!le bit be!er with concurrency - (load of server was also lower) - The longer your requests, the more you save ! ! - Others came to similar conclusions ;)
  24. HHVM - PROFILING - xhprof is included - But you

    need to recompile HHVM with - cmake -D HOTPROFILER:BOOL=ON . - (it doesn’t have much performance impact) ! - You can use the usual xhprof tools ! - We also use New Relic with HHVM. See end of talk
  25. HHVM - DEBUGGING - With HPHPd - HPHP Debugger -

    Interactive shell -  GDB-like debugging -  Standalone or w/ server -  Breakpoints -  Watches -  Macros
  26. HACK - TYPE HINTING - Scalars - bool, int, float,

    num, string - Return typehints - Typed properties - Constructor arg promotion ! - Static analyzer (hh_client/hh_server) looks for mismatches and errors without running code
  27. HACK - TYPE HINTING <?hh ! class Foo { !

    //Typed properties (and scalar typehint) private int $num = 123; ! //Return typehints public function add(int $delta): Foo { $this->num += $delta; return $this; } ! public function get(): int { return $this->num; } ! // Constructor arg promotion public function __constructor(private int $num): void { } } ! //needed, typechecker doesn't check in global space function main() { ! $f = new Foo(123); $f->add(456); ! // gives error with hh_client $f->add("banana"); } ! main();
  28. HACK - TYPE CHECKER - hh_client / hh_server - Only

    runs on linux right now, needs OCaml - hh_client spawns hh_server - hh_server watches file system on each save - makes hh_client really fast - doesn’t check with <?php ! - Integration for vim and emacs available, more should come
  29. HACK - GENERICS - You may know them from other

    languages like C# or Java - Allow classes and methods to be parameterized <?hh ! class Value<T> { public function __construct(protected T $value) { } ! public function getValue(): T { return $this->value; } ! public function addString(string $bar) { } } ! function main2() { $st = new Value("TestString"); $st->addString($st->getValue()); ! $st = new Value(42); //errors out, since getValue returns int //$st->addString($st->getValue()); } ! main2();
  30. HACK - COLLECTIONS - Specialized array objects - Vector (an

    ordered, index-based list) - Map (an ordered dictionary) - Set (a list of unique values) - Pair (an index-based collection of exactly two elements) - All also as Immutable classes - Clear interface - Literal syntax - It can be defined, what’s in those collections
  31. HACK - COLLECTIONS <?hh ! function CollectionDemo( Vector<int> $nums, Set<string>

    $names, Map<int,string> $numNameMap, ImmVector<int> $nums2): bool { ! foreach($nums as $num) { $mappedName = $numNameMap[$num]; if ($names->contains($mappedName)) { return true; } } if ($nums2->count() == 0) return true; return false; } ! function main3() { $vector = Vector {1, 2, 3}; $set = Set {"foo", "bar", "baz"}; $map = Map { 1 => "hello", 2 => "world" , 3 => "baz"}; $frozen = ImmVector{5,6}; var_dump(CollectionDemo($vector, $set, $map, $frozen)); } ! main3(); !
  32. HACK - TYPE ALIASING AND SHAPES - Type aliasing allows

    to redeclare a type - Opaque Type aliasing restricts access to underlying implementation - Shapes are like struct in other languages, but for arrays - Helps in type checking <?hh ! //type alias type Point = (int, int); //opaque type alias newtype SecretID = int; //shape type Point2D = shape('x' => int, 'y' => int); ! function create_point(int $x, int $y): Point { return tuple($x, $y); } ! function dotProduct(Point2D $a, Point2D $b): int { return $a['x'] * $b['x'] + $a['y'] * $b['y']; }
  33. HACK - OPAQUE TYPE ALIASING <?hh // File1.php ! newtype

    SecretID = int; ! function modify_secret_id(SecretID $sid): SecretID { return $sid - time() - 2042; } ! function main_ot1(): void { echo modify_secret_id(44596); } ! main_ot1(); ! ! <?hh // File2.php ! require_once "opaquetypealiasing.php"; ! function try_modify_secret_id(SecretID $sid): SecretID { //gives an error, because it’s an operation on int return $sid + time() + 2000; } ! function main_ot2(): void { //gives an error, because it’s an int not a SecretID try_modify_secret_id(44596); } ! main_ot2();
  34. HACK - LAMBDA EXPRESSION - Like closures, but shorter -

    Implicitly captures variables from outer scope <?hh ! $foo = $x ==> $x + 1; $foo(12); // returns 13 ! $foo = () ==> 73; $foo(); // returns 73 ! $bar = ($x,$y) ==> $x + $y; $bar(3,8); // returns 11 ! //type hints (not supported yet by the typechecker, gives an error) $captured = "test: "; $bar = (string $k = "foo"): string ==> $captured . $k; !
  35. HACK - ASYNC OPERATIONS - Parallelizing made “easy” - Allow

    multiple functions to run “simultaneously” - While one is blocking, the other executes - NOT threading - A li!le bit complicated right now, but more async native functions (database, scheduling, memory handling) will come <?hh // simplefied example, does not work this way, see next slide ! async function getPage($url) { $fp = fopen($url, 'r'); await $fp; return stream_get_contents($fp); } ! $pages = await [ getPage('http://php.net'), getPage('http://example.com'), getPage('http://hhvm.com'), ];
  36. HACK - ASYNC OPERATIONS <?hh ! class Fetcher { //

    async function: http://docs.hhvm.com/manual/en/hack.async.php // return type annotation: http://docs.hhvm.com/manual/en/hack.annotations.introexample.php public async function fetch(string $url) : Awaitable<int> { $ch1 = curl_init(); print "get $url \n"; ! curl_setopt($ch1, CURLOPT_URL, $url); curl_setopt($ch1, CURLOPT_HEADER, 0); curl_setopt($ch1, CURLOPT_RETURNTRANSFER, true); ! $mh = curl_multi_init(); curl_multi_add_handle($mh,$ch1); ! $active = null; do { $mrc = curl_multi_exec($mh, $active); // reschedule it for async to work properly await RescheduleWaitHandle::Create(1, 1); } while ($mrc == CURLM_CALL_MULTI_PERFORM); ! while ($active && $mrc == CURLM_OK) { if (curl_multi_select($mh) != -1) { do { $mrc = curl_multi_exec($mh, $active); await RescheduleWaitHandle::Create(1, 1); // simulate blocking I/O } while ($mrc == CURLM_CALL_MULTI_PERFORM); } } print "finished $url\n"; return 1; } } !
  37. ! class Fetch { ! protected Fetcher $fetcher; ! //Constructor

    Argument Promotion http://docs.hhvm.com/manual/en/hack.constructorargumentpromotion.php //Vector http://docs.hhvm.com/manual/en/hack.collections.vector.php (instead of array) //Annotating Arrays and Collections: http://docs.hhvm.com/manual/en/hack.annotations.arrays.php public function __construct(private Vector<string> $urls) { $this->fetcher = new Fetcher(); } ! public async function run() : Awaitable<int> { ! //lambda expressions: http://docs.hhvm.com/manual/en/hack.lambda.php $waithandles = $this->urls->map($url ==> $this->fetcher->fetch($url)); ! // works too, but not supported by typechecker yet //$waithandles = $this->urls->map((string $url): Awaitable<int> ==> $this->fetcher->fetch($url)); // same as above, but with closure and annotations, so it catches type errors //$waithandles = $this->urls->map(function(string $url): Awaitable<int> {return $this->fetcher->fetch($url);}); ! //create wait handle for all and only continue when all have finished $x = await GenVectorWaitHandle::Create($waithandles); return $x->count(); } ! public function start() : string { return $this->run()->join() . " urls fetched and finished\n"; } } ! function main4() { //Vector with Literal Syntax: http://docs.hhvm.com/manual/en/hack.collections.literalsyntax.php $urls = Vector{"http://chregu.tv/webinc/sleep.php?s=1","http://chregu.tv/webinc/sleep.php?s=1"}; $f = new Fetch($urls); print $f->start(); } main4(); ! !
  38. HACK - FURTHER FEATURES - Nullable Types. ?int, ?string, ?class

    - User A!ributes (accessible via Reflection) - XHP – XHtml for PHP (Templating) - Continuations (like Generators in PHP) - Tuples (fixed size arrays) - Override A!ribute (define in a child class that there must be a parent class)
  39. HHVM - WRITING EXTENSIONS - It’s not that hard (compared

    to PHP extensions anyway) - You can write the “easy” stuff in PHP/Hack - And switch to C++ for the harder stuff ! - We wrote an extension to use New Relic with HHVM - See blog.liip.ch/archive/2014/03/27/hhvm-and-new-relic.html for details
  40. HHVM - WRITING EXTENSIONS <?hh //The same as newrelic_add_attribute, but

    like in the officical NewRelic PHP API function newrelic_add_custom_parameter(string $name, string $value) { newrelic_add_attribute_intern($name, $value); } ! function newrelic_notice_error(string $error_message, \Exception $e = null) { if ($e) { if (!$error_message) { $error_message = $e->getMessage(); } $exception_type = get_class($e); $stack_trace = $e->getTraceAsString(); } else { $exception_type = ""; $stack_trace = NewRelicExtensionHelper::debug_backtrace_string(); } $stack_frame_delimiter = "\n"; newrelic_notice_error_intern( $exception_type, $error_message, $stack_trace, $stack_frame_delimiter); } function newrelic_start_transaction(string $appname, string $license = null) { newrelic_start_transaction_intern(); newrelic_transaction_set_request_url($_SERVER["REQUEST_URI"]); } ! //... ! <<__Native>> function newrelic_start_transaction_intern(): int; ! <<__Native>> function newrelic_name_transaction_intern(string $name): int; ! <<__Native>> function newrelic_transaction_set_request_url(string $name): int; ! <<__Native>> function newrelic_transaction_set_threshold(int $threshold): int; !
  41. // newrelic.cpp #include "hphp/runtime/base/base-includes.h" #include "hphp/runtime/ext/ext_error.h" #include "newrelic_transaction.h" #include "newrelic_collector_client.h"

    #include "newrelic_common.h" //... using namespace std; namespace HPHP { bool keep_running = true; static int64_t HHVM_FUNCTION(newrelic_start_transaction_intern) { long transaction_id = newrelic_transaction_begin(); return transaction_id; } static int HHVM_FUNCTION(newrelic_name_transaction_intern, const String & name) { return newrelic_transaction_set_name(NEWRELIC_AUTOSCOPE, name.c_str()); } static int HHVM_FUNCTION(newrelic_transaction_set_request_url, const String & request_url) { return newrelic_transaction_set_request_url(NEWRELIC_AUTOSCOPE, request_url.c_str()); } //... static class NewRelicExtension : public Extension { public: NewRelicExtension () : Extension("newrelic") { config_loaded = false; } virtual void init_newrelic() { newrelic_register_message_handler(newrelic_message_handler); newrelic_init(license_key.c_str(), app_name.c_str(), app_language.c_str(), app_language_version.c_str()); } virtual void moduleLoad(Hdf config) { if (!config.exists("EnvVariables")) return; Hdf env_vars = config["EnvVariables"]; //... } virtual void moduleInit () { if (config_loaded) init_newrelic(); ! HHVM_FE(newrelic_start_transaction_intern); HHVM_FE(newrelic_name_transaction_intern); HHVM_FE(newrelic_transaction_set_request_url); //... loadSystemlib(); } virtual void requestShutdown() { newrelic_transaction_end(NEWRELIC_AUTOSCOPE); } virtual void requestInit() { f_set_error_handler(s__NR_ERROR_CALLBACK); f_set_exception_handler(s__NR_EXCEPTION_CALLBACK); //TODO: make it possible to disable that via ini GlobalVariables *g = get_global_variables(); newrelic_transaction_begin(); String request_url = g->get(s__SERVER).toArray()[s__REQUEST_URI].toString(); newrelic_transaction_set_request_url(NEWRELIC_AUTOSCOPE, request_url.c_str()); String script_name = g->get(s__SERVER).toArray()[s__SCRIPT_NAME].toString(); newrelic_transaction_set_name(NEWRELIC_AUTOSCOPE, script_name.c_str()); } } s_newrelic_extension; HHVM_GET_MODULE(newrelic) } // namespace HPHP
  42. HHVM - DRAWBACKS? - Not every library works yet (eg.

    Doctrine DBAL only in dev branch) - Not really open dev model, Facebook controls it totally (and CLA needed for contribution), the far future is unknown - Still kind of moving target - Type Checker only really useful, when all your important classes are converted to <?hh - No easy way back, when you start using Hack. - If you need exotic extensions …
  43. Agile Web Development Liip.ch ! – Christian Stocker @chregu [email protected]

    QUESTIONS? And some links: ! - The examples from this talk: 
 github.com/chregu/hack-examples - The HHVM site: hhvm.com - with a blog: hhvm.com/blog - HHVM/Hack Docs: docs.hhvm.com - Hacklang site (with tutorial): hacklang.org