Advertisement
PHP

Advanced CodeIgniter Profiling With XHProf

by

There are a number of ways to profile and monitor the performance of PHP code in a development environment, but once it's been let loose on a production server its extremely difficult to know what's going on when your app is getting accessed by your users.

In March 2009, Facebook released XHProf, a function level profiler that allows you to identify bottlenecks in your application. And it runs on a production server with little overhead.

XHProf will provide you with a hierarchical profile of the functions your application calls, allowing you to follow the chain of events that lead up to resource intensive code running. You'll be able to see exactly how much wall time (the actual time elapsed), CPU time and memory your application uses.

This tutorial will help you get XHProf installed on your server, and integrated with your CodeIgniter application via hooks so that you can start profiling your application, in a production environment, straight away. Everything you see here was written for Ubuntu 10.04 - the latest LTS release at the time of writing.


Installation

Installation of XHProf can be done via PECL - that said, I've never been able to get the PECL version installed on Ubuntu easily so its easier to install from source. Start off by downloading the latest revision from the XHProf GitHub account.

  	wget https://github.com/facebook/xhprof/tarball/master -O xhprof.tar.gz

Extract the tarball and switch into the extracted folder - this will change depending on the latest revision available from GitHub.

	tar -xvf xhprof.tar.gz
	cd facebook-xhprof-bc8ef04/extension

Then install as normal.

	phpize
	./configure
	make
	sudo make install

Finally, we need to tell PHP to load the extension. Create a config file for it - I do this for cleanliness but you can always drop it at the end of your main php.ini.

	sudo nano /etc/php5/conf.d/xhprof.ini

And paste in the following:

	extension=xhprof.so
	xhprof.output_dir="/var/tmp/xhprof"

This tells XHProf to use the directory at /var/tmp/xhprof to save its run data.

You can check whether XHProf is installed correctly by entering php -m at the command line and checking that the module is available. Remember to restart Apache so that it gets picked up in your PHP web applications as well.

If you want to render the callgraph images you'll also need the graphviz package. This can be obtained from apt.

	sudo apt-get install graphviz

Integration With CodeIgniter

XHProf can be used on an ad-hoc basis to evaluate small pieces of code, but it's at its most useful when you let it profile the full page. First of all, you'll need to move the XHProf code into your web applications root so that it has access to the appropriate classes.

	sudo mv ~/facebook-xhprof-bc8ef04  /var/www/xhprof

CodeIgniter has an excellent mechanism for injecting custom code into the execution of a page called 'Hooks'. This is what we'll use to integrate XHProf with your application. Enable hooks in your application/config/config.php file.

	$config['enable_hooks'] = true;

Then specify your hooks in application/config/hooks.php

	$hook['pre_controller'] = array(
	  'class'  => 'XHProf',
	  'function' => 'XHProf_Start',
	  'filename' => 'xhprof.php',
	  'filepath' => 'hooks',
	  'params' => array()
	);

	$hook['post_controller'] = array(
		'class'  => 'XHProf',
		'function' => 'XHProf_End',
		'filename' => 'xhprof.php',
		'filepath' => 'hooks',
		'params' => array()
	);

Then create the hook that will load XHProf into your application at application/hooks/xhprof.php. This class will provide the necessary minimum to get XHProf collecting data from your application.

	class XHProf {

		private $XHProfPath = 'xhprof/';
		private $applicationName = 'my_application';
		private $sampleSize = 1;
		private static $enabled = false;

		public function XHProf_Start() {
			if (mt_rand(1, $this->sampleSize) == 1) {
				include_once $this->XHProfPath . 'xhprof_lib/utils/xhprof_lib.php';
				include_once $this->XHProfPath . 'xhprof_lib/utils/xhprof_runs.php';
				xhprof_enable(XHPROF_FLAGS_NO_BUILTINS);

				self::$enabled = true;
			}
		}

		public function XHProf_End() {
			if (self::$enabled) {
				$XHProfData = xhprof_disable();
		
				$XHProfRuns = new XHProfRuns_Default();
				$XHProfRuns->save_run($XHProfData, $this->applicationName);
			}
		}

	}

There's a few thing to point out in this code sample.

  • The $XHProfPath variable should point to the directory you installed XHProf in. In our example, we put it in the root of the web application, but you might be storing it somewhere central and symlinking it to multiple applications.
  • The $applicationName variable lets you specify the name of the application using XHProf. This could be especially important in an environment where you're running multiple applications on the same server.
  • The $sampleSize variable lets you specify a factor for how often XHProf profiles a run. In a production environment where you're receiving thousands of hits, it's probably not worth storing every single run. You can increase this variable to get a random sample of runs. Changing it to 10, for example, will give you a report from one in every 10 visits to your application.

The xhprof_enable() function can accept any combination of 3 constants.

  • XHPROF_FLAGS_NO_BUILTINS - skip all internal php functions. Adding this means you'll only see time spent in functions that you have written (or are part of CodeIgniter)
  • XHPROF_FLAGS_CPU - add additional CPU profiling information
  • XHPROF_FLAGS_MEMORY - add additional memory profiling information

Combine them using +. eg. xhprof_enable(XHPROF_FLAGS_NO_BUILTINS + XHPROF_FLAGS_MEMORY);

After running through your application a couple of times, point your browser at the XHProf application directory http://localhost/xhprof/xhprof_html/index.php - adjusting for the address of your development server - and you'll see a list of your last application runs with the newest at the top. Select one of the runs to see it's profiling information.


