[php-src] Issue #8283: Performance: array_reduce is drastically slower (~1000x) than implementing the same logic with foreach

From: Date: Wed, 30 Mar 2022 21:38:09 +0000
Subject: [php-src] Issue #8283: Performance: array_reduce is drastically slower (~1000x) than implementing the same logic with foreach
Groups: php.bugs 
Request: Send a blank email to php-bugs+get-240583@lists.php.net to get a copy of this message
Issue: https://github.com/php/php-src/issues/8283 Author: Firehed ### Description The following code: ```php <?php declare(strict_types=1); // generate a large sample of pseudo-random data which may have duplicates $data = []; for ($i = 0; $i < 40000; $i++) { $data[] = crc32((string)$i); } echo 'Foreach'; $start = hrtime(true); $result = []; foreach ($data as $item) { @$result[$item]++; } $durationNs = hrtime(true) - $start; echo sprintf('%f s', $durationNs / 1_000_000_000); echo "\n\n"; unset($start, $result, $item, $durationNs); echo 'Array reduce'; $start = hrtime(true); $result = array_reduce($data, function ($carry, $item) { @$carry[$item]++; return $carry; }, []); $durationNs = hrtime(true) - $start; echo sprintf('%f s', $durationNs / 1_000_000_000); ``` Resulted in this output: ``` Foreach 0.007446s Array reduce 8.685649s ``` But I expected this output instead: ``` (comparable runtimes) ``` Possibly impactful opcache ini settings: ``` $ php -i | rg opcache Additional .ini files parsed => /usr/local/etc/php/8.1/conf.d/ext-opcache.ini with Zend OPcache v8.1.3, Copyright (c), by Zend Technologies Zend OPcache opcache.blacklist_filename => no value => no value opcache.consistency_checks => 0 => 0 opcache.dups_fix => Off => Off opcache.enable => On => On opcache.enable_cli => Off => Off opcache.enable_file_override => Off => Off opcache.error_log => no value => no value opcache.file_cache => no value => no value opcache.file_cache_consistency_checks => On => On opcache.file_cache_only => Off => Off opcache.file_update_protection => 2 => 2 opcache.force_restart_timeout => 180 => 180 opcache.huge_code_pages => Off => Off opcache.interned_strings_buffer => 8 => 8 opcache.jit => tracing => tracing opcache.jit_bisect_limit => 0 => 0 opcache.jit_blacklist_root_trace => 16 => 16 opcache.jit_blacklist_side_trace => 8 => 8 opcache.jit_buffer_size => 0 => 0 opcache.jit_debug => 0 => 0 opcache.jit_hot_func => 127 => 127 opcache.jit_hot_loop => 64 => 64 opcache.jit_hot_return => 8 => 8 opcache.jit_hot_side_exit => 8 => 8 opcache.jit_max_exit_counters => 8192 => 8192 opcache.jit_max_loop_unrolls => 8 => 8 opcache.jit_max_polymorphic_calls => 2 => 2 opcache.jit_max_recursive_calls => 2 => 2 opcache.jit_max_recursive_returns => 2 => 2 opcache.jit_max_root_traces => 1024 => 1024 opcache.jit_max_side_traces => 128 => 128 opcache.jit_prof_threshold => 0.005 => 0.005 opcache.lockfile_path => /tmp => /tmp opcache.log_verbosity_level => 1 => 1 opcache.max_accelerated_files => 10000 => 10000 opcache.max_file_size => 0 => 0 opcache.max_wasted_percentage => 5 => 5 opcache.memory_consumption => 128 => 128 opcache.opt_debug_level => 0 => 0 opcache.optimization_level => 0x7FFEBFFF => 0x7FFEBFFF opcache.preferred_memory_model => no value => no value opcache.preload => no value => no value opcache.preload_user => no value => no value opcache.protect_memory => Off => Off opcache.record_warnings => Off => Off opcache.restrict_api => no value => no value opcache.revalidate_freq => 2 => 2 opcache.revalidate_path => Off => Off opcache.save_comments => On => On opcache.use_cwd => On => On opcache.validate_permission => Off => Off opcache.validate_root => Off => Off opcache.validate_timestamps => On => On ``` Note that opcache_get_status() returns false when running this script via CLI, which is where I encountered this. General observation: this doesn't appear to be something that gets incrementally slower the further along the array the algorithm is. By adding an echo '.' in either section, it's apparent that even the very first item (with an empty $carry) is drastically slower in array_reduce than in the body of foreach. I know they're not 100% comparable, but both should have O(n) complexity so I would not expect _three orders of magnitude_ performance difference to produce the same result. ### PHP Version 8.1.3 ### Operating System macOS 12.3

« previous php.bugs (#240583) next »