From wiki.mikejung.biz
Jump to navigation Jump to search

HHVM Overview

Facebook created Hip Hip for PHP to try and make PHP use less resources by converting it to C++ and compiling it, then running it. This kind of worked but it was hard to make changes to code quickly because you had to re compile and ship code all over in large binaries. To have the best of both worlds Facebook then created HHVM which is a "just in time compiler" which executes PHP code like a boss and makes your website fast.

HHVM translates PHP into [bytecode] which is then compiled by a just in time compiler making it really fast. Machine code is faster than Bytecode due to less overhead for the CPU so not only is this faster, but it also uses a lot less resources. The performance gain is small to normal people. On a large scale though, this means you use less RAM and CPU, generally speaking that means you don't have to spend as much money.

HHVM Performance

HHVM is not always faster than PHP. The first time execution speed for HHVM is always slower because if the just in time compiler. After the first time HHVM performance significantly better.

tl;drHHVM is an open source virtual machine that can execute PHP or HACK with a JIT (just in time compiler).

  • As of Mid 2014 HHVM provides 10x throughput while using 75% memory than PHP 5.2. Wow. Let that settle in and keep reading this wiki, why wouldn't you want to install HHVM RIGHT THIS SECOND? Yes, PHP 5.2 is old, but still, speed aside, 75% reduction in memory usage is amazing.
  • Compared to PHP 5.5 with opcache enabled, HHVM still performs nearly two times faster.

How does HHVM work?

HHVM parses PHP code and converts it into untyped bytecode and metadata. From there a bunch of crazy things happen and that bytecode is turned into machine code. This means the CPU can execute code waaay faster than using PHP's interpreter. HHVM's JIT compiler translates small amount of bytecode at a time, it reads the code and learns about what is going on and what might happen next. This is basically what happened in The Matrix and we are probably all gonna be killed by robots soon.

  • HHVM is able to detect when a file changes and will automatically handle changes so you can still quickly edit PHP code without having to tell HHVM that you changed something because JIT.

HHVM currently supports Wordpress, Mediawiki, Magento and Drupal.

How to install HHVM and Apache on Ubuntu 15.04

Step 1) Install Apache with the Event MPM, enable fastcgi, alias and proxy.

apt-get install apache2 apache2-mpm-event apache2-utils libapache2-mod-fastcgi
a2enmod actions fastcgi alias proxy_fcgi
service apache2 reload

Step 2) Install HHVM

sudo apt-get install software-properties-common
sudo apt-key adv --recv-keys --keyserver hkp://keyserver.ubuntu.com:80 0x5a16e7281be7a449
sudo add-apt-repository 'deb http://dl.hhvm.com/ubuntu vivid main'
sudo apt-get update
sudo apt-get install hhvm

Step 3) Configure HHVM to work with Apache using the install_fastcgi script (which is awesomesauce!) If you notice any errors in the output, or missing Apache modules, please be sure to install / enable the modules, otherwise HHVM and Apache won't work together.

sudo /usr/share/hhvm/install_fastcgi.sh
service hhvm restart
service apache2 restart

Step 4) Update hhvm_proxy_fcgi.conf to proxy /var/www/html/ instead of just /var/www/. This step is optional, but if you plan on using vhosts you will want to adjust this line to point to the www root for your site.

vim /etc/apache2/mods-enabled/hhvm_proxy_fcgi.conf
ProxyPassMatch ^/(.+\.(hh|php)(/.*)?)$ fcgi://$1

Change to:

ProxyPassMatch ^/(.+\.(hh|php)(/.*)?)$ fcgi://$1
service apache2 restart

Step 5) Test out HHVM and Apache

vim /var/www/html/test.php

echo  defined('HHVM_VERSION')?'Using HHVM':'Not using HHVM';
chown www-data. /var/www/html/test.php

The page should load in your browser and it should say “Using HHVM”. Congrats!

Step 6) Install WordPress because why wouldn't you?

cd /var/www/html
wget https://wordpress.org/latest.zip
unzip latest.zip
chown -R www-data. wordpress/

