The Need for Speed: Profiling PHP with XHProf and XHGui

Share this article

While patience is a virtue, it’s generally not one inherent to today’s society when it comes to waiting for web pages to load. Studies conducted by big names in technology like Google, Microsoft, and Yahoo! have shown that even sub-second differences in page load time can have significant impact on conversions. If that’s not enough reason, Google incorporated page load time into their search rankings back in April 2010, so it also impacts SEO. A number of factors can affect page load time: network latency, web server configuration or load, use of persistent storage, caching or lack thereof, and application response time. In general, application response time should be suspected and dealt with last as it’s a less common culprit than database servers or handling of static assets and efforts to tune it usually have a lower ROI. However, knowing how to locate issues affecting application performance – often called bottlenecks – is a good skill to have should you ever be required to do so. Profiling is the process of measuring the execution time of each function or method call involved in servicing a single page request. The data collected from this process can reveal issues such as a particular method taking a long time to execute or being called a large number of times. Profiling a PHP script generally requires installing a PHP extension. The two more popular extensions for this purpose are Derick RethansXdebug and Facebook’s XHProf. This article will focus on XHProf.

Installing XHProf

XHProf is available via PECL, so installing it is pretty easy. For example, it can be installed with the following on Debian-based systems:
sudo pecl install xhprof-beta
echo '' | sudo tee /etc/php5/conf.d/xhprof.ini >/dev/null
sudo apachectl restart
The raw profiling data generated by XHProf isn’t easily consumed at a glance. As such, an interface or visualization of some sort can be useful to view it. XHGui, a fork of XHProf, provides this. XHGui is hosted on GitHub, so you have two installation options. The first option involves using git to clone the repository, which provides an easy way to update it later.
git clone git://
If you prefer not to use git, the second option is to simply download and extract a tarball reflecting the repository’s current state like so:
wget -O xhgui.tar.gz && tar -zxf xhgui.tar.gz
At this point, you can use directions in the INSTALL file to guide you through the rest of the process for your particular server environment. The xhprof_html directory contains the index.php file to load the XHGui interface, so make sure your web server is configured to expose that path within your host’s document root using a symbolic link, an Alias directive, or something of that sort. SQL to create the database table used for storing profiling data is located in comment blocks at the top of the PHP files in the xhprof_lib/utils/Db directory. Use the file appropriate for your environment’s database server to create that database table, then add credentials to access it to the XHGui config.php file. If your web server is not running on your local host, don’t forget to add your local host’s IP address to the $controlIPs variable in the XHGui config.php file, else you’ll get an error message stating “You do not have permission to view this page.” Once all this is in place, XHGui should load successfully when you browse to it.

For more information on other configuration settings offered by XHGui, see the PHP Advent blog post
linked at the bottom of the INSTALL file. If you’re running XHGui in a development environment, one place where you can vary slightly from the instructions is in the directives to configure the auto_prepend_file PHP configuration setting. According to the PHP manual, this setting is configurable per directory, meaning you can use a .htaccess file rather than having to modify your virtual host configuration and bounce your web server if your application has a central endpoint for servicing requests. An example of this is shown below.
php_value auto_prepend_file "../../xhprof/external/header.php"
This setting executes the specified PHP file before any PHP file is served. This particular file enables collection of profiling data before the code to be profiled is executed and sets up a shutdown function to store that data once the code has completed its execution.

Profiling your Application

