clarification on the performance of require_once and APC
| From: | Gregory Beaver | Date: | Sat, 25 Aug 2007 18:32:51 +0000 |
| Subject: | clarification on the performance of require_once and APC | ||
| Groups: | php.pear.dev | ||
| Request: | Send a blank email to pear-dev+get-47835@lists.php.net to get a copy of this message | ||
Hi,
I just tracked down Rasmus on IRC and asked him lots of questions about
require_once and APC performance. I think that all of the questions
raised in June with reference to require_once were addressed. Here are
the facts:
* Gopal's fix to include_once in APC 3.0.14 *does* improve the
performance of relative include_once when compared to absolute
include_once
(http://t3.dotgnu.info/blog/php/include_once-mostly-harmless.html)
* Gopal's fix to include_once in APC 3.0.14 does *NOT* improve the
performance of include relative to include_once - include_once even with
apc_stat=0 is still slower than include
* The problem that was brought to light by HTML_QuickForm with APC was
that some files were being included both conditionally and
unconditionally. The way APC solved this was simply to not cache the
files or classes within them, obviously resulting in slower
performance. An example of this is when an HTML element extends another
element that is used. The user require_once's a driver, and the other
driver conditionally includes it.
* autoload is slower than direct unconditional include because it is
processed at runtime in the exact way a conditional include is processed
* There is no way to improve the performance of require_once other than
to remove it and use require
With these facts in place, it proves that although the performance
difference is small for most users, using require_once has an
unavoidable performance hit, and the more calls to require_once, the
worse the hit, even with APC in its most optimized state. So yes,
performance of *_once *is* an issue, contrary to earlier assertions
based on Gopal's blog entries.
The best performance is to be achieved by having a single include
statement for each needed file in the entire application.
For users who simply wish to try out a package, performance is not an
issue, they just need to have an easy way to include all needed files.
This should be done on the application level by including allfiles.php,
or by setting up an __autoload().
Unlike PEAR, PEAR2 should support both models equally well. With PEAR,
the best performance is physically impossible, and beginners often need
to require_once several files just to get started.
There were several synthetic benchmarks posted over the summer that
support the relative performance of slow => fast with autoload =>
allfiles.php => custom allfiles.php, there's no need to rehash that
argument. It is also true that the relative "performance" of ease of
getting started is include '/path/to/PEAR2/Package/Name/allfiles.php';
=> set up include_path/__autoload() => custom allfiles.php. In
addition, creating a customized allfiles.php is relatively easy if
autoload is possible. Simply use __autoload() and set up a shutdown
function that var_dumps() get_included_files().
In short, after extensive research, I still support the initial proposal
of removing require_once and adding allfiles.php and a README for each
package.
In my opinion, the next step is to figure out the best way to make this
new system robust in the case of a missing file/class and to document
how it should be used.
I would like each package to have a top-level README.PackageName file,
so that when it is installed or when it is unzipped, this file is easy
to find. For instance:
pyrus install PEAR2_PackageName
PEAR2_PackageName installed into /full/path/to/pear2/ - read
README.PEAR2_PackageName to get started
the README would contain instructions on using allfiles, or on using
__autoload(). This file could be autogenerated at packaging time for
packages that don't have a customized one, as it would be the same for
most packages.
Within each file, dependencies, both internal and external, need to be
clearly documented at the top of the file. Whether this should be done
with only /** */ or additionally with class_exists() and exceptions or
some other code-based solution is a decision that needs to be made. I
would prefer beginning users to see a clear and simple error message if
they try to directly include a file without a missing dependency.
Making this possible in a way that does not adversely affect performance
is important.
That's all for now.
Thanks,
Greg