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.
Thanks for writing, will help. BTW, your Autoload class files link is not correct.
Damn, I hate when I see that on other blogs…I’m such a hypocrite!
All fixed, much obliged.
Did you know that if you make your require paths absolute it’s faster, too? Because in this case it won’t have to walk the include_path looking for matches. While this doesn’t make a huge difference for linux, it’s a large difference on Mac OS X (where a lot of us develop) so saving the time is nice.
Also from my experiments using full paths in your autoloads allows them to be cached by the opcode cache as well.
I’ll have to look into that…it seems really strange that relative dirs would exclude autoload classes from opcode caching…if that’s the case I can just run getcwd on load and use the to make the abs dir (we run all scripts out of the same cwd).
What are the units on those measurements? My first guess was milliseconds, but then I was thinking… it can’t really be taking 1.5sec to require() 5 files. My second guess was microseconds, but that’d mean that the absolute performance difference between the different approaches wasn’t really all that significant.
Help me out?
They were the number of ms it took to load the page N times, M at a time. Because the actual numbers depend on the machine performance, I didn’t bother providing the numbers. Their relative values are all that matters.
You should probably amend the article. I was confused too until I went back and reread the reference to
ab
.The relative values are not the only thing that matter. If the absolute difference between require() and require_once() is 100 microseconds, and you’re only doing it 5 times, then it’s completely irrelevant as far as optimizing a code base goes (guaranteed there’s more significant wins to be gained elsewhere).
Were these benchmarks performed with APC enabled?
Care to throw in APC as another variable in your experiment?
All tests has APC enabled. APC is such a no-brainer (*always* use it) that it didn’t seem worth comparing without it on.
How does that compare to include_once and include?
Haven’t verified this, but I think include has the same performance as require (ditto for *_once), since the only difference is what they throw if they fail (warning vs. error).
I am failing to get how did you perform test.
I took a file named “main.php” and in which I included 2 files, r1 and r2.php. Both had sleep() for 3 seconds. The result of AB for both require and require_once are not SO different. What am I Missing? Stats are giving below:
REQUIRE_ONCE
Concurrency Level: 10
Time taken for tests: 80.162736 seconds
Complete requests: 100
Requests per second: 1.25 [#/sec] (mean)
Time per request: 8016.273 [ms] (mean)
Time per request: 801.627 [ms] (mean, across all concurrent requests)
Connection Times (ms)
min mean[+/-sd] median max
Connect: 0 0 0.3 0 1
Processing: 8004 8014 24.7 8006 8089
Waiting: 8003 8014 24.4 8006 8088
Total: 8004 8015 24.8 8006 8089
REQUIRE
Concurrency Level: 10
Time taken for tests: 80.77928 seconds
Complete requests: 100
Requests per second: 1.25 [#/sec] (mean)
Time per request: 8007.793 [ms] (mean)
Time per request: 800.779 [ms] (mean, across all concurrent requests)
Connection Times (ms)
min mean[+/-sd] median max
Connect: 0 0 1.6 0 9
Processing: 8004 8006 1.3 8006 8010
Waiting: 8002 8006 1.2 8006 8010
Total: 8004 8006 2.0 8006 8015
Pls guide
FYI I edited your comment down to remove unnecessary info from the output.
1) I was running at a higher level of concurrency
2) I was including 30 files instead of 2
3) Are you using opcode caching? Not sure how that affects require vs. require_once, but it may.
I’m sure there are more differences that affect the outcome of that test, but those are the most striking.
Thanks for this enlightenment.
What about a benchmark with spl_autoload_register ?
And with multiple autoload functions ?
That is left as an exercise to the reader .
However, I strongly suspect that spl_autoload_register will cause no notable overhead besides a few extra function calls (ditto with multiple autoload registers).
How do you propose replacing instances of require_once with require? if ( ! class_exists()) ?
Pingback: using include/require/require_once
If you can write a simple perl script to inline these require’s as part of your build and deployment you will see a good increase in performance due to opcode caching + no file stat.
Can u test with
include VS include_once VS require VS require_once ?
Thanks.
Amazegu.
I would say comparing “require_once” vs “require” is pointless.
Its true that “require” is almost twice as fast than “require_once”
but that cannot be tested, really, not in a real world scenario.
If you know for sure you are only including a script ONCE, why
would you use require_once? The whole idea of using require_once
is when you dont know if and when you gonna need the script.
When testing performance you test suite should ofcourse include
same files multiple times right? Someone may argue that if your
code is loading same files more than once, then it is a failure
by design. I dont agree. For the same reason we use #ifndef in
our C or C++ programs =)
An example:
Assume I have a utlity class with common stuff and it is used by
both DB.php and Auth.php. Most of the time these two are NOT
loaded in the same script but what if they do? Like the login
script which uses DB backend. Using plain “include” or “require”
will throw fatals if and when both DB and Auth are used in a
script: Cannot redeclare bla bla…
So there is only 2 options left: include_once or __autoload.
Depending on your code I would say:
- If you know your code is using the included file then require_once
is better.
- If the required file is most likely NOT used, then use __autoload
- plain require/include should be used only when the included
file does not contain any PHP code at all. Means you are loading
static content or templates or whatever similar.