Wherein I occasionally rant on various topics including, but not limited to, PHP, Music, and whatever other Topics I find interesting at the moment, including my brain tumor surgery of August 2010.

Tuesday, May 22, 2012

PHP Caches (APC et al)

I occasionally still see people referencing ancient misinformation that various PHP bytecode caches are giving huge performance boosts by caching the bytecode so the PHP bytecode parser/compiler doesn't have to do the monumental task of reading PHP source and converting it into bytecode to be run by the Zend Engine.

Nothing could be further from the truth.

Okay, there is one tiny bit of truth in there.

The php process/program/runtime, without a bytecode cache, is in fact a JIT parser/compiler to a bytecode, which is then run by the Zend Engine.


Amd. okay, the various caches all cache the bytecode as part of the process of gaining huge performance boosts for most PHP web applications.

So that's two tiny bits of truth in a monumentally flawed statement.


But the significant boost is not from bypassing the parser/compiler.

APC and other caching mechanisms save a great deal of time by not hitting the hard disk to load the script, but keeping it in RAM, if possible. Hard disks are slow.  RAM is fast.

The bytecode is saved in cache instead of source, which does bypass the PHP parser/compiler.

But that's just "gravy"

Compare two following psuedo code samples that describe the difference the APC (or other cache) makes:

Code Listing #1


//save hitting the hard disk
if ( $source_code = in_cache($path) ){
  //got the source code from cache, do nothing
}
else{
  //file_get_contents = super-duper slow!!!
  $source_code = file_get_contents($path);
}
$bytecode = zend_parse($source_code);
zend_execute($bytecode);

//Code Listing #2


//save hitting the hard disk
//and a small bonus, cache the bytecode, not source:
if ( $bytecode = in_cache($path) ){
  //got the bytecode from cache, do nothing
}
else{
  //file_get_contents = super-duper slow!!!
  $source_code = file_get_contents($path);
  $bytecode = zend_parse($source_code);
}
zend_execute($bytecode);

As you can see, both code listings bypass the hard drive access which is super-duper slow.

But the second one also bypasses the PHP parser/compiler, simply because it's such a trivial difference, just moving one single line of code into the conditional, to cache $bytecode versus $source_code.

The savings from parsing is chump change compared to disk I/O.

It's also trivial chump change to implement.

But every ounce counts, so all the "bytecode caching" (sic) mechanisms do it this way.

They should all really be called "RAM caching, with bytecode gravy" or even "RAM caching" and just ignore the minimal difference between source versus bytecode.

I'm sure this post is going to make all the caching implementers run out and change their documentation etc. :-)

Well, at least you now understand what "bytecode cache" really means. I'll call it a "win".