Friday, March 20, 2015

Profiling PHP Applications with Xdebug and CacheGrind

Recently I worked on a project that required setting up a code profiler for PHP on Windows. In case you are interested in doing the same, here are some tips for you.

Prerequisites

- Working installation of PHP (version 5.2 or above)
- Apache or any other web server that runs together with the PHP installation (assuming you are profiling web pages).

Installation

Step 1: Download the correct Xdebug DLL from http://xdebug.org/download.php. Note that you have to download a DLL that matches your version and architecture of PHP, This information you can get from the output of phpinfo.

Step 2: Save the DLL to a reasonable location (e.g. somewhere near or in the PHP installation directory). As this is not a PHP module, this does not have to be the PHP's extensions directory.

Step 3: Configure the php.ini file (in your PHP installation folder):
zend_extension = "[the location of the xdebug dll]\php_xdebug-2.2.7-5.3-vc9.dll"

[XDebug]
; this turns off the profiler by default:
xdebug.profiler_enable=0
; this makes the profiler overwrite, rather than append to profiling output
; (i.e. only the profile of the last request will be stored in output)
xdebug.profiler_append=0
; this enables reading a GET/POST/COOKIE parameter named XDEBUG_PROFILE to profile a specific request
xdebug.profiler_enable_trigger=1
xdebug.profiler_output_dir="[Path where to store the profiler output]"

If everything succeeded, then after restarting Apache, there should be an Xdebug section in the output of phpinfo() and the phrase "with Xdebug ..." next to the Zend framework logo. If this is not so, verify that the path to the DLL is correct and that the DLL matches the version of your PHP installation.
More parameters to play with can be found on the documentation page of Xdebug. In general, if you want to profile just one specific HTTP request, it makes more sense to use the profiler_enable_trigger=1 parameter, with profiler_enable=0, so that you can pinpoint the exact request by adding an XDEBUG_PROFILE=1 parameter to the request. On the other hand, to get the total profiling output for a series of requests, you should set profiler_append=1 and possibly profiler_enable=1 (or XDEBUG_PROFILE=1 in a cookie) to get a cumulative profile of multiple queries in a row.
Note that by default, Xdebug writes the output to a single file, called cachegrind.out.[process ID].

Step 4: Install QCacheGrind. This one is a lovely Windows port of the KCacheGrind tool that allows you to analyze the profiling output. Documentation on how to use it is available at http://kcachegrind.sourceforge.net/html/Documentation.html.

Keep in mind that the profiling output can grow very fast if the profiler is constantly on. With QCacheGrind, there seems to be an upper bound to the number of profiles that are stored in one output file - from some point on, the tool tends to crash without warning. So, keep your profiling output lean or distribute it to separate files (see http://xdebug.org/docs/all_settings#profiler_output_name).

Step 5: Success! Profiling should now be enabled.