Benchmarking
Why use a PHP accelerator?
1To understand how a PHP accelerator works the best place to start is looking at how PHP code is executed by the web server. In it’s simplest form it is something like this:
Open PHP file(s) -> Parse/Compile PHP code to bytecode -> Execute bytecode
Generally what a PHP accelerator will do is store the compiled bytecode either on disk or in shared memory which almost completely eliminates the first to execution steps above. Generally the process to load a page stored in cache will be as follows:
Check file modification time of original script -> Read file from cache -> Execute bytecode
Using an accelerator with PHP can produce some fairly substantial speed improvements by removing the need to parse/compile every script prior to execution. To demonstrate this improvement with an example, the graph below shows the results of the Hello World benchmark, from the benchmarks section of this site:
The blue bars are a standard PHP configuration without any optimisation.
The red bars are when Zend Optimizer+ is enabled within Zend Server CE.
In this example it is evident that with bytecode caching enabled, in this case using Zend Optimizer+, there is a considerable speed increase for every framework tested for this benchmark.
Every microsecond counts
0This evening the config caching was cleaned up and re-factored, resulting in a 200 µs (0.2 ms) speed increase on the Hello World benchmark. This might seam like a tiny amount, but considering the previous load time was around 4.5 ms with Optimizer+ enabled this actually equates to almost a 5% speed increase, which in programming terms is good improvement. This improvement is obviously not going to be noticeable to the human eye, but considering it in terms of a real world application every 1,000,000 page loads we have saved the server 200 seconds of processing time.
Optimising ini parsing
0A great way to store application config, but unfortunately a better way of slowing down the application. Parsing and accessing ini files is somewhat of a heavy process, here is a webgrind output using a stripped down version of the Zend Framework Zend_Config_Ini class:
The main reason for the long processing time of these functions is that they are riddled with recursive functions, which quickly add up. Unfortunately there is little that can be done about the processing time, but there are other possibilities.
The first and most obvious optimisation is to cache the parsed config file, completely eliminating the processing overhead. By default all config files are parsed and saved in a serialised state in the cache directory, this can be switched for Memcache and possibly SHM at a later stage.
The second optimisation that provides a nice speed boost is to change the way the data is stored, multiple calls to the __get magic method soon start to add up and become a bottleneck. For this reason I changed the big array of objects into a simple array structure, leaving the __get magic method so that the top level configuration data can still be accessed in an object format.
For example to access a field called param within session configuration data from the parsed config in LiteMVC we can do the following:
$sessionConfig = $config->session;
$sessionParam = $sessionConfig['param'];
This maintains a nice level of usability while almost completely eliminating data access processing overheads. As often using Zend Framework it’s necessary to use the toArray method (another recursive function) this is also completely eliminated as data is already in array form.
Here is a webgrind output showing the new ini parser with file caching, taking just 367 microseconds to load the configuration:


