Home > PHP/MySQL > Benchmarking Autoload Performance In PHP

Benchmarking Autoload Performance In PHP

by Sam on October 18, 2009 · 8 comments

in PHP/MySQL

I read a blog post a few days ago written by Brandon Savage outlining some of the more worthwhile optimizations one can make to their PHP code and application environment in order to improve performance. One of the optimizations suggested by Brandon is employing the use of an autoloader (for the uninitiated, you can read all about autoloading here). On reading through the comments, I noticed that there seemed to be some uncertainty as to how autoloading stacks up against the use of multiple include files as it relates to speed. After running a quick Google search on the topic, I realized that the uncertainty extended far beyond Brandon’s article. I decided then, to do some benchmarking of my own and post the results.

First of all, let me categorically state that for reasons which I’ll reveal in a later article, I don’t care very much for benchmarks. These tests were carried out merely out of academic interest. Secondly, I am a fan of anything which makes my life easier. Autoloading makes my life easier. Enough said.

The Machine

These tests were carried out on a Sony Vaio notebook with 4GB of RAM and a core 2 duo processor with each core running at 2.0Ghz. The software versions are listed below:

  • Windows 7 RC
  • PHP 5.3.0
  • Apache 2.2.12
  • eAccelerator 0.9.6 RC1

The Tests

Two sets of tests were carried out, one without opcode caching and one with opcode caching (courtesy of eAccelerator). Each set of tests include tests using multiple include() calls, tests using the SPL autoloader and tests using the __autoload magic function.

The Code

The code used to perform the tests is extremely simple. It consists of a timer class as defined below:

class Timer 
{ 
private $totalTime; 
public function startTimer() { 
	$this->totalTime = microtime(true); 
} 
public function stopTimer() { 
	$this->totalTime = round(microtime(true)-$this->totalTime,8); 
} 
public function getTime() { 
	return $this->totalTime; 
} 
}

As you can see, the Timer class has Timer::startTimer() and Timer::stopTimer() methods which start and stop the timer respectively. Calls to these methods envelop the code which we are evaluating, i.e. the multiple includes or our autoload functions:

$timer = new Timer;
$timer->startTimer();
 
//Code block used to test multiple includes.
include 'includes/dummy.class.php';
include 'includes/dummytwo.class.php';
include 'includes/dummythree.class.php';
include 'includes/dummyfour.class.php';
include 'includes/dummyfive.class.php';
 
//Code block used to test SPL Autoloader.
function autoload($classname) {
 	$name = strtolower($classname);
 	include 'includes' . DIRECTORY_SEPARATOR . $name . '.class.php';
}
spl_autoload_register('autoload');
 
//Code block used to test __autoload()
function __autoload($classname) {
 	$name = strtolower($classname);
 	include 'includes' . DIRECTORY_SEPARATOR . $name . '.class.php';
}
 
$dummyOne = new Dummy;
$dummyTwo = new DummyTwo;
$dummyThree = new DummyThree;
$dummyFour = new DummyFour;
$dummyFive = new DummyFive;
 
$timer->stopTimer();
echo $timer->getTime();

The classes being included are identical save for their names and simply perform a mathematical addition 50 times each:

class Dummy 
{
public function __construct() {
	for($i=0;$i<50;$i++) {
		$r = $i + 1;
	}
}
}

For tests done while using eAccelerator, the relevant php.ini settings were as follows:

[eAccelerator] 
eaccelerator.shm_size = "0"
eaccelerator.enable = "1"
eaccelerator.debug = 0 
eaccelerator.check_mtime = "1"
eaccelerator.filter = ""
eaccelerator.shm_max = "0" 
eaccelerator.shm_ttl = "0" 
eaccelerator.shm_prune_period = "0"
eaccelerator.shm_only = "0"

The Results

Now onto the results. Take a look:

PHP 5.3.0 Without Opcode Caching

  Multiple include() SPL Autoloader __autoload()
Trial 1 0.00168896 0.00130391 0.00112915
Trial 2 0.00153303 0.00128794 0.00122499
Trial 3 0.00114799 0.00116611 0.00140595
Trial 4 0.00140595 0.00124097 0.00120497
Trial 5 0.00173497 0.00115585 0.00128889
Trial 6 0.00110888 0.00119805 0.00119996
Average (seconds) 0.00143663 0.001225472 0.001242318


PHP 5.3.0 With Opcode Caching (eAccelerator)

  Multiple include() SPL Autoloader __autoload()
Trial 1 0.00052309 0.00060201 0.00057101
Trial 2 0.00049305 0.00054383 0.00055003
Trial 3 0.00049591 0.00055194 0.00060415
Trial 4 0.00049996 0.00055408 0.00054097
Trial 5 0.00052595 0.00058699 0.00054979
Trial 6 0.0005219 0.00055003 0.00053716
Average (seconds) 0.000509977 0.000564813 0.000558852


The first set of tests indicate that autoloading is faster than multiple includes. The SPL autoloader wins here with the __autoload() function coming in second and multiple includes quite a way behind in third. The second set of tests however convey the complete opposite. Here we see multiple includes winning out by a clear margin with the __autoload() function coming in second and the SPL autoloader finishing third. I was quite interested to find out why using multiple includes is faster than autoloading when using an opcode caching system and so I did a bit of research. Apparently some opcode caching systems may have issues with caching autoloaded classes. I’m going to have to do a bit more digging to find out why exactly that is.