You may need to install mysql-server, if you already have mysql installed simply create the database and user.

apt-get install mysql-server

CREATE USER 'wordpress'@'localhost' IDENTIFIED BY '$PASSWORD';

In your browser, visit http://$IP/wordpress/

Enter in the database info and complete the installation. Go ahead and test out your site using gtmetrix.com or webpagetest.org and bask in the glory of having a fast wordpress site!

How to install HHVM on Ubuntu 14.10

Install Apache if you don't have it installed already.

apt-get install apache2 apache2-utils apache2-mpm-event

Install HHVM, if you are using something other than Ubuntu 14.10, replace "utopic" on the second line with whatever silly name your Ubuntu Version should be.

apt-key adv --recv-keys --keyserver hkp://keyserver.ubuntu.com:80 0x5a16e7281be7a449
add-apt-repository 'deb http://dl.hhvm.com/ubuntu utopic main'
apt-get update
apt-get install hhvm

HHVM has a nice configuration script which will enable Apache to use HHVM for PHP / Hack files. Run the script then restart hhvm and apache.

/etc/init.d/hhvm restart
/etc/init.d/apache2 restart

You should probably make sure HHVM starts up after reboot if you plan on using this in a production enviroment

update-rc.d hhvm defaults

I found that the default line in hhvm_proxy_fcgi.conf did not work for my configuration since I have other vhosts than the default one. You will want to update this file with the location of your site otherwise you might get a "File not found" error, or something like that.

vim /etc/apache2/mods-available/hhvm_proxy_fcgi.conf

ProxyPassMatch ^/(.+\.(hh|php)(/.*)?)$ fcgi://$1

##Modified for a specific vhost##
ProxyPassMatch ^/(.+\.(hh|php)(/.*)?)$ fcgi://$1

I suggest using the latest version of MariaDB for your database, installation is rather easy, just run the commands below.

apt-get install software-properties-common
apt-key adv --recv-keys --keyserver hkp://keyserver.ubuntu.com:80 0xcbcb082a1bb943db
add-apt-repository 'deb http://ftp.utexas.edu/mariadb/repo/10.0/ubuntu utopic main'
apt-get update
apt-get install mariadb-server

HHVM Configuration Files

The configuration file is read when HHVM starts up, if you are running HHVM in server mode this only happens once.

vim /etc/hhvm/php.ini

HipHop VM 3.4.2 comes with these settings by default, which can be found in /etc/hhvm/php.ini

; php options
session.save_handler = files
session.save_path = /var/lib/php5
session.gc_maxlifetime = 1440

; hhvm specific 
hhvm.log.level = Warning
hhvm.log.always_log_unhandled_exceptions = true
hhvm.log.runtime_error_reporting_level = 8191
hhvm.mysql.typed_results = false

HipHop VM 3.4.2 also comes with these server settings by default, which can be found in /etc/hhvm/server.ini

; php options

pid = /var/run/hhvm/pid

; hhvm specific 

hhvm.server.port = 9000
hhvm.server.type = fastcgi
hhvm.server.default_document = index.php
hhvm.log.use_log_file = true
hhvm.log.file = /var/log/hhvm/error.log
hhvm.repo.central.path = /var/run/hhvm/hhvm.hhbc

To pass along the config file location when running HHVM use the "-c" option with the path to the .ini

Inside the ini file you can pass along environment variables if you wish

; PHP_MEMORY_LIMIT is taken from environment
memory_limit = ${PHP_MEMORY_LIMIT}

You can also set values like you normally would

register_globals = off
track_errors = yes


Below are the various modes and what they mean. See the link above for more detail

PHP_INI_USER 	Entry can be set in user scripts (like with function ini_set()).
PHP_INI_PERDIR 	Entry can be set in php.ini, .htaccess, httpd.conf or .user.ini (since PHP 5.3)
PHP_INI_SYSTEM 	Entry can be set in php.ini
PHP_INI_ALL 	Entry can be set anywhere

You can use Zend Extensions with HHVM, but you must enable the compatibility layer in the ini file

vim /etc/hhvm/php.ini

hhvm.enable_zend_compat = true