For the purposes of this article, the skeleton example application provided for use with Zend Framework 2 is used as the subject of profiling. The .htaccess file above is placed in that application’s public directory, which is configured as the host document root. To enable profiling for a particular URL, append _profile=1 to its query string. For example, the environment used in this article uses a hostname of zf2.local, making the URL to access the application with profiling enabled http://zf2.local/?_profile=1. This will set a cookie and then redirect back to the application with that query string variable removed; with the cookie in place, you won’t need to modify the query string to enable profiling for subsequent requests. Once the application request has completed, the profiling data will be stored in the database you configured XHGui to use. Simply refresh the XHGui interface and its data grid will list the new profiling run near the top. The data grid also has links for easy filtering of runs by time period, memory usage, runtime, server, and domain. Click the timestamp listed for a run and XHGui will display a page detailing the data collected during that run. The table on the top left displays aggregated statistics such as total runtime, memory usage, and function call count. The top right shows tables of GET, POST, and cookie data as well as a pie chart detailing expensive function calls made during the request. Scroll down and you’ll find a data grid listing functions and their corresponding statistics. If you’re profiling for runtime, the two columns you’ll generally want to focus on are labeled “Exclusive Wall Time” and “Call Count.” For memory usage, look at the columns labeled “Exclusive Memory Usage” and “Exclusive Peak Memory” Usage. Click on any grid column to sort the grid’s data by that column. Click on an individual function name to view a detail page that includes that function’s statistics as well as those of its parent functions (i.e. functions that call it) and child functions (i.e. functions that it calls).

Comparing Profiling Runs

The common use case for profiling is to profile an application, make a change to that application’s source code, and then profile it again to see what performance impact the change made. XHProf and XHGui were designed to make doing this fairly easy. Within XHGui, in the data grid for profiling runs, each run has a hash value shown underneath its timestamp. Choose one of two runs you’d like to compare and copy its hash value. Click the timestamp of the other run to bring up its detail page. Finally, at the bottom of the data table on the top left, enter the hash value into the text box labeled “Perform Delta” and hit the “Delta” button next to it. This displays a page where the run for which you entered the hash value is labeled “Run Two” and the run for which you viewed the detail page is labeled “Run One.” Like the detail page, it displays both aggregate statistics and statistics per function call. These function call statistics are computed by subtracting those for Run One from those for Run Two. For example, the “Wall Time” column value for the main() function row in the function statistics table corresponds to the difference of the values of the “Incl. Wall Time” cell for Run Two and Run One in the aggregated statistics tables.

It’s possible that you may profile an application twice without making any changes and see a significant difference in the two profiles. One possible reason for this is that PHP maintains its own stat cache of filesystem lookups to improve performance. To mitigate this difference in xhprof profiling runs, add a call to the clearstatcache function at the top of external/header.php in your XHGui installation.

Viewing Callgraphs

Another feature offered by XHGui is generation of callgraphs, directed graphs that show calls between functions and visually highlight function calls that take up a large amount of runtime. XHGui shells out to the dot graphviz utility to do this. Below is the command to install the package for this on Debian-based systems:
sudo apt-get install graphviz
Note that you also need to uncomment the block that looks like the one below in the XHGui config.php file or else XHGui will return a rather unintuitive error message in place of the callgraph. Thanks to a blog post by Lorna Jane Mitchell for pointing this out.
//These are good for linux and its derivatives.
$_xhprof['dot_binary']  = '/usr/bin/dot';
$_xhprof['dot_tempdir'] = '/tmp';
$_xhprof['dot_errfile'] = '/tmp/xh_dot.err';
Near the top of the detail page for an individual run or a difference between two runs, you’ll find a “View Callgraph” link. Clicking it will generate a call graph resembling the one shown below. Note that this may take a while for profile runs with a lot of function calls. You can also click on an individual function name and click the “View Callgraph” link on its detail page to view a callgraph specific to that function.

In Closing

I hope you’ve enjoyed this overview of the functionality that XHProf and XHGui provide and that it’s provided insight into the value of an effective profiling toolset. While your application layer may prove an infrequent cause of performance bottlenecks, you should now have the knowledge necessary to isolate their causes and take further steps to eliminate them. Image via Fotolia

Frequently Asked Questions about Profiling with XHProf and XHGui

What is the purpose of using XHProf and XHGui in PHP applications?

