Benjamin Benjamin 08.09.2014

Improving XHProf further

The information from this post is not up to date. We have setup a dedicated page for the Tideways PHP Extension - our XHProf fork with PHP 5.5, PHP 5.6 support and better performance.

Almost a month passed since our last blog post on the XHProf extension and we are happy to announce more improvements today that were necessary to improve the experience and performance of the Profiler. We released all this as v0.9.7 of XHProf.

Skipping userland functions

XHProf ships with a flag called XHPROF_FLAGS_NOBUILTIN which ignores all builtin functions during profiling by not overwriting the Zend Engine hook. This is a very efficient mechanism to save a lot of performance, however the other way around is much more interesting, skipping userland functions.

We have introduced a new flag XHPROF_FLAGS_NOUSERLAND that does just that, ignoring all userland functions during profiling by not hooking into zend_execute.

New "layer" profiling mode

When using XHProf for permanent production profiling, a full trace for every request is just a waste of CPU cycles. To get an overview of the performance using the average response times of different layers such as I/O, database, cache and HTTP is just enough.

With support for XHPROF_FLAGS_NOUSERLAND and the function whitelist we have added a third feature called layers that is both available in normal xhprof_enable() as an option but also with a dedicated call xhprof_layers_enable():

<?php

xhprof_layers_enable(array("mysql_connect" => "db", "mysql_query" => "db"));

mysql_connect();
mysql_query("SELECT 'hello world'");

$data = xhprof_disable();

printf("%d calls with a total of %d ms", $data['db']['ct'], $data['db']['wt'] / 1000);

Fatal error traces

For our error collecting feature we have missed traces for fatal errors from the beginning. Adding a new function xhprof_last_fatal_error() you are now able to access the trace inside a register shutdown handler.

The output is the same as error_get_last() with a new key "trace". It also formats uncaught exception error fatals a little differently by using the exception class as "type".

This function only works when called after either xhprof_enable() or xhprof_layers_enable() and before xhprof_disable(), because it overwrites PHPs error callback only in this case.

Stopping a trace unified

In Facebooks xhprof you could call both xhprof_disable and xhprof_sample_disable to stop the profiling. Because internally xhprof uses a lot of global state, we had to unify this approach to work with a single function only, xhprof_disable, to avoid bugs when calling the wrong disable method.

Testing the changes

This time you can easily test everything as well, we have pre-compiled the extension for 64bit Linux for PHP 5.3, 5.4 and PHP 5.5. This is still considered beta and you should expect it to segfault in some cases. The code is provided AS IS with no warranty that it works on your machines, please don't use it in production yet.

If you want to compile it yourself, see the Github repository. Make sure to copy ext/curl/php_curl.h from the php-src to your PHP's include directory otherwise it won't compile.

Our first experiments with PHP 5.6.0 show that XHProf is not compatible out of the box. We are working on fixing them as soon as possible.

Outlook

With this milestone we are working on stabilizing all our changes to XHProf and focussing on the Profiler UI again. The layer and argument functionality is already integrated, but there is still a lot of room for improvement.

After this round of changes we will also be looking at activating new beta testers. In the current closed beta, our users have already created 56 applications that transmit a total of 2.5 million requests a day which has already required us to dedicate some time to scaling, which is why we haven't added a lot more beta testers yet.