Tuesday, May 17, 2011

PHP “require” Performance

SkyHi @ Tuesday, May 17, 2011
We recently went through a round of performance improvements for our website, and got a significant performance boost off of a relatively small change.
Previously, our code had a section at start of every page:
require_once('include/Foo.php');
require_once('include/Bar.php');
.
.
.
require_once('include/Baz.php');
Each file was a single class of the same name as the file. While we’re well aware of PHP’s ability to Autoload class files, we chose to list each file out is because of a talk by Rasmus Lerdorf. Rasmus discussed file loading performance. In it he mentioned that __autoload causes issues with opcode caching, and as a result will cause a drop in performance.
Speaking of, if you haven’t heard of opcode caching for PHP, stop now and go read up. As simple sudo apt-get install php-apc will give you an order-of-magnitude speedup on your website. There’s no reason for any production server to not be using it.
Anyway, this may have been true when we only had a includes, but now we have 30 files that we were including on every page load! It was time for some performance testing.
It’s also a fairly well-known fact that require_once is much slower than require…I wasn’t thinking when I used require_once. I also tested the difference between those two calls.
I tested 2 pages. First was our homepage, which only requires 3 of these 30 files. Second was an inner page that requires 5. They were tested with ab, and the numbers listed are the mean response times under high concurrency. Lower is faster.
For reference the autoload code used is:
function __autoload($name) {
    require('include/' . $name . '.php');
}

Results

Homepage (3 required files)
require_once: 1579
require:      1318
__autoload:   578
Inner page (5 required files)
require_once: 1689
require:      1382
__autoload:   658
Wow! Over a 2x speedup…that’s pretty nice. This led me to wonder: what’s the difference in time when we’re only loading the files we need:
only autoload:         618
5 requires + autoload: 530
only 5 requires:       532
Actually having autoload called adds significant overhead to the page, but as would be expected just having it enabled but never invoked doesn’t add any overhead.

Conclusion

The main takeaway: if your primary concern is performance, then any file included on all of your pages should be included with a require. Any file that’s included on fewer pages can be loaded through __autoload, especially if it’s only on a few pages. Also, always use APC and never use require_once unless you absolutely have to.
Also, your situation may be different than the situations you see in performance tests, so always run your own metrics. ab is your friend.

REFERENCES
http://www.gazehawk.com/blog/php-require-performance/
http://stackoverflow.com/questions/186338/why-is-require-once-so-bad-to-use