From:             lee at projectmastermind dot com
Operating system: Linux, OSX
PHP version:      6SVN-2010-02-01 (snap)
PHP Bug Type:     Performance problem
Bug description:  no-op cast triggers copy-on-write

Description:
------------
given a value with a particular type, casting it to that same type 
should essentially be a no-op -- once it is determined that the 
operand already has the correct type, no further action needs to be 
taken.

Ex:
  $a = array();
  $b = (array)$a;

In this example, $a is already an array, so this should be a simple 
assignment operation.  $b should get a "lazy" copy of $a via PHP's 
copy-on-write policy.  Instead, the cast operation seems to force an 
immediate (non-lazy) full copy.

This creates a huge potential for hidden performance problems, as it 
causes code that *looks* like it would run in constant time [O(1)] to 
actually require linear time [O(n)] (where n represents the size of 
the data being copied).

I have verified that this issue does exist for string types as well.  
I assume that it applies to all PHP types.

Of course it becomes a significant performance issue primarily for 
types that can hold large amounts of data, where the data is 
duplicated whenever the zval is duplicated (AFAIK, this is only string 
and array).

I have verified this on the following versions of php:
  5.2.6
  5.2.8
  6.0.0-dev (php6.0-201001312130)



Reproduce code:
---------------
<?php

for( $z=1; $z<5; ++$z ) {
   $a = array_fill(0, 100*$z, '0');

   $t_start = microtime(true);
   for($i=0;$i<100000;++$i) {

      // O(n) [should be constant time, but isn't]
      // cast triggers non-lazy copy
      //
      $b = (array)$a;

      // O(1) [constant time, as expected]
      // (comment above, and uncomment here for comparison)
      //
      //$b = $a;
   }
   $t_elapsed = (microtime(true)*1000)-($t_start*1000);
   printf(
      "(%d elements * %d copies): %f ms\n\n", 
      100*$z, $i, $t_elapsed
   );
}



Expected result:
----------------
(100 elements * 100000 loops): 11.264160 ms

(200 elements * 100000 loops): 11.363037 ms

(300 elements * 100000 loops): 11.208984 ms

(400 elements * 100000 loops): 11.809082 ms


NOTE: the time stays roughly constant as the number of elements 
increases -- the assignments are copy-on-write, so no significant 
performance hit is incurred.


Actual result:
--------------
(100 elements * 100000 copies): 736.453613 ms

(200 elements * 100000 copies): 1448.991211 ms

(300 elements * 100000 copies): 2130.541016 ms

(400 elements * 100000 copies): 2823.362793 ms


NOTE: the time increases as the size of the array increases.  (This 
happens with large strings too).  This is a good indicator that a copy 
is being made [non-lazily] when the cast is applied.


-- 
Edit bug report at http://bugs.php.net/?id=50894&edit=1
-- 
Try a snapshot (PHP 5.2):            
http://bugs.php.net/fix.php?id=50894&r=trysnapshot52
Try a snapshot (PHP 5.3):            
http://bugs.php.net/fix.php?id=50894&r=trysnapshot53
Try a snapshot (PHP 6.0):            
http://bugs.php.net/fix.php?id=50894&r=trysnapshot60
Fixed in SVN:                        
http://bugs.php.net/fix.php?id=50894&r=fixed
Fixed in SVN and need be documented: 
http://bugs.php.net/fix.php?id=50894&r=needdocs
Fixed in release:                    
http://bugs.php.net/fix.php?id=50894&r=alreadyfixed
Need backtrace:                      
http://bugs.php.net/fix.php?id=50894&r=needtrace
Need Reproduce Script:               
http://bugs.php.net/fix.php?id=50894&r=needscript
Try newer version:                   
http://bugs.php.net/fix.php?id=50894&r=oldversion
Not developer issue:                 
http://bugs.php.net/fix.php?id=50894&r=support
Expected behavior:                   
http://bugs.php.net/fix.php?id=50894&r=notwrong
Not enough info:                     
http://bugs.php.net/fix.php?id=50894&r=notenoughinfo
Submitted twice:                     
http://bugs.php.net/fix.php?id=50894&r=submittedtwice
register_globals:                    
http://bugs.php.net/fix.php?id=50894&r=globals
PHP 4 support discontinued:          http://bugs.php.net/fix.php?id=50894&r=php4
Daylight Savings:                    http://bugs.php.net/fix.php?id=50894&r=dst
IIS Stability:                       
http://bugs.php.net/fix.php?id=50894&r=isapi
Install GNU Sed:                     
http://bugs.php.net/fix.php?id=50894&r=gnused
Floating point limitations:          
http://bugs.php.net/fix.php?id=50894&r=float
No Zend Extensions:                  
http://bugs.php.net/fix.php?id=50894&r=nozend
MySQL Configuration Error:           
http://bugs.php.net/fix.php?id=50894&r=mysqlcfg

Reply via email to