Lazyweb Request: Why would PHP be *faster* than HTML?

With the help of the great guys at, I am attempting to run my benchmark series on a virtual private server, to compare with EC2. However, I’m seeing a very strange result for the baselines: a PHP page delivers more requests-per-second than a static HTML page.

The OS is a stock Ubuntu 8.10 installation; you can see the setup steps here.

The virtual private server has 2 gigs of RAM, and is on a box by itself, so there is no other external activity to skew the results.

I ran ab -c 10 -t 60 http://localhost/ on each of two files: index.html, which has only the static text “hello world”; and index.php, which has only the code <?php echo 'hello world'; ?>.

Here are the results without APC, averaged over 5 one-minute runs:

index.html : 7067.57 req/sec
index.php  : 7484.57 req/sec # faster???

Here are the results with APC, averaged over 5 one-minute runs:

index.html : 7013.50 req/sec
index.php  : 8041.06 req/sec # faster???

I haven’t seen this behavior on EC2. I’m not complaining, but it does seem unintuitive; invoking the PHP interpreter should be more expensive than just delivering a static HTML file. Does anyone have ideas as to why this might be happening?

UPDATE: With the help of Paul Reinheimer, we appear to have found the culprit: the ab tool itself seems to be at fault. Running similar tests by hand with siege returns much more reasonable and expected numbers (~4000 req/sec for HTML, ~3200 for PHP). I’m going to re-work the test scripts to use siege later and report back. Thanks to everyone who provided suggestions, and special thanks to Paul Reinheimer for working through it with me today.

Are you stuck with a legacy PHP application? You should buy my book because it gives you a step-by-step guide to improving your codebase, all while keeping it running the whole time.

22 thoughts on “Lazyweb Request: Why would PHP be *faster* than HTML?

  1. Are you sure there are not other Apache Modules installed that detect the HTML extension, and pass it through to check for such things as SSI? Perhaps, you should also try the old .htm extension as well.

  2. The APC numbers *might* be explained by Apache going to disk for the HTML while APC serves the opcode out of memory, but that’s a wild guess. If PHP does some caching (e.g. of the file) and Apache / the file system isn’t doing good disk caching for the HTML, it might explain the first set of numbers.

    No idea, overall. Interesting numbers though!

  3. Now that’s odd. As Joe Stump mentioned I could see how using APC could potentially make it faster (though I doubt it), but the non-APC numbers don’t seem to make any sense at all.

    Complete shot in the dark, but they aren’t on different file systems are they?

    I’d say start stripping down Apache to the bar minimum, seems likely that there’s something in there causing extra work for .html files. Hmmm, maybe try this test with an index.txt file to see if there’s any difference. Should be the same as the index.html file.

    What order are you running the tests? Is index.html always run first?

  4. Maybe the Apache webserver isn’t optimised for static file delivery (too much mods/dynamic stuff) loaded ?

    You could try a .txt vs. .php file for comparison to be sure?

  5. Hmm. I use ab all the time for quick tests. So this is not encouraging. Any more specifics on what exactly ab is doing wrong?

  6. I don’t know much about the technical stuff, but I was just thinking that the work Apache has to do to serve a static file will take more time than parsing the PHP code?

    To serve a static file, Apache has to:

    1. Read the file’s last modification date (“Last-Modified header”)
    2. Generate an Etag
    3. Get the file’s size
    4. Output the file.

    Could it be that doing all these steps simply takes longer than parsing a few bytes of PHP code and let mod_php output the text directly over the wire?

  7. @K — you show good critical thinking. We went though all those points, and determined that they did *not* outweigh invoking the PHP interpreter. Instead, it turned out (per the update I posted at the end of the entry above_) that the “ab” benchmarking tool was at fault and was showing bad numbers; the “siege” benchmarking tool showed much more reliable information. (Now I have to go back and re-run all the previous benchmarks for comparison. 😉

  8. You have said that ab is faulty , and siege works , but this assumption is based only on the fact that siege results look normal(based on the info you provided).

    If it’s ab’s fault , you should explain why. You should also try to determine when and why this happens so that you woun’t have to to re-run all your previous benchmarks with siege , mainly because all your previous benchmarks influenced a lot of people and you gained a certain reputation based on it , and now you are saying they are wrong and ab is faulty too (this influences ab too).

    Not checking and explaining the ab thing would not be fair(to ab , to you , to the comunity , etc) .

  9. Hi Khelo — I agree with everything you say there. Let me address point-by-point.

    1. I’m not 100% certain that siege is exactly right, but it does seem a lot more reasonable than ab did. The basis for me saying that is that siege *does not* report HTML being faster than PHP, while ab does.

    2. I’m am eager to know why ab is reporting this way, but I don’t know enough about it (or siege) to explain yet. Happy to take pointers here.

    3. Based on my runs with siege so far, the *relative* benchmarking rankings are the same as with ab; the absolute numbers are different, but the percentages are similar, and the ordering of most-to-least responsive remains the same.

    I will be publishing updated information as soon as I get it completed; benchmarking is still a very time-consuming task, and I have a paying job I’d like to keep, so it might be a bit.

  10. Hi , dont agree with this php is faster than html ,when tested php and html why the results came html were faster so html is faster than php

  11. Late follow up, but thought it might be worth it.

    I’ve been running some new tests for WordPress and this time I used Ubuntu instead of FreeBSD as the test server. In both cases the client running ab was Mac OS X, so that part hasn’t changed. Both Ubuntu and FreeBSD were running under Parallels.

    When I ran the ab tests against the FreeBSD I never saw the problems you described, where the PHP results would magically show up faster that static files. When I ran these tests against the Ubuntu box though I did! I was seeing PHP results that were 1.8 times faster than static files, which makes no sense at all.

    This makes me wonder if there’s something different that Linux is doing that is causing the wonky numbers.

  12. I’m somewhat sceptical of everyone who says something about the disk unless apache does very strange things. In fact, if it is linux I would disagree strongly with what they say. I’m assuming Linux since you said SliceHost.

    After reading the file, once, it will be thrown into the Page Cache. So even though it seems logical to think apache reads the html file from disk every single time, in reality it _should_ only read it once assuming the underlying inodes don’t change and the heuristics. After that it should get shoved into the pagecache and any further read(2) calls will in fact hit the page cache from the Linux MM (memory manager).

    If apache somehow magically bypasses all of that, the most it would do is call stat(2) which only reads the inode metadata vs the entire file. This is only a somewhat educated guess. Your best bet would be to RTFS but httpd is a gorilla.

  13. you sure you’re not gzipping output set in your php.ini, while apache isn’t?

    That could give php a faster TTLB over straight HTML especially with large streams.

Leave a Reply

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