ext/standard: Optimize sort(), rsort() and usort() for packed arrays - #23585
ext/standard: Optimize sort(), rsort() and usort() for packed arrays#23585LamentXU123 wants to merge 3 commits into
Conversation
c8a0784 to
f4dc3c4
Compare
f4dc3c4 to
e43223d
Compare
|
Nice to see faster sorting. In PHPStan profiles we see slow sorting in https://github.com/phpstan/phpstan-src/blob/2.3.x/src/Type/TypeCombinator.php in most profiles (which is not sorting on pure integers though) |
|
Okay this is now completed. |
d9e2539 to
6dcbecd
Compare
2187f7c to
8431424
Compare
Avoid the packed-to-mixed-to-packed round trip in sort(), rsort() and usort(), without an array-size threshold. Share the value comparison implementations and flag dispatch with the existing Bucket comparators, retaining stable ties and protection across calls to user code. Keep the metadata-free integer specialization private. Built-in sorts of direct scalars and strings skip the lifetime pin and GC root registration; NaN remains on the protected path because coercion warnings can call an error handler. Empty and single-element inputs skip unnecessary comparison setup while retaining the required pointer and next-free-index behavior. Both packed APIs compact holes, initialize stable-sort positions and relocate active iterators, including past-the-end cursors. The relocation loop includes cursors at the current source index after cursors on preceding holes; the corresponding fixes in legacy rehash and duplication are handled separately. Arrays without holes only initialize stable-sort positions. Document numeric-index visibility during implicit comparison callbacks. Cover comparison modes, stable ties, references, holes, iterator relocation, append metadata, exceptions, reentrancy and single-element inputs in PHPTs.
8431424 to
232718b
Compare
|
would it make sense to add benchmark numbers for the case when sorting a array of objects? |
|
I know how to add object in this optimization case but it seems like it's quite annoying cuz it will cause bugs and inevitably break things. Now, sorting object's performance should be unchanged (except in usort. If you are sorting objects in usort it should be faster.). |
TL;DR: This PR completely implements a sort internally, but using only zvals. sort(), rsort(), and usort() now avoid converting packed arrays to mixed storage while sorting.
After the last trivial one-element optimization I get to be familiar with how sort works in Zend. So, now, except the array is empty or only has one element, we convert arrays to mixed storage before sorting, and convert them back after we sort them.
The reason we are doing this is because the internal sorting functions is using Buckets, so we can preserve the keys when sorting the values. Packed arrays (most cases we are sorting them instead of unpacked and mixed arrays), are sequence zvals, and don't have customized keys.
This let me thinking. Can we just implement a sort internally which completely works with zvals and not Buckets? So we don't need to convert them to Bucket and convert them back again when sorting packed arrays that don't have external keys at all?
I have a idea to implement a sort works with packed arrays entirely depending on zvals. There it is. The benchmark results:
sort:
intfloatstringrsort:
intfloatstringusort:
intfloatstringbenchmark.php