I’ve been working on an MVC framework for PHP for a while now. I started way long ago but never really had enough time to sit down and “really” work on it. Various ideas and chunks of code from this soon-to-exist framework have already been put to use over at Fuzz. Don’t get me wrong – we’re not using some crippled piece of shit at Fuzz, it works & is pretty rad – but I’ve got a bunch to do before I can put this bad boy out as a standalone framework that the public can use.

Anyways… One goal for the framework is to deal with the nuisance of require‘s and include‘s. Its always easy to fall back on include’ing/require’ing more shit than you actually need. Also, you have all the supposed require_once/include_once performance issues to deal with. With all that in mind I wrote a little, crappy script to do some timing tests on require_once, include_once, require & include. What’s the performance difference between all these?

This script performs a require, require_once, include or include_once on 1,000 DIFFERENT files (0.txt, 1.txt thru 999.txt) and times how long that “batch” takes. Due to the results I saw (which I’ll get to later) I actually didn’t trust it and wrote some other code to verify what I was seeing with this script.

Here’s the code:

the beefy script:

<?
    $numFiles 
= empty ($argv[1]) ? 1000 $argv[1];
    
ini_set ('memory_limit', -1);

    function doIt ($operation)
    {
        global 
$numFiles;
        
clearstatcache ();                       
        
        `
touch *.txt`;        
        for (
$i 0$i $numFiles$i++) include "{$i}.txt";
        
$startMemoryUse memory_get_usage ();
        
        
$startTime microtime (true);        
        
        for (
$i 0$i $numFiles$i++) 
        {
            eval (
"$operation \"{$i}.txt\";");
        }
        
        
$endTime microtime (true);
        
$endMemoryUse memory_get_usage ();
        
        return array (
                (
$endTime $startTime), 
                (
$endMemoryUse $startMemoryUse));        
    }    
    
    echo 
"------------------------------------\n";    
    
    if (! 
file_exists (($numFiles -1) . ".txt"))
    {
        echo 
"Prep: touch $numFiles files\n";        
        for (
$i 0$i $numFiles$i++) `touch {$i}.txt`;
    }
    
    
$operations = array (
                        
'require_once''require'
                        
'include_once''include');
    
shuffle ($operations);

    $results = array ();           
 &n

bsp;  echo "Running for $numFiles files:\t"
            
implode (', '$operations) , "\n";
    foreach (
$operations as $operation)
    {
        list (
$time$memory) = doIt ($operation);
        
$results[$operation] = $time;
        
        
printf ("%12s: %10d\n"$operation$memory);
    }

    asort ($results);
    echo 
"------------------------------------\n";
    echo 
"Results:\n";
    
    
$winner array_slice ($results01true);
    
$quickest $winner[key ($winner)];
    
    
$fh fopen ("results_{$numFiles}.csv"'a');
    