HHVM server.ini settings

http://docs.hhvm.com/manual/en/ini.list.php https://github.com/facebook/hhvm/wiki/INI-Settings

This is an example configuration file for running HHVM in daemon mode.

vim /etc/hhvm/server.ini

hhvm.server.port = 9001
hhvm.server.host = localhost
hhvm.server.ip =
hhvm.server.type = fastcgi
hhvm.log.file = /var/log/hhvm.log

HHVM PHP Configuration Options and Info


HHVM phpinfo

This is an example of what a phpinfo file looks like using HHVM


// Show all information, defaults to INFO_ALL

// Show just the module information.
// phpinfo(8) yields identical results.





This sets the maximum time that a script is allowed to live (in seconds). If this limit is reached the parser will terminate the script. Keep in mind that Apache has a timeout setting as well which defaults to 300 seconds, so you may want to adjust both values to something that makes sense.

max_execution_time 30 

This time does not include waiting for external services like MySQL. This value only affects the execution time of the script itself. For more information check out this link: http://docs.hhvm.com/manual/en/function.set-time-limit.php


Sets the max time that a script is allowed to parse input data like post or get. This time is measured as soon as all the data is received on the server to the start of script execution.

max_input_time $N

Getting HHVM and Apache to work together

Make sure this mod is loaded and enabled

a2enmod proxy_fcgi

Modify vhost to include this line

vim /etc/apache2/sites-enabled/000-default.conf

ProxyPassMatch ^/(.*.php(/.*)?)$ fcgi://$1

How to run HHVM in a Ubuntu docker container on cPanel

Install Docker

Grab a repo, install it, then install docker, start the service and enable Docker to start on reboot.

wget http://mirrors.liquidweb.com/fedora-epel/6/i386/epel-release-6-8.noarch.rpm
rpm -i epel-release-6-8.noarch.rpm
yum install docker-io
service docker start
chkconfig docker on

HHVM Dockerfile

Make a new directory some where and create a file called Dockerfile. This file will contain all the instructions needed to build a docker container that will have HHVM.

mkdir /root/dockerfile
cd /root/dockerfile
vim Dockerfile

##Add this##

FROM ubuntu:14.04

RUN apt-get update ; apt-get install supervisor vim wget mysql-client -y ; wget -O - http://dl.hhvm.com/conf/hhvm.gpg.key | sudo apt-key add - ; echo deb http://dl.hhvm.com/ubuntu trusty main | sudo tee /etc/apt/sources.list.d/hhvm.list ; apt-get update -y ; apt-get install hhvm -y

ADD supervisord.conf /etc/supervisor/conf.d/supervisord.conf

RUN service supervisor start

ADD run.sh /run.sh

RUN chmod a+x /run.sh

EXPOSE 9000:9000

ENTRYPOINT ["/run.sh"]


In the same directory as Dockerfile, create a file called supervisord.conf. This file lets supervisor know what services to keep running, in this case we are just worrying about hhvm. MAKE SURE TO CHANGE directory=/$path/$to/$/www. If you want to use HHVM for a specific cPanel account then you would use something like "/home/$user/public_html/".

vim supervisord.conf

##Add this##


serverurl=unix:///var/tmp/supervisor.sock ; use a unix:// URL for a unix socket

command=hhvm -m daemon -vServer.Type=fastcgi -vServer.Port=9000 


In the same directory as Dockerfile, create a file called run.sh


set -e -x
echo "starting supervisor in foreground"
supervisord -n

Building the docker container

At this point you should have 3 files in your directory


To build the container use the command below. This tells docker to build a container using the Docker file located in "." which is the working directory. You can replace "hhvm" with whatever you want to call the container.

docker build -t hhvm .

It should take a few minutes to build the container, if something failed you will know it, otherwise docker should build the container without issue.

Start Up HHVM Docker Container

At this point you should be able to run the container. Make sure you open port 9000 in the firewall. The -d flag tells the container to run in daemon mode. -v tells the container that I want to mount /home/$user/public_html from the host, and mount it inside the container as /home/$user/public_html. Change this location with wherever your www/ is.

