Repository navigation
Conversation
…rays With the default SORT_REGULAR flag, a packed array whose elements are all integers is now sorted as a plain zend_long buffer, instead of being converted to a hash, sorted as Buckets through comparison and swap callbacks, and converted back. The result is identical: comparing two integers cannot call user code, emit a diagnostic or throw, and since the keys are renumbered, the order of equal integers is unobservable. Holes are squeezed out and the next free key and internal pointer are reset, as the generic path does. Any other array, including one holding a reference, takes the existing path. Runs of 2 to 5 elements are sorted with the branchless sorting networks AlphaDev found for libc++ (Mankowitz et al., Nature 618, 2023), which std::sort uses for arithmetic types. They are only correct for a strict weak ordering, which integer comparison is, so they are not reachable from user comparators. sort() and rsort() on lists of integers become 2-4x faster; other arrays are unaffected. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Hey. I've written the same stuff before #23585. Instead of opening a new PR, can you please review the previous ones? |
Sorry didn't realise - will close this one... |
|
Yeah this is interesting improvements I want to land a while ago and have put my thought into. Do you have any ideas of the (potential) regressions in mixed arrays sortings with our new similiar implementation. Or, will you expect your optimization only land specificly on packed int arrays? |
|
I'm putting aside the code quality and whether these changes are worth it. I just wanted to point out that, technically, the two ideas don't conflict and could be combined. As far as I can tell, they optimize different things in the same area. The other PR (#23585) avoids the packed → hash → packed round trip and sorts packed arrays directly as zvals. This one specializes the sort itself for integers. That said, my guess is that the maintenance cost of a custom, type-specific sort would likely outweigh its gain, since most of the overhead seems to come from the conversion rather than the comparison and swapping. So the int specialization would only be worth considering as a possible follow-up if it turns out to be measurably beneficial on top of your work. |
|
Here's further details, including speed improvements. Feel free to take this code and add into your PR if easier. What changesToday,
The scratch buffer takes 8 bytes per element: Why the result is identical
Sorting networks for 2-5 elementsShort runs are sorted with the branchless sorting networks that AlphaDev found for LLVM's libc++ (Mankowitz et al., Faster sorting algorithms discovered using deep reinforcement learning, Nature 618, 2023). These are
Benchmarksphp-src master (8.7.0-dev,
Run-to-run noise on this machine is a few percent. A 15-process re-run on 8.4 measured the rejected-input cases at −2% to +3%. TestsThe new tests are in
All three pass on unpatched master too, so they pin down existing behaviour. To check that the tests can actually catch bugs, I broke the patch on purpose in six ways:
Each break failed at least one new test, while a behaviour-preserving change passed.
I've only built and tested this on Linux x86-64 with gcc. CI will cover the rest. Possible follow-ups (not in this PR)
|
Have been interested in whether the AlphaDev sorting array algorithm finds from 2023 - https://deepmind.google/blog/alphadev-discovers-faster-sorting-algorithms/ - would benefit PHP at all.
I don't have C skills, but have used Claude to help investigate. For integer-only sorting we have the ability to use this updated algorithm to help speed up these sorts.
Comments below detail the update, but are not my words:
With the default SORT_REGULAR flag, a packed array whose elements are all integers is now sorted as a plain zend_long buffer, instead of being converted to a hash, sorted as Buckets through comparison and swap callbacks, and converted back. The result is identical: comparing two integers cannot call user code, emit a diagnostic or throw, and since the keys are renumbered, the order of equal integers is unobservable. Holes are squeezed out and the next free key and internal pointer are reset, as the generic path does. Any other array, including one holding a reference, takes the existing path.
Runs of 2 to 5 elements are sorted with the branchless sorting networks AlphaDev found for libc++, which std::sort uses for arithmetic types. They are only correct for a strict weak ordering, which integer comparison is, so they are not reachable from user comparators.
sort() and rsort() on lists of integers become 2-4x faster; other arrays are unaffected.