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

Reply via email to