docker run -d -v /home/$user/public_html:/home/$user/public_html -p 9000:9000 hhvm

Configure cpanel vhost(s) to use mod_proxy_fcgi

If you have not already enable fcgid using /scripts/easyapache please do so now. Make sure Mod FastCGI is selected. Once EA is done you will want to modify the vhost.

Now we need to update httpd.conf and add a few lines that will tell Apache to send php processing over to HHVM in the container. Find the vhost you want to modify and make sure you add the lines in the <VirtualHost> SECTION </VirtualHost>. I placed the block right under the "UserDir" line. Please replace "$docker_container_IP" with the IP of the docker container. You can find out what that is my running docker inspect $container_ID.

vim /usr/local/apache/conf/httpd.conf

        <IfModule mod_proxy_fcgi.c>
                ProxyPassMatch ^/(.*\.php(/.*)?)$ fcgi://$docker_container_IP:9000/home/$user/public_html/


Save the file and restart apache.

Allow remote DB access on cPanel

Since PHP will now run inside the container you need to grant permissions for the container IP in mysql. You can do this via CLI or use WHM. Every app is different but you should be able to figure out what needs to be updated.

HHVM CentOS 6.5 / 6.6

This section is still in the works.

boost 1.54

[download them here]

Grab a few files

wget http://yum.gleez.com/6/x86_64/boost-static-1.54.0-9.el6.x86_64.rpm
wget http://yum.gleez.com/6/x86_64/boost-devel-1.54.0-9.el6.x86_64.rpm
wget http://yum.gleez.com/6/x86_64/boost-1.54.0-9.el6.x86_64.rpm
wget http://yum.gleez.com/6/x86_64/boost-atomic-1.54.0-9.el6.x86_64.rpm
wget http://yum.gleez.com/6/x86_64/boost-chrono-1.54.0-9.el6.x86_64.rpm
wget http://yum.gleez.com/6/x86_64/boost-context-1.54.0-9.el6.x86_64.rpm
wget http://yum.gleez.com/6/x86_64/boost-date-time-1.54.0-9.el6.x86_64.rpm
wget http://yum.gleez.com/6/x86_64/boost-filesystem-1.54.0-9.el6.x86_64.rpm
wget http://yum.gleez.com/6/x86_64/boost-graph-1.54.0-9.el6.x86_64.rpm
wget http://yum.gleez.com/6/x86_64/boost-graph-mpich2-1.54.0-9.el6.x86_64.rpm
wget http://yum.gleez.com/6/x86_64/boost-graph-openmpi-1.54.0-9.el6.x86_64.rpm
wget http://yum.gleez.com/6/x86_64/boost-iostreams-1.54.0-9.el6.x86_64.rpm
wget http://yum.gleez.com/6/x86_64/boost-locale-1.54.0-9.el6.x86_64.rpm
wget http://yum.gleez.com/6/x86_64/boost-log-1.54.0-9.el6.x86_64.rpm
wget http://yum.gleez.com/6/x86_64/boost-math-1.54.0-9.el6.x86_64.rpm
wget http://yum.gleez.com/6/x86_64/boost-mpich2-1.54.0-9.el6.x86_64.rpm
wget http://yum.gleez.com/6/x86_64/boost-mpich2-devel-1.54.0-9.el6.x86_64.rpm
wget http://yum.gleez.com/6/x86_64/boost-mpich2-python-1.54.0-9.el6.x86_64.rpm
wget http://yum.gleez.com/6/x86_64/boost-openmpi-1.54.0-9.el6.x86_64.rpm
wget http://yum.gleez.com/6/x86_64/boost-openmpi-devel-1.54.0-9.el6.x86_64.rpm
wget http://yum.gleez.com/6/x86_64/boost-openmpi-python-1.54.0-9.el6.x86_64.rpm
wget http://yum.gleez.com/6/x86_64/boost-program-options-1.54.0-9.el6.x86_64.rpm
wget http://yum.gleez.com/6/x86_64/boost-python-1.54.0-9.el6.x86_64.rpm
wget http://yum.gleez.com/6/x86_64/boost-random-1.54.0-9.el6.x86_64.rpm
wget http://yum.gleez.com/6/x86_64/boost-regex-1.54.0-9.el6.x86_64.rpm
wget http://yum.gleez.com/6/x86_64/boost-serialization-1.54.0-9.el6.x86_64.rpm
wget http://yum.gleez.com/6/x86_64/boost-signals-1.54.0-9.el6.x86_64.rpm
wget http://yum.gleez.com/6/x86_64/boost-system-1.54.0-9.el6.x86_64.rpm
wget http://yum.gleez.com/6/x86_64/boost-test-1.54.0-9.el6.x86_64.rpm
wget http://yum.gleez.com/6/x86_64/boost-thread-1.54.0-9.el6.x86_64.rpm
wget http://yum.gleez.com/6/x86_64/boost-timer-1.54.0-9.el6.x86_64.rpm
wget http://yum.gleez.com/6/x86_64/boost-wave-1.54.0-9.el6.x86_64.rpm