Evaluating the Results

Storing all this profiling information is all very well and good but knowing how to evaluate it is the key to optimising your application.

The 'Overall Summary' is a good place to start - it'll show you:

  • Total inclusive wall time - how long (in microseconds) it took for you page to be generated
  • Total memory use - the total memory used by this run of your application
  • Total peak memory use - the maximum amount of memory that was used by your application
  • Number of function calls - the number of functions that were called by your application
Run summary

These number should give you an overall base to start from and provide headline numbers to compare against when you start optimisation.

Below the summary is the detailed run report The bottlenecks in your application should be fairly obvious - they're the function calls at the top of the report.

Wall report

The most resource intensive things you're likely to come across will be those that make calls to external services or your database. By default, the results are sorted by 'inclusive wall time'. This shows the functions that took the longest to run by the cumulative total of them and the functions they call. Ordering by 'exclusive wall time' allows you to see the specific functions that are using the most amount of resource.

Clicking a function allows you to drill down into more detail about that function and the functions it called. From there, it'll be easier to see exactly what your long running function was doing and spot any issues.

When debugging your CodeIgniter application, one of the best places to start is the controller being called for your page - Welcome::index in the example. From there you can easily see the breakdown of where the controller spent most of it's time.

Controller summary

Callgraph

XHProf can generate a call graph view that provides a visual clue to the main path of your application. The main bottlenecks are highlighted in red to show where most your resources are being spent.

Callgraph

Comparing Runs

XHProf provides a mechanism for comparing multiple runs - this will allow you to make a number of optimisations and then see how they've affected your application.

http://localhost/xhprof/xhprof_html/index.php?run1=run_id_1>&run2=run_id_2&source=applicationName

Note: run_id_1 and run_id_2 should be the ids from some of your previous runs and applicationName should be the name you specified when setting up the hook earlier.

This will provide the same information you see in a regular report but provide percentage statistics on any changes since the first run, allowing you to easily see if your optimisations are moving your performance in the right direction.

Aggregating Runs

Sometimes a single run might not be enough to evaluate exactly what's going on. Pages my work slightly differently depending on the query string or user input or there might be differences in caching mechanisms.

Aggregating a number of runs allows you to combine a number of runs and receive an average of the resources consumed.

http://localhost/xhprof/xhprof_html/index.php?run=run_id,run_id,run_id&source=applicationName

Note: run_id should be the ids from some of your previous runs and applicationName should be the name you specified when setting up the hook earlier.


Summary

You should now have XHProf up and running in your CodeIgniter application and be able to see exactly where your code is spending most of it's time. Optimisation can be a difficult task. Sometimes it's not as simple as reimplementing a function, or adding a layer of caching. Thinking about why you're doing something and what the exact effect that is having on your application is just as important.

So let me know if you have any questions in the comments below. Thank you so much for reading!

Related Posts
  • Code
    Web Development
    How to Use New Relic With PHP & WordPressRelic retina preview
    Today we will look at how to monitor a PHP application using New Relic. More specifically we will set up a basic WordPress installation and get some performance data about it, in the New Relic dashboards.Read More…
  • Code
    WordPress
    An Introduction To Deploying WordPress with MinaImage400
    As a PHP application, WordPress is usually deployed by a very old method: uploading files via FTP. We have some deployment tools, but they often requires some type of Ruby skill. For example, one popular, powerful tool is Capistrano, but it's also very heavy with many Ruby/Rails related features. I also think that it's little bit tricky to install Capistrano for a PHP developer without any Ruby knowledge. So what options do we have as WordPress developers? In this tutorial, I will introduce you Mina: A small, light tool aims to fast deployment and server automation.Read More…
  • Code
    Web Development
    Laravel Unwrapped: Session, Auth and CacheLaravel wide retina preview
    Join me as we learn how to use Laravel's component-based system, Illuminate. Additionally, we'll see how to utilize service providers, Laravel's manager system, the Session, Auth, and Cache components, and the Store, Guard, and Repository libraries.Read More…
  • Code
    PHP
    Setting Up a Local Mirror for Composer Packages With SatisComposer retina preview
    Installing all your PHP libraries with Composer is a great way to save time. But larger projects automatically tested and run at each commit to your software version control (SVC) system will take a long time to install all the required packages from the Internet. You want to run your tests as soon as possible through your continuous integration (CI) system so that you have fast feedback and quick reactions on failure. In this tutorial we will set up a local mirror to proxy all your packages required in your project's composer.json file. This will make our CI work much faster, install the packages over the local network or even hosted on the same machine, and make sure we have the specific versions of the packages always available.Read More…
  • Computer Skills
    Electronics
    How to Install Alternative Web Browsers on the Raspberry PiPibrowser400
    If you are running the Raspian distro on your Raspberry Pi–and many people are–then the default web browser is probably your primary method for accessing webpages. In this tutorial, I’ll show you how you can optimise Midori and I’ll show you how to install some alternative web browsers and explain why you might want to use them.Read More…
  • Code
    Tools & Tips
    New Relic & JMeter - Perfect Performance TestingGetting started new relic retina preview
    Following on from the great introductory articles featured recently on Nettuts+, this article looks to show how you can take New Relic to the next level. As a performance monitoring tool New Relic is fantastic, but what about performance testing, before you go live. That's where JMeter comes in to play. In this tutorial, you will see how we can stress test our application under realistic load, and combine the output of JMeter and New Relic to give you confidence in your applications performance, before releasing into a production environment.Read More…