|Making PHP go faster
||[Saturday 8th February 2014 at 7:54 pm]
|||||Waltz of the Boos ~ Super Mario Galaxy Original Soundtrack||]|
The story so far: trying to make PHP run faster on a ReadyNAS Duo. Now, when it comes to optimising software there's two rules:
1. Don't optimise
2. Don't optimise yet
What this really means is that you shouldn't just blindly attempt to optimise your code without first knowing which parts of it are actually slow. For example, you may have some function that when you look at the source code is obviously very slow, but in practice it may always be called in a way that means it runs quickly (for example, a bubble sort which only ever sorts 3 items). On the other hand, you might have an algorithm that is usually fast but you just happen to use it in such a way that makes it very slow (for example, a hash map where every element has the same hash code).
Now, my suspicion is that the main slowness is due to PHP having to read in and parse umpteen bajillion source files whenever I pull up a page on HomePortal, as Craig wrote it in a shiny new object-orientated style using the Code Igniter framework, and in PHP that means lots of source files scattered across multiple directories. And as best as I can tell, every time I pull up a page PHP has to re-read every single source file, parse and convert it to PHP bytecode, then interpret it. Funnily enough these are all rather slow things to do.
I'm feeling like doing this properly, so rather than playing around with PHP caches I'm actually going to start by installing a PHP profiler. That way I can (hopefully) find out what's really causing the slowness.
The internets suggested Xdebug, so I'm giving that a try. There doesn't appear to be a prebuilt package that works on my system but the folks at Xdebug have rather nicely written a wizard that looks at your phpinfo and comes up with some mostly-accurate instructions. In my case it tells me to download Xdebug, run phpize (whatever that does), then do the usual ./configure, make followed by telling PHP to use the new module. The downside is this means compiling code, but since the ReadyNAS is running a real Debian install I can just do apt-get install g++ and hey presto, I have a C++ compiler! Of course, there's more to it than that...
The first pitfall came when running phpize (which I installed by running apt-get install php5-dev):
PHP Api Version: 20041225
Zend Module Api No: 20060613
Zend Extension Api No: 220060519
Can't locate File/Compare.pm in @INC (@INC contains: /usr/share/autoconf /etc/perl /usr/local/lib/perl/5.8.8 /usr/local/share/perl/5.8.8 /usr/lib/perl5 /usr/share/perl5 /usr/lib/perl/5.8 /usr/share/perl/5.8 /usr/local/lib/site_perl .) at /usr/share/autoconf/Autom4te/FileUtils.pm line 136.
BEGIN failed--compilation aborted at /usr/share/autoconf/Autom4te/FileUtils.pm line 136.
Compilation failed in require at /usr/bin/autom4te line 42.
BEGIN failed--compilation aborted at /usr/bin/autom4te line 42.
For some bizarre reason, my NAS' Perl install is missing a core Perl module. Easily solved with apt-get install --reinstall perl-modules, and on to the next fail:
Lots of tests...
checking build system type... ./config.guess: unable to guess system type
This script, last modified 2005-04-22, has failed to recognize the operating system you are using. It is advised that you download the most up to date version of the config scripts from
If the version you run (./config.guess) is already up to date, please send the following data and any information you think might be pertinent to <firstname.lastname@example.org> in order to provide the needed information to handle your system.
I suppose the NAS is running on a somewhat obscure platform - it's using a SPARC processor, and I'd only ever heard of those on Sun servers. The NAS was also first released a bit more recently than 2005! Anyway, those links are actually obsolete, as I found when I downloaded those files and re-ran configure just to get the same failure. The correct links are http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess;hb=HEAD and http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub;hb=HEAD. With that done configure seems happy to detect a "sparc-unknown-linux-gnu" system and spit out a Makefile. Which even seems to build something!
So, copy xdebug.so to the PHP library folder, add a line to php.ini, restart the webserver with /etc/init.d/frontview restart (frontview is what Netgear call the admin interface) and... PHP still works!
Right, time to profile the script. Xdebug suggest using either KCacheGrind or WinCacheGrind to view the output - I'm going for the latter as it actually has a Windows installer (KCacheGrind claims it works on Windows but they don't have a pre-built binary). To enable profiling add xdebug.profiler_enable = 1 and xdebug.profiler_output_dir = /c/website/profile/ to php.ini, restart the webserver again, and then just point a browser at a webpage to test.
And amazingly it all Just Works!
Now to puzzle through the output and see what's really slowing things down - from a quick glance, it seems that my original guess may not be entirely accurate...