From d13d9b3c24ffeedaa114313eb184ea61323867f3 Mon Sep 17 00:00:00 2001 From: Niels Dossche <7771979+nielsdos@users.noreply.github.com> Date: Sun, 30 Mar 2025 18:09:01 +0200 Subject: [PATCH] Optimize SplFixedArray::toArray() (#18190) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We can use the optimized packed filling code instead of going through all the logic of the zend_hash update APIs. For this script: ```php $test = new SplFixedArray(4); $test[0] = 0; $test[1] = 1; $test[2] = 2; $test[3] = 3; for ($i = 0 ; $i< 5000000; $i++) $test->toArray(); ``` On an i7-4790: ``` Benchmark 1: ./sapi/cli/php toarray.php Time (mean ± σ): 170.0 ms ± 1.8 ms [User: 167.3 ms, System: 2.2 ms] Range (min … max): 166.9 ms … 173.0 ms 17 runs Benchmark 2: ./sapi/cli/php_old toarray.php Time (mean ± σ): 215.7 ms ± 3.6 ms [User: 211.9 ms, System: 3.0 ms] Range (min … max): 211.3 ms … 222.0 ms 13 runs Summary ./sapi/cli/php toarray.php ran 1.27 ± 0.02 times faster than ./sapi/cli/php_old toarray.php ``` On an i7-1185G7: ``` Benchmark 1: ./sapi/cli/php toarray.php Time (mean ± σ): 112.6 ms ± 1.4 ms [User: 109.6 ms, System: 2.9 ms] Range (min … max): 111.1 ms … 116.4 ms 25 runs Benchmark 2: ./sapi/cli/php_old toarray.php Time (mean ± σ): 145.3 ms ± 2.8 ms [User: 141.8 ms, System: 3.4 ms] Range (min … max): 142.6 ms … 151.8 ms 20 runs Summary ./sapi/cli/php toarray.php ran 1.29 ± 0.03 times faster than ./sapi/cli/php_old toarray.php ``` --- ext/spl/spl_fixedarray.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/ext/spl/spl_fixedarray.c b/ext/spl/spl_fixedarray.c index fa846e48eee..b0de1dc4836 100644 --- a/ext/spl/spl_fixedarray.c +++ b/ext/spl/spl_fixedarray.c @@ -695,11 +695,16 @@ PHP_METHOD(SplFixedArray, toArray) intern = Z_SPLFIXEDARRAY_P(ZEND_THIS); if (!spl_fixedarray_empty(&intern->array)) { - array_init(return_value); - for (zend_long i = 0; i < intern->array.size; i++) { - zend_hash_index_update(Z_ARRVAL_P(return_value), i, &intern->array.elements[i]); - Z_TRY_ADDREF(intern->array.elements[i]); - } + array_init_size(return_value, intern->array.size); + HashTable *ht = Z_ARRVAL_P(return_value); + zend_hash_real_init_packed(ht); + + ZEND_HASH_FILL_PACKED(ht) { + for (zend_long i = 0; i < intern->array.size; i++) { + ZEND_HASH_FILL_ADD(&intern->array.elements[i]); + Z_TRY_ADDREF(intern->array.elements[i]); + } + } ZEND_HASH_FILL_END(); } else { RETURN_EMPTY_ARRAY(); }