These tests can be modified and extended in a number of ways to improve the data collected. They could be carried out on Unix, Linux and Mac systems, they could be modified so they test against require(), require_once() and include_once() or they could be tested with differing classes. This data is simply a starting point and is subject to one of the biggest issues I have with benchmarks, they simply don’t effectively mirror real world systems.

Final Thoughts

We have one victory here for the pro-autoload developers and one for the anti-autoload developers. These tests and results however provide quite an effective distraction from the entire point of using an autoloader. Even if autoloading proved to be whole seconds slower than using multiple includes, it is a technique I’d still use. Religiously. Why you ask? The answer is simple. The benefits of using an autoloader are not centered around speed gains. It is about organizational efficiency. Autoloading allows you to write less lines of code, which in turn decreases the probability of bugs creeping up in your code. Think about it, writing less code equals less opportunity to mess up somewhere. Additionally, in cases where you might include 25 files of which only 5 are used autoloading would clearly prove to be the faster option. Somewhere in the region of 5 times faster I’m guessing. Cleaner, smaller and in some cases faster code. That is what autoloading offers. If these results teach us anything, it is that we should definitely use an opcode caching system on our servers. The difference in speed between the two sets of tests is incredible!

I am open to any comments or criticism regarding how these tests were carried out, and I welcome any data which validates or invalidates my own. I have yet to perform these tests on a Linux server, however once I get around to upgrading to PHP 5.3 on my Linux box I’ll be sure to rerun the tests and post the results. I hope that you found this article useful.

Short URL for this post:

http://bit.ly/3gtMUv

Comments Map

Location data courtesy of GeoSmart

{ 1 trackback }

United States Tweets that mention Benchmarking Autoload Performance In PHP -- Topsy.com from California, United States
October 19, 2009 at 3:19 am

{ 7 comments… read them below or add one }

1 United States Brandon Savage from Texas, United States October 19, 2009 at 3:32 am

Twitter: @brandonsavage

I like your argument about why you’d still use an autoloader. I’d probably dispute your benchmarks as fundamentally flawed because of the very small amounts of time we were talking about here; that said, even if autoloading was slower I still think it’s a superior option.

Thanks for doing the work on this!

2 Jamaica Sam from Saint Andrew, Jamaica October 20, 2009 at 12:00 pm

Twitter: @SamuelFolkes

I actually thought about that a bit. I figured that since I was only measuring the time taken to load the classes, either way, the times would be very small. I don’t even think the time taken to instantiate the objects should be measured. Only the time to find the class and include it in the script being executed. I could be wrong though. Any suggestions as to how I could make the tests more accurate?

3 Canada Dave from Ontario, Canada October 20, 2009 at 3:21 pm

Trouble with only trying to test the including of the files via autoloading is that, you HAVE to instantiate the object… or at least do a class_exists() or similar method – others the autoloader is never hit.

However, I think the testing could be improved by looking at a more likely situation; one where the included classes include (or depend on) other classes. It doesn’t need to be hideously more complicated, one layer should do it – but it should also include files that are not necessarily needed. e.g. class1 in the include test includes class2 and class3, but never uses them, but class4 includes class5 because class4 extends class5. In the autoloader tests, that should result in only class1, class4 and class5 being pulled in, whereas all classes would be included in the straight include test.

But that then raises another issue: would that be a fair test? You are loading less (but then isn’t that the whole point?!)

One thing I will say, in my own testing in a large application, spl_autoload is always faster than __autoload even when using an opcode cache (APC in that instance). How does that simple test of yours react to APC? The last few versions of APC all (at least in my testing and profiling) seem to have worked very nicely with spl_autoload.

I also agree entirely with your reasons for using an autoloader – I would never code PHP without one these days, as it just makes life so much easier and doesn’t result in include hell.

4 Jamaica Sam from Saint Andrew, Jamaica October 20, 2009 at 5:48 pm

Twitter: @SamuelFolkes

Thanks for the insights Dave. I plan to redo these benchmarks in the near future and I’ll certainly include (no pun intended ;) ) your suggestions. I haven’t gotten a chance to test with APC as I just can’t seem to get it to run on Windows 7. I want to do tests with all the major opcode caching systems (APC, xCache, eAccelerator and maybe Zend Accelerator+) in order to see the differences (if any) in the way they handle autoloading.

5 Sweden Andreas Eriksson from Kalmar Lan, Sweden October 22, 2009 at 3:48 am

As you said in the article i would use autoload any day even if it were slower then the require statement.

I think it would also be interesting and see the difference with the include_once or require_once statement.

6 United States Richard Lynch from Illinois, United States October 31, 2009 at 12:27 am

Twitter: @LynchRichard

Curious…

I’ve never bothered with an autoload, as I’ve always built up my classes in a logical order, with the include() calls in the same logical order, and have never had a problem loading in a ton of unused classes, nor felt that the listing of include files was onerous…

Perhaps I’ve simply never made enough classes to get into trouble…

The only “problem” with autoload I’ve ever hit was tracking down where it was loading from when handed an app that used it. That doesn’t usually take too terribly long, usually…

7 Germany PHP Autoloader from Baden-Wurttemberg, Germany December 4, 2009 at 5:51 am

I’ve written a convenient Autoloader implementation: http://php-autoloader.malkusch.de/en/

It can be used with other autoloaders, finds classes automatically, stores them in an index and works without any configuration out of the box.

Leave a Comment

You can use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong> <pre lang="" line="" escaped="">

Previous post:

Next post: