ID: 40809 Updated by: [EMAIL PROTECTED] Reported By: thuejk at gmail dot com -Status: Open +Status: Assigned Bug Type: Performance problem Operating System: Linux PHP Version: 5.2.1 -Assigned To: +Assigned To: dmitry
Previous Comments: ------------------------------------------------------------------------ [2007-03-14 23:51:42] thuejk at gmail dot com Description: ------------ In some cases, the ".=" operator can have poor performance. I have a production PHP program which a problem which I think is caused by this. Originally a task took 700 seconds to run. Some debug output found that a simple ".=" on a very long string took far too long. Tweaking the memory allocator to round up allocations to the nearest power of 2 decreased the run time to 60 seconds. My tweak was to insert uint pow_2 = 4; while (pow_2 < size) { pow_2 *= 2; } size = pow_2; into the top of _zend_mm_alloc_int() and _zend_mm_realloc_int() (I think) ".=" uses the Zend/zend_operators.c:concat_function() function. This function will reallocate the string with the minimum length needed for each concatenation. My tweaked memory allocator will allocate extra space in advance, which means realloc() returns immediately, which seems to make the difference. I have attached some code which reproduces the performance problem. I am actually not sure exactly what happens. The part for creating MM holes is taken from http://bugs.php.net/bug.php?id=40261 , so this may be the same bug, but I am not sure. Run time of attached test case with and without my tweak: [EMAIL PROTECTED] ~> time /usr/local/php-5.2.1/bin/php evil.php /usr/local/php-5.2.1/bin/php evil.php 1,04s user 0,01s system 99% cpu 1,047 total [EMAIL PROTECTED] ~> time /usr/local/php-5.2.1_clean/bin/php evil.php /usr/local/php-5.2.1_clean/bin/php evil.php 12,30s user 0,02s system 99% cpu 12,323 total Reproduce code: --------------- <?php error_reporting(E_ALL|E_STRICT); $num_increments = 100; $num_repeats = 1000; $increment = 50; /* Create some more holes to give the memory allocator something to * work with. */ $num = 5000; $a = Array(); for ($i=0; $i<$num; $i++) { $a[$i] = Array(1); } for ($i=0; $i<$num; $i++) { $b[$i] = $a[$i][0]; } unset($a); for ($i=0;$i<$num_repeats;$i++) { $evil = ""; for ($j=0;$j<$num_increments;$j++) { $evil .= str_repeat("a", $increment); } unset($evil); } ?> ------------------------------------------------------------------------ -- Edit this bug report at http://bugs.php.net/?id=40809&edit=1