XHProf and XHGui are powerful tools used for profiling PHP applications. Profiling is a process that helps developers understand the runtime behavior of a program, particularly in terms of its performance. XHProf, a hierarchical profiler, provides detailed information about how the functions in your code are executed, including the memory used, CPU time consumed, and the number of times a function is called. XHGui, on the other hand, is a graphical interface for XHProf data, making it easier to understand and analyze the profiling data. These tools are essential for identifying bottlenecks in your code and optimizing it for better performance.

How do I install XHProf and XHGui on my server?

The installation process for XHProf and XHGui varies depending on your server’s operating system. For Ubuntu, you can use the PECL extension repository to install XHProf. Once XHProf is installed, you can clone the XHGui repository from GitHub and follow the provided instructions to set it up. Remember to configure your PHP settings to enable XHProf and set the output directory for your profiling data.

How do I use XHProf to profile my PHP application?

To use XHProf for profiling, you need to start and stop the profiler around the code you want to profile. You can do this by calling the xhprof_enable() function at the start and xhprof_disable() function at the end. The xhprof_disable() function returns the profiling data, which you can then save to a file or analyze using XHGui.

How can I interpret the results from XHProf?

XHProf provides a wealth of information about your code’s execution, including the total time taken, memory used, and the number of function calls. Each function call is also broken down into inclusive and exclusive metrics. Inclusive metrics include the time taken by the function itself and all the functions it calls, while exclusive metrics only consider the time taken by the function itself. By analyzing these metrics, you can identify which parts of your code are consuming the most resources and need optimization.

How does XHGui help in analyzing XHProf data?

XHGui provides a graphical interface for XHProf data, making it easier to understand and analyze. It presents the profiling data in a hierarchical format, showing the relationship between different function calls. It also provides various filters and sorting options to help you focus on the most critical parts of your code. With XHGui, you can easily identify bottlenecks and performance issues in your PHP application.

Can I use XHProf and XHGui for profiling applications in other programming languages?

XHProf and XHGui are specifically designed for profiling PHP applications. However, similar tools are available for other programming languages. For example, Python has cProfile and Py-Spy, while Ruby has ruby-prof and StackProf.

Are there any alternatives to XHProf and XHGui for profiling PHP applications?

Yes, there are several other tools available for profiling PHP applications, such as Blackfire, Tideways, and Zend Debugger. Each tool has its own strengths and weaknesses, so the best choice depends on your specific needs and preferences.

How can I optimize my PHP application based on the profiling data from XHProf and XHGui?

The profiling data from XHProf and XHGui can help you identify the parts of your code that are consuming the most resources. Once you’ve identified these bottlenecks, you can focus on optimizing them. This could involve rewriting inefficient code, reducing unnecessary function calls, or optimizing database queries. Remember, optimization is an iterative process, so you should continue profiling and optimizing your code until you’re satisfied with its performance.

Can XHProf and XHGui help me identify memory leaks in my PHP application?

Yes, XHProf provides detailed information about the memory usage of your PHP application, which can help you identify potential memory leaks. However, it’s important to note that XHProf is not a dedicated memory leak detector, and some memory leaks may not be apparent from the profiling data alone. For more detailed memory analysis, you may need to use other tools like Valgrind or Memprof.

Are XHProf and XHGui suitable for profiling production applications?

While XHProf and XHGui can be used to profile production applications, it’s generally recommended to use them in a development or staging environment. Profiling can add significant overhead to your application, which can impact its performance. Therefore, it’s best to profile your application in an environment that mirrors your production environment as closely as possible, but without affecting your actual users.

Matt TurlandMatt Turland
View Author

Matthew Turland has been working with PHP since 2002. He has been both an author and technical editor for php|architect Magazine, spoken at multiple conferences including Confoo and php|tek, served as an instructor for php|architect training courses, and contributed to Zend Framework. He holds the PHP 5 and Zend Framework ZCE certifications and is the author of "php|architect's Guide to Web Scraping with PHP." He currently works as a Senior Engineer for Synacor. In his spare time, Matt likes to bend PHP to his will to scrape web pages and run IRC bots.

Share this article
Read Next
Get the freshest news and resources for developers, designers and digital creators in your inbox each week