[php-src] PR #23947: Speed up zend_hash_iterator_add() when iterators are nested
| From: | nicolas-grekas | Date: | Sun, 27 Sep 2026 15:38:17 +0000 |
| Subject: | [php-src] PR #23947: Speed up zend_hash_iterator_add() when iterators are nested | ||
| Groups: | php.git-pulls | ||
| Request: | Send a blank email to git-pulls+get-38858@lists.php.net to get a copy of this message | ||
Pull Request: https://github.com/php/php-src/pull/23947
Author: nicolas-grekas
zend_hash_iterator_add() looks for a free slot in EG(ht_iterators) starting from slot 0 every time,
so a foreach by reference, a foreach over object properties, an ArrayIterator or array_walk() pays
one probe per iterator that's already alive.
This adds EG(ht_iterators_free_hint): all slots below it are in use, zend_hash_iterator_add() starts
looking from there and zend_hash_iterator_del() lowers it. The returned slot is still the lowest
free one, so slot indexes and EG(ht_iterators_used) don't change.
Found while profiling #23945: a recursive walk of 17.6k Twig nodes, each iterated through
new
ArrayIterator($this->nodes), spends 2.4M instructions in zend_hash_iterator_add()/del().
That's 1.5M with this patch, -1.2% on the whole walk (callgrind).
Instructions per foreach ($a as &$v) {} over a 1-element array, nested in d-1 other
loops by reference: 364 -> 365 at d=1, 389 -> 370 at d=5, 464 -> 369 at d=20. Same savings
per loop for ArrayIterator, foreach over properties and array_walk().