printf ("\t%12s    %10s %10s\n"
            
'''faster by''og. time');    
    foreach (
$results as $k => $v)    
    {
        
fwrite ($fh"$k\t$v\n");
        if (
$v $quickest)
        {
            
printf ("\t%12s: + %10f %10f\n"
                
$k, ($v $quickest), $v);
        }
        else
        {
            
printf ("\t%12s:   %10s %10f\n"$k'n/a'$v);
        }
    }
?>

So running this on my MacBook I get the following results… oh ya, don’t forget that the timing reflects 1,000 operations.

on MacBook – 1.8Ghz Core Duo

------------------------------------
Running for 1000 files:	require, require_once, include_once, include
------------------------------------
Results:
	                 faster by   og. time
	include_once:          n/a   0.088193
	require_once: +   0.013137   0.101330
	     require: +   0.030759   0.118952
	     include: +   0.045299   0.133492

on Fuzz’s staging server – RHEL on i686

------------------------------------
Running for 1000 files:	require_once, include, include_once, require
------------------------------------
Results:
	                 faster by   og. time
	require_once:          n/a   0.026613
	include_once: +   0.000050   0.026663
	     require: +   0.026534   0.053147
	     include: +   0.026741   0.053354

On both systems x_once turned out the fastest times. I ran the script a bunch of times on both my MacBook and on the Linux box and x_once always registered the fasted times. It looks like my MacBook favors include_once and the Linux box favors require_once… it looks like a 60/40 sort of split.

This didn’t jive with me so I generated 4 new scripts. Each of these scripts ditched all the fluff from the original and just called require_once, require, include_once and include 1,000 times in a row. I ran each of these simplified scripts (honestly, I dunno why I made the first script all beefy anyways…) a bunch of times on both boxes with pretty much the same results as the beefy script.

script generator:

<?
    
if (empty ($argv[1]))
        die (
            
"usage:\n\tphp {$_SERVER['SCRIPT_NAME']} " .
            
"[require|require_once|include|include|once]"
            
);
            
    
$type $argv[1];
    echo 
"<?\n";
    
    echo 
"clearstatcache ();\n";
    echo 
"ini_set ('memory_limit', -1);\n";
    
    echo 
"`touch *.txt`;\n";
    echo 
"for (\$i = 0; \$i < 1000; \$i++) include \"{\$i}.txt\";\n";    
    
    echo 
"\$start = microtime(true);\n";
    for (
$i 0$i 1000$i++)
    {
        echo 
"$type \"{$i}.txt\";\n";
    }
    echo 
"\$end = microtime(true);\n";    
    echo 
"\$time = (\$end - \$start);\n";
    
    echo 
"\$fh = fopen (\"manualResults_1000.csv\", 'a');\n";
    echo 
"fwrite (\$fh, \"$type\\t\$time\\n\");\n";
    echo 
"echo \"$type: \$time\\n\";";    
    echo 
"\n?>";    
?>

Something worth noting is the fact that I do a touch and include of each file before I start the timer. The reason for this is cuz I wanted to make sure that each run through had its fair shot of having the txt file available in memory; my cheap attempt at trying to make sure the playing field was fair for each operation. Also, the $operations array is shuffled each time the script is run. I didn’t want to get into a situation where the order the operations ran played a role in their performance.

I added some logging to the end of the scripts so that the timing output was shoved in a cvs. A quick and dirty companion script I wrote would crunch through the csv files to report averages. These resuts were in line with the output of the beefy script.

I’m pretty shocked at the results. I’d always read about the x_once operations being slower. Honestly if it wasn’t for the fact that the simple scripts gave the same results I’d assume I had a bug. This is actually why I wrote the simple scripts… I just didn’t beleive my original numbers.

So, for now, it looks like using include_once or require_once are actually faster than using include or require. Now, the next thing to check out is going to be the difference in memory consumption. I’ll get to that later cuz I’m gonna go drink now :) .

Now, don’t get me wrong, I know there’s functional differences between include_once, require_once, include and require. However, for the problem I’m trying to solve any of them will do (it’ll make more sense when I write about my framework).

BTW: Happy Thanksgiving!

  • Digg
  • del.icio.us
  • Facebook
  • Reddit
  • Twitter
Tagged: ,

18 comments

Arin on Nov 23, 2007 at 1:58 pm

Check out http://www.phatduckk.com/blog/php/ for some more info

racers auction on Jun 04, 2008 at 5:13 pm

I have a small problem I can’t find the answer to. Say I have a large includes file but I only need ONE function from the file for a certain page the needs to be incredibly fast. Racing fast, should I include that function on the page itself, include the file with that function or write another file with only that function and include it on the page??

Dave Carlson on Nov 26, 2008 at 3:09 am

if it for performance, then you should include the function inline. then the server doesn’t have to make another HDD access to grab your include file, then load into memory etc etc.

phatduckk on Nov 26, 2008 at 10:43 am

i agree w/ you Dave. i was just dong this out of curiosity b/c i read a bunch of stuff about *_once’s performance and wanted to see for myself

[...] Developer Finds require_once() Slower Than require() Another Developer Finds Little Difference Yet Another Developer Finds It Depends On His Cache Configuration Rumor has it,  PHP 5.3 improves [...]

andrew on Feb 16, 2009 at 5:26 pm

this article was a great find. ive always thought that include_once was much slower, but i saw the same results you did when doing benchmarking and wanted to confirm online.

thanks for doing all this testing and posting the results.

[...] PHP require vs. include vs. require_once vs. include_once Performance Test [...]

meo on May 19, 2009 at 7:33 pm

Hi, thanx for benchmarking, that was very interesting

[...] PHP require vs. include vs. require_once vs. include_once Performance Test par Arin [...]

Ivan Chepurnyi on Sep 08, 2009 at 5:24 am

Also if you have a large MVC framework, its make sense to compile “file/path/to/class.php” to something like this “file_path_to_class.php”, it will speed up any type of php files includes, becouse php interpreter will not check FS stat data for directories “file”, “file/path”, “file/path/to”, etc.

Chris on Nov 18, 2009 at 2:30 am

You can’t just compare the mean values – you need to consider the actual distribution and do t-tests or something. Also I’m not convinced that your replicates are actually independent – what is the variance from repeated runs of the same top level script? How does it compare to the variance of the different operation types?

Ashwin on Nov 22, 2009 at 9:10 pm

Arin,

Thanks for the results of the comparison.
Although, these 4 functions cannot be used in place of each other. In some cases you have to use include_once, like in case of a file that contains class definitions.

In such cases it’s really upto the programmer to use the 4 functions judiciously, whatever the comparative performance might be!

Cialis on Mar 04, 2010 at 8:30 am

KkLTK6 Thank you for the material. Do you mind if I posted it in her blog, of course, with reference to your site?

Matthias Loitsch on Apr 26, 2010 at 1:56 am

Your benchmark doesn’t really make sense…
Of course: When you do include a thousand times it will be slower than doing include_once. This is not surprising since the file really has to be included & parsed a thousand times.
A test that would make sense, is to do a simple variable check before, to check IF you want to include the file.
I myself did a speed comparison test recently, where I compared include_once to include with a boolean check (something like: if (!$someFileHasBeenIncluded) include(‘someFile.php’);) . This way you have the same behavior, but using two different approaches. Surprisingly, my results were pretty clear: Checking a boolean is MUCH faster, than include_once.

Matthias Loitsch on Apr 26, 2010 at 3:22 am

I redid some testing. I implemented 3 different kinds of tests:
1) include_once
2) Checking if class_exists (where the implementation of the class is in the file obviously)
3) Setting a bool and checking every time.
The results differ a LOT when using a lot of iterations, and still noticeable when using a few:

For 10000 iterations, include_once: 0.19029593467712ms
For 10000 iterations, class_exists: 0.0049629211425781ms
For 10000 iterations, bool check: 0.00084900856018066ms

For 10 iterations, include_once: 0.00040292739868164ms
For 10 iterations, class_exists: 0.00012707710266113ms
For 10 iterations, bool check: 0.00011205673217773ms

Since about 10 includes are the common case, using class_exists is a very good alternative to include_once IMO.

Cheers.

[...] Another reason to use one of the _once() methods is because they are faster in performance. See the _once() methods performance tests results here. [...]

samanta on Aug 30, 2010 at 3:09 am

9Fxq5H http://djb3jDdmjckow30cnjcmd61l0dy.com

Signup to Leave a Comment

Or Login via Facebook

Lots of responses on my laptop question. Thanks for the feedback guys 2 hrs ago

Search This Blog