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.

GazeHawk provides eye tracking services using ordinary webcams. They are the industry leader in economical eye tracking, with the ability to run higher quality studies at lower costs. Learn more about their products or request additional information.
This entry was posted in Uncategorized and tagged . Bookmark the permalink.

21 Responses to PHP “require” Performance

  1. Maz says:

    Thanks for writing, will help. BTW, your Autoload class files link is not correct.

  2. 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.

    • Brian Krausz says:

      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).

  3. Tony Arkles says:

    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?

    • Brian Krausz says:

      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.

      • Josh says:

        You should probably amend the article. I was confused too until I went back and reread the reference to ab.

      • Tony Arkles says:

        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).

  4. KevBurnsJr says:

    Were these benchmarks performed with APC enabled?
    Care to throw in APC as another variable in your experiment?

  5. Justin Palmer says:

    How does that compare to include_once and include?

    • Brian Krausz says:

      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).

  6. Pknerd says:

    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

    • Brian Krausz says:

      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.

  7. Nyro says:

    Thanks for this enlightenment.
    What about a benchmark with spl_autoload_register ?
    And with multiple autoload functions ?

    • Brian Krausz says:

      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).

  8. Joe says:

    How do you propose replacing instances of require_once with require? if ( ! class_exists()) ?

  9. Pingback: using include/require/require_once

  10. CS says:

    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.

  11. opencart says:

    Can u test with
    include VS include_once VS require VS require_once ?

    Thanks.

    Amazegu.

  12. Dominevski says:

    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.

Leave a Reply

Your email address will not be published. Required fields are marked *

*

You may 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>