Poor date() performance (v 5.4.9) [PATCH]

From: Date: Sat, 01 Dec 2012 18:06:40 +0000
Subject: Poor date() performance (v 5.4.9) [PATCH]
Groups: php.internals 
Request: Send a blank email to [email protected] to get a copy of this message
I am migrating from 4.4.9 to some new servers I built out, and wrote a
benchmark suite that is testing many individual aspects of PHP so I
could see what sort of performance benefits I might see not only from
the new server, but moving off my custom forked 4.4.9 branch. Here's a
snippet of some of the comparisons: (sorry for the poor formatting) --
each test is run using 1 million loops.

4.4.9 on old machine vs 5.4.9 on new machine:
for                     : 0.213 sec	for                     : 0.019 sec
while                   : 0.145 sec	while                   : 0.014 sec
if else                 : 0.449 sec	if else                 : 0.069 sec
switch                  : 0.547 sec	switch                  : 0.087 sec
Ternary                 : 0.418 sec	Ternary                 : 0.066 sec
str_replace             : 1.043 sec	str_replace             : 0.421 sec
preg_replace            : 3.627 sec	preg_replace            : 1.678 sec
preg_match              : 1.250 sec	preg_match              : 0.509 sec

As you can see, the new machine is considerably faster, and there are
no major issues with wanting to switch... until I get to the date
functions I make frequent use of:
date                    : 1.856 sec	date                    : 2.111 sec
strtotime               : 2.963 sec	strtotime               : 3.133 sec

and just to test (though I don't currently use it):
strftime                : 2.679 sec	strftime                : 1.764 sec

The former two actually are slower on the new box and newer version of
php, when everything else is 2 to 200x faster.

Relevant code to the functions: (tested with and without the $now
parameter -- which makes no perceptible difference)
date('F j, Y, g:i a', $now);
strftime('%B %e, %Y, %l:%M %P', $now);

This type of formatting is pretty common. I started digging into the
source code, and found an obvious place where there was a performance
issue:
timelib_isoweek_from_date(t->y, t->m, t->d, &isoweek, &isoyear);
is being called every time, even though it's only used in two rather
obscure cases, and ones that are probably very uncommon in actual
practice. So, to test, I created a "is set" type variable, and moved
the function call into each case, with a condition checking if it was
already populated, if not, call the function to populate isoweek and
isoyear, then resume as before. (Patch will be attached as a file)

I then recompiled and reran my benchmark and here is the result:
date: 1.763 sec
Which is a performance increase of nearly 20%.

My patch was thrown together rather quickly to just do a quick test,
so it may warrant some tweaking before being applied to any branches.
I plan to continue digging, as I feel that I should be able to
continue to improve the performance of these functions further. The
rest will be a little less obvious, is there is much more cross
functionality issues to contend with to ensure nothing is broken.

Side note- I attempted the same concept with not setting the timezone
information if those flags were not used in the switch (which they
aren't in anything I use), but it didn't appear to have any noticeable
performance increase. My next step is to start tracing through actual
execution and see if I can't find any other obvious issues. My initial
thoughts are that it may be faster to try and cache some of this (for
fcgi purposes), or even have a compile time option to allow a build to
use old 4.4.9 functionality that uses localtime_r() and actually
trusts that the server has the right information set.

Thanks in advance for looking at this with me!


Thread (6 messages)

« previous php.internals (#64127) next »