From:             thuejk at gmail dot com
Operating system: Linux
PHP version:      5.2.1
PHP Bug Type:     Performance problem
Bug description:  Poor perfomance of ".="

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 bug report at http://bugs.php.net/?id=40809&edit=1
-- 
Try a CVS snapshot (PHP 4.4): 
http://bugs.php.net/fix.php?id=40809&r=trysnapshot44
Try a CVS snapshot (PHP 5.2): 
http://bugs.php.net/fix.php?id=40809&r=trysnapshot52
Try a CVS snapshot (PHP 6.0): 
http://bugs.php.net/fix.php?id=40809&r=trysnapshot60
Fixed in CVS:                 http://bugs.php.net/fix.php?id=40809&r=fixedcvs
Fixed in release:             
http://bugs.php.net/fix.php?id=40809&r=alreadyfixed
Need backtrace:               http://bugs.php.net/fix.php?id=40809&r=needtrace
Need Reproduce Script:        http://bugs.php.net/fix.php?id=40809&r=needscript
Try newer version:            http://bugs.php.net/fix.php?id=40809&r=oldversion
Not developer issue:          http://bugs.php.net/fix.php?id=40809&r=support
Expected behavior:            http://bugs.php.net/fix.php?id=40809&r=notwrong
Not enough info:              
http://bugs.php.net/fix.php?id=40809&r=notenoughinfo
Submitted twice:              
http://bugs.php.net/fix.php?id=40809&r=submittedtwice
register_globals:             http://bugs.php.net/fix.php?id=40809&r=globals
PHP 3 support discontinued:   http://bugs.php.net/fix.php?id=40809&r=php3
Daylight Savings:             http://bugs.php.net/fix.php?id=40809&r=dst
IIS Stability:                http://bugs.php.net/fix.php?id=40809&r=isapi
Install GNU Sed:              http://bugs.php.net/fix.php?id=40809&r=gnused
Floating point limitations:   http://bugs.php.net/fix.php?id=40809&r=float
No Zend Extensions:           http://bugs.php.net/fix.php?id=40809&r=nozend
MySQL Configuration Error:    http://bugs.php.net/fix.php?id=40809&r=mysqlcfg

Reply via email to