Skip to content

Improve array_reduce() consume carry#21340

Open
drealecs wants to merge 2 commits intophp:masterfrom
drealecs:improve-array-reduce-consume-carry
Open

Improve array_reduce() consume carry#21340
drealecs wants to merge 2 commits intophp:masterfrom
drealecs:improve-array-reduce-consume-carry

Conversation

@drealecs
Copy link

@drealecs drealecs commented Mar 4, 2026

Related to #8283

For some callback operations, it is safe to consume/reuse a value passed as a parameter instead of copying it first.
This PR adds a generic internal mechanism for that (zend_fcall_info.consume_params) and applies it to array_reduce() carry handling.

This reduces copy-on-write churn and significantly improves array_reduce() performance for mutable accumulator patterns, while keeping userland semantics unchanged.

The same mechanism can be used in other callback-heavy paths in follow-up changes.

@drealecs drealecs force-pushed the improve-array-reduce-consume-carry branch 2 times, most recently from 86f212d to 2f9aa58 Compare March 4, 2026 17:24
@drealecs drealecs changed the title Draft: Improve array_reduce() consume carry Improve array_reduce() consume carry Mar 4, 2026
@drealecs drealecs force-pushed the improve-array-reduce-consume-carry branch from 2f9aa58 to 3299db5 Compare March 4, 2026 18:55
@TimWolla
Copy link
Member

TimWolla commented Mar 4, 2026

Can you provide the benchmark you used to verify this improves the situation?

@drealecs
Copy link
Author

drealecs commented Mar 5, 2026

Can you provide the benchmark you used to verify this improves the situation?

Yes, this is a good point.
Here is a simple test I used locally:

<?php

declare(strict_types=1);

function test($size) {
    $data = [];
    for ($i = 0; $i < $size; $i++) {
        $data[] = substr(hash('crc32b', (string) $i), 0, 4);
    }

    $start = hrtime(true);
    $result = array_reduce(
        $data,
        static function ($carry, $item) {
            @$carry[$item]++;
            return $carry;
        },
        [],
    );
    $duration = hrtime(true) - $start;

    printf("size=%d, unique=%d, duration=%.3f ms\n", $size, count($result), $duration/1_000_000);
}

test(10_000);
test(20_000);
test(40_000);

On master, this is the output:

$ ./sapi/cli/php test_array_reduce.php
size=10000, unique=9980, duration=1199.907 ms
size=20000, unique=19084, duration=4844.224 ms
size=40000, unique=34066, duration=19404.972 ms

and we can see that the complexity is O(n^2).

On this branch, this is the output:

$ ./sapi/cli/php test_array_reduce.php
size=10000, unique=9980, duration=9.108 ms
size=20000, unique=19084, duration=18.905 ms
size=40000, unique=34066, duration=35.392 ms

with O(n) complexity.

@drealecs drealecs force-pushed the improve-array-reduce-consume-carry branch from 3299db5 to cdbe42a Compare March 5, 2026 11:53
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants