Although the general assumption is that having PHP chewing through comments causes no measurable difference, better to check it, ain't it?
(Note: by common sense, we'd expect that the sheer request processing, permission management, process control, dispatching this, delegating that, firing up the PHP runtime environment, managing various caches, fiddling with asset files, overall disk and network I/O etc. etc., oh, and BTW, also executing the code, all very likely add up to far more than any generous amount of comments.)
So I gave it a very unsophisticated go, just to get an instant feel of it.
1. Setup
Predicting the "comment impact" to be as difficult to detect as neutrinos, I was deliberately after a slightly pathological setup, trying to make the difference measurable, but still not be overly unrealistic.
I created two files. One with no comments, just ~100 bytes, straight to the point, no-comments.php
:
<?php
function task() {
++$GLOBALS;
echo "[$GLOBALS] Lorem ipsum dolor sit amet cosectetur...\n";
}
And another, ~60K (staying under 64K just for heap-management-related superstition), comments.php
:
<?php
/* ... some 30K comments ... */
// OK, that's something, but how about:
/* ... same 30K comments again ... (Phantomjs changelog, for the curious of you. :) ) */
// Finally, do something:
function task() {
++$GLOBALS; // Comments are cheap, so let me tell you how much I enjoyed this instead of properly declaring a counter. :)
echo "[$GLOBALS] Lorem ipsum with a lot of comments...\n";
}
Note: this would of course very likely test file size impact actually, not purely the comments, but that's always an inherent part of the "comments (non)issue" anyway, and also I wanted just something first. Perhaps even that's already unmeasurable, right?
The general idea was then to loop task()
in various ways, just a bit (or none at all) from inside the same PHP process, and a lot from outside of it, via separate executions, to force reparsing, which is the only interesting part of this experiment.
For quickest results I did some shell runs:
#!/bin/bash
for (( i = 0; i < 1000; i++ ))
do
php comments.php # <-- and another batch with "no-comments.php"
done
But that turned out to be unreliable, as increasing the loop count caused inexplicable and disproportional changes in execution times. I switched to a PHP runner instead, which ran more smoothly:
#!/usr/bin/php
<?php
$t1 = microtime(true);
for ($i = 0; $i < 1000; ++$i ) {
system("php comments.php"); // <-- and with "no-comments.php"
}
$t2 = microtime(true);
echo "Time: ", $t2 - $t1
For HTTP runs I then added this index.php
:
<?php
$GLOBALS = 0; // innovative use of a dull language feature ;)
$t1 = microtime(true);
require_once (isset($_GET['no']) ? 'no-' : '') . 'comments.php';
// Played a bit with looping here, but ended up leaving it out.
// for ($i = 0; $i < 3; ++$i) {
// task();
// echo '<br>';
// }
$t2 = microtime(true);
echo "<hr>Time: ", number_format($t2 - $t1, 10);
Note: at first, unfortunately, I left PHP's Zend Opcache enabled, and wasted a lot of time trying to make sense of the results... ;-o Then i disabled the cache, of course, and repeated the web tests (only).
The host is just vanilla Debian, Apache2 with some PHP5 (I guess it's FPM -- didn't even bother checking, as that's supposed to be orthogonal to the subject of the testing (please correct me if this is not true). It may actually even help exposing the difference by reducing the irrelevant PHP startup overhead masking the tiny comment parsing time.)
2. Results - shell:
Running PHP-cli was surprisingly slow, so I got quickly bored, after only a dozen loops of 1000 iterations for both variants. (Results in seconds.)
COMMENTS:
44.2015209198
39.710990905762
42.374881982803
36.29861998558
44.764121055603
38.85772395134
42.627450942993
38.342661142349
48.539611816406
39.784120082855
50.34646987915
47.782819032669
36.974604845047
45.692447900772
AVERAGE: 42.592717
NO COMMENTS:
45.617978811264
43.397685050964
46.341667175293
44.246716976166
40.348230838776
43.048954963684
38.57627081871
50.429704189301
41.811543226242
35.755078077316
53.086957931519
31.751699924469
48.388355970383
49.540207862854
AVERAGE: 43.738647
As you can see, it's all rubbish... But if we ignore the environmental fluctuations, the conclusion is use more comments, it'll make your script faster! :)
3. Results - HTTP, Zend Opcache enabled:
(Some noise was cut from the ab outputs.)
COMMENTS:
ab -qd -n 10000 'http://.../comments/?yes'
Server Software: Apache/2.4.10
Concurrency Level: 1
Time taken for tests: 3.158 seconds
Complete requests: 10000
Failed requests: 0
Non-2xx responses: 10000
Total transferred: 7120000 bytes
HTML transferred: 4620000 bytes
Requests per second: 3166.12 [#/sec] (mean)
Time per request: 0.316 [ms] (mean)
Transfer rate: 2201.45 [Kbytes/sec] received
NO COMMENTS:
ab -qd -n 10000 'http://.../comments/?no'
Server Software: Apache/2.4.10
Concurrency Level: 1
Time taken for tests: 3.367 seconds
Complete requests: 10000
Failed requests: 0
Non-2xx responses: 10000
Total transferred: 7120000 bytes
HTML transferred: 4620000 bytes
Requests per second: 2969.95 [#/sec] (mean)
Time per request: 0.337 [ms] (mean)
Transfer rate: 2065.04 [Kbytes/sec] received
Wow! :-o Just like the shell runs! :) OK, not believing my eyes, I repeated it a few more times, until it made sense... :) See? Here:
Benchmarking ...<"NO COMMENTS">... (be patient).....done
Time taken for tests: 2.912 seconds
Total transferred: 7120000 bytes
HTML transferred: 4620000 bytes
Requests per second: 3433.87 [#/sec] (mean)
Time per request: 0.291 [ms] (mean)
Transfer rate: 2387.61 [Kbytes/sec] received
(BTW, don't ask me, why the non-2xx responses. They were 200 OK via the web.)
Then, with ten times more iterations:
COMMENTS:
Time taken for tests: 32.499 seconds
Requests per second: 3077.04 [#/sec] (mean)
Time per request: 0.325 [ms] (mean)
Transfer rate: 2139.51 [Kbytes/sec] received
NO COMMENTS:
Time taken for tests: 28.257 seconds
Requests per second: 3538.92 [#/sec] (mean)
Time per request: 0.283 [ms] (mean)
Transfer rate: 2460.66 [Kbytes/sec] received
Phew, perfect! Comments are evil! ;)
Well, I still did a couple more, and I can only show you this no-comment result strictly off the record:
Time taken for tests: 37.399 seconds
Requests per second: 2673.84 [#/sec] (mean)
Time per request: 0.374 [ms] (mean)
Transfer rate: 1859.15 [Kbytes/sec] received
4. Results - HTTP, Zend Opcache DISABLED:
OK, after realizing that I left the cache on, I commented out the extension from the PHP-FPM config (so, indeed, that's what runs here), restarted the services, checked phpinfo()
, and gathered the new results:
COMMENTS:
Time taken for tests: 34.756 seconds
Requests per second: 2877.23 [#/sec] (mean)
Time per request: 0.348 [ms] (mean)
Transfer rate: 2000.58 [Kbytes/sec] received
Once again:
Time taken for tests: 31.170 seconds
Requests per second: 3208.24 [#/sec] (mean)
Time per request: 0.312 [ms] (mean)
Transfer rate: 2230.73 [Kbytes/sec] received
NO COMMENTS:
Time taken for tests: 30.060 seconds
Requests per second: 3326.70 [#/sec] (mean)
Time per request: 0.301 [ms] (mean)
Transfer rate: 2313.10 [Kbytes/sec] received
Once again:
Time taken for tests: 32.990 seconds
Requests per second: 3031.23 [#/sec] (mean)
Time per request: 0.330 [ms] (mean)
Transfer rate: 2107.65 [Kbytes/sec] received
Well. As you can see, basically: no freaking difference from the opcache on/off state! Nor between comments on/off (apart from a tiny hint, but having seen the fluctuations...)! :-o
5. Conclusion
So... Finally, numbers! Well, useless garbage, as a matter of fact, but at least not just religions speculations. It feels a lot better being confused for the sound reason of confusing data than the lack of it! :)
Now, after I've certainly wasted more than enough time on this, the answer to the ages-old question of "how much comments cost", remains a mystery.
As neutrinos have (incredibly) been detected for years, we may justly start feeling embarrassed. Will someone eventually bring on the breakthrough and finally detect the PHP comment impact, too? Nobody knows...
Yes it has an impact! There is NO doubt about it.
Each time PHP must interpret a code that is NOT somehow cached, the I/O operation takes longer if it needs to read more data from disk.
The interpretation itself (if NOT cached one way or another) takes longer too.
The performance penalty is very much depending on the file system and caches in use. It may not be that important in your specific case.
In a web framework that we have written, when we package the distribution files for use in a production environment, we specifically remove all the comments as to make sure that LIVE apps get not penalized by our many comments (typically, the source file of our "String" routines accounts for about 169Kb before removing the comments, and only for 46Kb after treatment).
We have abandoned trying to measure the real penalty as it was impossible to cope with the variety of environments, file systems and caching mechanisms. We therefore have decided to distribute our code in 2 flavors: with comments and without comments.
If you have something configured on your system to "compress" your javascript on the fly there are a few gotchyas in doing this. I've actually implemented this with .htaccess myself and you can have HUGE performance gains and have commented code on the server itself.
I used google's closure tools (jar file on the server) and run closure if the md5_file() in PHP comes up as different.
Next, I used etags to assign a tag to that file. I also cache that file.
I also return a 304 not modified when the etag matches. If it doesnt then I return the new file and update the users etag. This is CRITICAL because if you return a 200/OK you're passing back the whole file again.
The key here is that you lose performance if you compress on the fly because you're always compressing and running PHP code. You can implement it correctly if you spend the time to do it. I personally like the technique because I can patch live server code without sending up a non-minified version. The performance of the "first run" of this technique is slow but subsequent users pull down a cached file on the server and then I return the 304 not modified thereafter. You have to do all this magic in your compressing PHP file.
I mention .htaccess too in here because I use a re-write rule in there and tell the website which files to compress and which not to. e.g. mylibrary.jsc tells my website to compress it with closure. yourlibrary.js allows me to have other .js files out there and compress on demand.