Skip to content

Performance Tuning

Josh Watzman edited this page May 22, 2015 · 7 revisions

This page will be a collection of wisdoms about how to get even more speed out of HHVM if you're willing to put some effort in. The percentages are just empirically what average speedups people have seen.

You may also want to look into profiling and optimizing the code actually running on HHVM.

Use RepoAuthoritative - 20%

Normally, when HHVM receives a request, it dynamically finds the source code, compiles it and any files it requires on the fly, and then executes them. This is a good flow for development. However, if HHVM can know ahead-of-time what files exist, it can do some precomputation and apply a lot of optimizations that are impossible without ahead-of-time knowledge of all source code. Such optimizations include function inlining (which requires knowing the inlined function won't change), optimizations to the memory layout of objects (which benefits from knowing what member variables may be defined), and many more.

Enabling RepoAuthoritative mode involves pre-compiling all of your source code into a bytecode repo. HHVM then consults only this repo, and not your source code, when servicing web requests. This comes with an often dramatic performance improvement due to the optimizations involved, but means that changes to source code won't take effect until the repo is rebuilt.

Since it's made a bunch of assumptions about what code exists, eval and create_function do not work in RepoAuthoritative mode.

Easy Way

As of HHVM 3.8, we provide a shell script to make this easy. To enable RepoAuthoritative mode use the hhvm-repo-auth script provided with our Debian and Ubuntu packages. Give it the enable command, followed by the path to your project's source code root -- probably /var/www or /usr/share/nginx/html. It will compile the repo, change the relevant HHVM configuration, and restart HHVM all automatically. (Since it changes HHVM configuration, you will probably need to be root to run it.) An example invocation might look like:

sudo hhvm-repo-auth enable /var/www

To disable:

sudo hhvm-repo-auth disable

Manual Way

Although the above script is easy, for more advanced HHVM deployments, the recommended way to use RepoAuthoritative mode is to develop with it disabled, and then to build and deploy a repo, not source code, to production machines.

If you have PHP files file1.php and file2.php, you can build a bytecode archive named hhvm.hhbc by executing this command:

hhvm --hphp -thhbc -o some_dir file1.php file2.php

Now you will have a pre-compiled repo file named some_dir/hhvm.hhbc. The file hhvm.hhbc is actually an sqlite database file - you can even view the structure of the file using sqlite. This is similar to a java .jar or a python .par file. It is a stand-alone version of your scripts. To run the program file1.php, use this command:

hhvm -vRepo.Authoritative=true -vRepo.Central.Path=some_dir/hhvm.hhbc file1.php

To run the program file2.php, use this command:

hhvm -vRepo.Authoritative=true -vRepo.Central.Path=some_dir/hhvm.hhbc file2.php

Note: If you get the error message Unable to find/load systemlib.php, make sure you are pointing at the hhvm.hhbc file and not the directory.

Warm up your server - 10%

The cache locality of the JITted code is very important, and you want all your important endpoints code to be located close to each other in memory. The best way to accomplish this is to pick your most important requests (say 5) and cycle through them all serially until you've done them all 12 times. Something like

for i in `seq 12`; do 
  while read url; do 
    curl "$url"
  done < important_urls.txt
done

Do this every time you startup the server before it sees user traffic.

TODO: HHVM has a "warmup requests" feature which can do this more effectively, and automatically. We should document it.

Clone this wiki locally