Just install a few packages...

yum install mpich-devel.x86_64 mpich-devel.i686 mpich2-devel.i686 mpich2-devel.x86_64 mpich.i686 mpich.x86_64 mpich2.i686 mpich2.x86_64 libibverbs.x86_64 libibverbs.i686 libipathverbs-static.x86_64 libibverbs-utils.x86_64 libibverbs-devel-static.x86_64 libibverbs-devel.x86_64 libibverbs-devel.i686 opensm-devel.i686 opensm-devel.x86_64 opensm-libs.i686 opensm-libs.x86_64 opensm-static.x86_64 compat-opensm-libs.i686 compat-opensm-libs.x86_64 opensm.x86_64 opensmtpd.x86_64 papi-devel.i686 papi-devel.x86_64 papi-static.x86_64 papi-testsuite.x86_64 papi.i686 papi.x86_64 librdmacm-devel.i686 librdmacm-devel.x86_64 librdmacm-static.x86_64 librdmacm-utils.x86_64 librdmacm.i686 librdmacm.x86_64 plpa-libs-1.3.2-2.1.el6.x86_64 libesmtp-1.0.4-15.el6.x86_64 libicu-devel-4.2.1-9.1.el6_2.x86_64

Grab these packages and try and install, you will run into dependency hell but all the files should be listed here.

wget ftp://rpmfind.net/linux/centos/6.6/os/x86_64/Packages/compat-openmpi-1.4.3-1.2.el6.x86_64.rpm
wget ftp://rpmfind.net/linux/centos/6.6/os/x86_64/Packages/openmpi-1.8.1-1.el6.x86_64.rpm
wget ftp://ftp.pbone.net/mirror/ftp5.gwdg.de/pub/opensuse/repositories/home:/kleinrob:/ofed35/CentOS_CentOS-6/x86_64/infinipath-psm-3.1-366.1.x86_64.rpm
wget http://mirror.centos.org/centos/6/os/x86_64/Packages/mpich2-1.2.1-2.3.el6.x86_64.rpm

rpm -iv openmpi-1.8.1-1.el6.x86_64.rpm
rpm -iv infinipath-psm-3.1-366.1.x86_64.rpm
rpm -iv compat-openmpi-1.4.3-1.2.el6.x86_64.rpm
rpm -iv mpich2-1.2.1-2.3.el6.x86_64.rpm

Now we can finally install boost

rpm -iv boost*.rpm

Cool, got boost installed! Yay, should be able to install HHVM? LOL hell no

wget http://yum.gleez.com/6/x86_64/hhvm-3.5.0-4.el6.x86_64.rpm
rpm -iv hhvm-3.5.0-4.el6.x86_64.rpm


yum install ilmbase-1.0.1-6.1.el6.x86_64 OpenEXR-libs-1.6.1-8.1.el6.x86_64 libxslt-1.1.26-2.el6_3.1.x86_64
yum install inotify-tools-3.14-1.el6.x86_64 lcms2-2.3-2.el6.x86_64 libvpx-1.3.0-5.el6_5.x86_64
yum install libyaml-0.1.3-1.4.el6.x86_64


