strange PHP behaviour with global array

In this forum members can discuss topics about specific programming languages.
Post Reply
mbr001
Posts: 3
Joined: Wed Dec 23, 2015 11:33 am

strange PHP behaviour with global array

Post by mbr001 » Fri Dec 25, 2015 10:37 am

Hi all,
while trying to optimize a Project Euler problem,I stumbled upon a problem, I dont understand.
consider the following code

Code: Select all

<?php
header("Content-Type:text/plain");
set_time_limit(200);
$time_start = microtime(true);
ini_set('memory_limit', '2048M');

$x = 10000;
$a = makeArray($x);

$time_end = microtime(true);
echo "Call makeArray(".$x.") : ".($time_end - $time_start)." s\n";

$time_start = microtime(true);

$sum = sumArray($a);

$time_end = microtime(true);
echo "Calculate with sumArray() : ".$sum." :".($time_end - $time_start)." s\n";

$time_start = microtime(true);

	$sum = 0;
	//$lim = count($a);
	for($i=0;$i<count($a);$i++)
	{
		$sum += $a[$i];
	}
	
$time_end = microtime(true);
echo "direct Calulation : ".$sum." : ".($time_end - $time_start)." s\n";


function makeArray($x)
{
	for($i=0;$i<$x;$i++)
	{
		$a[] = $i;
	}
	return $a;
}

function sumArray(&$a)
{
	$sum = 0;
	//$lim = count($a);
	for($i=0;$i<count($a);$i++)
	{
		$sum += $a[$i];
	}
	return $sum;
}

?>
In my opinion, both calculations should have roughly the same timing, but the output is:

Call makeArray(10000) : 0.0089700222015381 s
Calculate with sumArray() : 49995000 :10.526546001434 s
direct Calulation : 49995000 : 0.0033800601959229 s

I Expected that there would be a very slight overhead, because of calling the function and perhaps copying the array, but I thought that should be very small, if not unmeasureable at all.

So can anyone tell me, why the huge performance hit occurs?
Edit: I just figured out that it has something to do with calling the count() function in the loop. But I do not fully understand the effect. When using the outcommented line and comparing to the $lim variable in the loop, I get the following:

Call makeArray(10000) : 0.0067830085754395 s
Calculate with sumArray() : 49995000 :0.0027248859405518 s
direct Calulation : 49995000 : 0.0012359619140625 s

But I still dont get it, why this change impacts the function call this massive, while the effect in the direct calculation is comparable small...

TripleM
Posts: 382
Joined: Fri Sep 12, 2008 2:31 am

Re: strange PHP behaviour with global array

Post by TripleM » Fri Dec 25, 2015 10:43 pm

While the count function is O(1), it's still several times slower than using a variable. You're calling the count function 10000 times within the loop, so the effect is magnified.

mbr001
Posts: 3
Joined: Wed Dec 23, 2015 11:33 am

Re: strange PHP behaviour with global array

Post by mbr001 » Sat Dec 26, 2015 10:18 am

Hello TripleM,
thank you for your reply.
TripleM wrote:While the count function is O(1), it's still several times slower than using a variable. You're calling the count function 10000 times within the loop, so the effect is magnified.
So I realize that using count in a loop is a big mistake in terms of performance. But what still amazes me is the fact that replacing the count() by a precalculated variable in the "main" function changes the speed by a factor of roundabout 2.7 while in the function "sumArray()" it improves speed by the factor of roundabout 3829. Thus my original problem being solved (solution for Problem 72 (View Problem) runs in 53 s now instead of 10 minutes :D ) I would like to understand the inner workings of PHP in this case.

User avatar
euler
Administrator
Posts: 3071
Joined: Sun Mar 05, 2006 4:49 pm
Location: Cheshire, England
Contact:

Re: strange PHP behaviour with global array

Post by euler » Sat Dec 26, 2015 12:03 pm

I don't know the answer myself, so I'd like to know what is going on too. If I had to guess then I suspect it is to do with needing to continually "reach outside the function" each time you use count() to determine the size of the array. Because you are passing the array by reference then it may have to recalculate the dimension of the array each time the function is used, whereas using the count function with a local variable PHP knows it hasn't changed in size and so after the first call it caches the value.

Interestingly, if I don't pass the array to sumArray by reference: sumArray(\$a) instead of sumArray(&\$a), then the time difference is negligible with the direct calculation. Also quite interesting on my machine is that if I remove the pass-by-reference but then explicitly declare the array as global: global $a, within the sumArray function, then it is about 50 ms slower than using the pass-by-reference.
Image
impudens simia et macrologus profundus fabulae

TripleM
Posts: 382
Joined: Fri Sep 12, 2008 2:31 am

Re: strange PHP behaviour with global array

Post by TripleM » Sat Dec 26, 2015 11:24 pm

Hm, I see what you mean. That is strange.

It doesn't appear to be anything to do with the count function (or what that function does) - it looks like someone else found the same applies even to an empty function, when a reference to a large array is used: https://gist.github.com/ihabunek/6375653

Edit - I suspect this may contain the answer: https://flyleafbd.wordpress.com/2011/06 ... variables/ . It seems as if creating a reference can, on certain occasions, still require creating a duplicate of the entire data, while conversely passing by value doesn't necessarily.

mbr001
Posts: 3
Joined: Wed Dec 23, 2015 11:33 am

Re: strange PHP behaviour with global array

Post by mbr001 » Sun Dec 27, 2015 9:18 am

Wow, thank you very much for all of your answers
I never thought that I would receive this much attention with such an obscure problem. I did a quick googling myself before, but was not very successfull (used something like "PHP global arrays performance" as search keywords). So thanks again for all of your efforts. Of course, I will continue to investigate. Especially the second link from TripleM looks very promising in explaining the behaviour - and that means that some of my assumptions on performance are terribly wrong.

One thing, I forgot: I am using PHP 5.3.8 on a XAMPP System - should have mentioned that earlier - just in case the behaviour is not reproducible

Post Reply