Press "Enter" to skip to content

Optimizations in the Zend Engine (PHP 5.4)

In the PHP 5.4 changelog, there's a line: improved the performance of the Zend engine, reduced memory usage.
So, how exactly was it improved?

Avoiding unnecessary Hashtables

We know that in PHP, a class's properties / static properties / constants are all stored in a Hashtable. In the past, even if a class declared no properties / static properties / constants, the Zend engine would still allocate a Hashtable for them.
Now, this process has been optimized — a Hashtable is only allocated when there are elements.
This avoids some emalloc/efree operations and reduces some memory usage.

Quadruple (opcode) optimization

In PHP, what actually gets executed are Opcodes. An Opcode contains 3 fixed operands: result, left, right. In the past, each of these 3 operands contained a zval. Even when it wasn't used at all — for example, when there was no right operand — a zval would still be allocated for the right operand.
Now, all the operands will no longer directly contain a zval, but instead contain a pointer into a literal table. Each op array contains one literal table.
And the znode has also been adjusted accordingly.
This way, it also reduces some memory usage. From previously (on a 32-bit OS) one opcode taking 72 bytes, to now 28 bytes.
In addition, for strings, the literal table will also store a pre-computed hash value of the string, avoiding computing it multiple times at runtime. This improves a portion of the performance.

Literal strings

Just like in the C language, where literal strings in code are stored in a fixed section (the data section), and throughout the entire execution period these strings are constant strings — they cannot be modified and cannot be freed.
PHP borrows this idea, introducing the concept of an Internal string. Literal strings in PHP code are allocated once, and throughout the entire execution period they cannot be modified.
When PHP does copy_zval, free zval and other operations, it specially handles internal strings to avoid unnecessary frees and copies.
And the hash values of these literal strings are pre-computed. This way, for string comparison (==) and hash computation in a hashtable, this pre-computed hash value can be used directly, improving a portion of the performance.

Other

Of course, there are many more optimization points, for example optimizing the opcodes and reducing some unnecessary opcodes. I won't enumerate them all here.

Comparison

Here's some data from internal testing by the PHP dev team:
Native PHP, no Opcode Cache:

php-trunk patched inprovement
bench.php (sec) 4.31 3.49 19%
micro_bench.php (sec) 19.78 14.63 26%

Some real-world applications:

php-trunk pathced improvement
blog (req/sec) 59.3 66.2 12%
drupal (req/sec) 1073.9 1084.8 1%
fw (req/sec) 105.3 111.8 6%
hello (req/sec) 5362.5 5351.4 0%
qdig (req/sec) 243.4 253.7 4%
typo3 (req/sec) 355.3 382.6 8%
wordpress (req/sec) 101.8 108.5 7%
xoops (req/sec) 70.3 78.5 12%
scrum (req/sec) 86.5 104.2 20%

From this data, the performance improvement is quite clear..

Be First to Comment

Leave a Reply

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

This site uses Akismet to reduce spam. Learn how your comment data is processed.