wget ftp://ftp.pbone.net/mirror/dl.iuscommunity.org/pub/ius/development/Redhat/6/x86_64/mysql56-libs-5.6.10-2.ius.el6.x86_64.rpm
rpm -iv --replacefiles mysql56-libs-5.6.10-2.ius.el6.x86_64.rpm


wget http://yum.gleez.com/6/x86_64/hhvm-3.5.0-4.el6.x86_64.rpm
rpm -iv hhvm-3.5.0-4.el6.x86_64.rpm

How to run HHVM inside CentOS 7 Docker on cPanel

These instructions work on CentOS 6.6 running cPanel/WHM 11.48

Manual Steps

First you need to install the epel repo, then once the repo is installed, install docker-io. Docker will not start up after the installation by default so you need to actually start docker before you can use it.

wget http://mirrors.liquidweb.com/fedora-epel/6/x86_64/epel-release-6-8.noarch.rpm
rpm -i epel-release-6-8.noarch.rpm
yum install docker-io
service docker start
chkconfig docker on

Once docker is up and running use the pull command to grab the latest version of CentOS (CentOS 7). You can either enter the container via bash and run the commands manually to compile HHVM, or you can make a docker file and automate the build process. For this example I'll cover how to manually do this first, and will include a docker file at the end for ease of use.

docker pull centos:latest
docker run -i -t centos:latest bash

The rest of the steps are almost the same as what you can find here, but I've added a few packages that are needed (like make) that the github page doesn't include - https://github.com/facebook/hhvm/wiki/Building-and-installing-hhvm-on-CentOS-7.x

These commands need to be run inside of the container, if you used the last docker run command you should already be inside the container

Grab the CentOS 7 epel repo and remi repo and install them

rpm -Uvh http://dl.fedoraproject.org/pub/epel/7/x86_64/e/epel-release-7-5.noarch.rpm
rpm -Uvh http://rpms.famillecollet.com/enterprise/remi-release-7.rpm

Install a ton o packages that are needed for HHVM

yum install -y make cpp gcc-c++ cmake git psmisc {binutils,boost,jemalloc}-devel \
{sqlite,tbb,bzip2,openldap,readline,elfutils-libelf,gmp,lz4,pcre}-devel \
lib{xslt,event,yaml,vpx,png,zip,icu,mcrypt,memcached,cap,dwarf}-devel \
{unixODBC,expat,mariadb}-devel lib{edit,curl,xml2,xslt}-devel \
glog-devel oniguruma-devel inotify-tools-devel ocaml

Remove ImageMagick, then install it again, but this time using the remi repo which contains updated versions of software.

yum remove ImageMagick
yum install -y ImageMagick-last\* --enablerepo=remi

Change directories into tmp, use git to clone the lastest hhvm stuff

cd /tmp
git clone https://github.com/facebook/hhvm -b master  hhvm  --recursive

While in tmp, change directories into the new hhvm directory (located in /tmp/). Run the cmake command, once that is done run make install and at this point HHVM should be ready to go

cd hhvm

cmake \
-DLIBMAGICKWAND_INCLUDE_DIRS="/usr/include/ImageMagick-6" \
-DLIBMAGICKCORE_LIBRARIES="/usr/lib64/libMagickCore-6.Q16.so" \
-DLIBMAGICKWAND_LIBRARIES="/usr/lib64/libMagickWand-6.Q16.so" .
make -j$(($(nproc)+1))

make install

To confirm that HHVM is working run this command

hhvm version

To exit the container without killing it off, press Ctrl + p + q.

You should now be outside the container. Use Docker ps to list the running container, note the CONTAINER ID

docker ps

To commit / save this container:

docker commit $CONTAINER_ID centos_hhvm

Now that the container has been commited you can stop, start, or create multiple containers if you wish.

HHVM Links and Videos

HHVM, the new PHP?


CppCon 2014: Drew Paroski "How HHVM Uses Modern C++ for Fun and Profit (Literally)"


HHVM Supported Frameworks


HHVM Heroku


HHVM Performance Tests