Speeple » Join Speeple | People | Groups | Blogs | News

Speeple Core

Compiling PHP – PHP Performance Optimization

PHP like any other scripting or programming language can be optimized to improve performance. In this series of blog posts I hope to highlight the areas where PHP can be optimized. I won’t go into details of PHP output caching (which can of course lead to massive performance improvements) – mainly because after the initial cache PHP plays only a minor role. This series of posts will target dynamic PHP scripts where output caching (e.g. due to constantly changing data etc.) isn’t an option.

Compiling PHP

The performance of PHP is ultimately determined by the PHP interpreter itself. PHP is open source software written in the C programming language. Taking steps to make sure a fast binary is compiled is the first step to improving overall PHP performance.

The popularity of PHP has resulted in the availability of pre-compiled binaries across the myriad of operating systems in use today. Pre-compiled binaries are very convenient – especially when setting up a development environment quickly; unfortunately they don’t allow you to squeeze out every drop of performance which is desired in production environments. The problem with pre-compiled binaries is that they include a lot of features that may not be required and might not be optimized optimally for your setup.

Compiling PHP directly from source allows you to adjust compiler settings and functionality specific to your server environment. This can result in smaller PHP binaries & shared object files which are optimized to run on your system architecture.

C compilers support levels of optimization ranging from none to very aggressive. Using the “-O3” optimization flag on the GCC/Intel C++ compilers can result in some performance gains; the drawback is that more often than not the resulting compiled output file size is larger in comparison to using the default compiler settings. Sometimes using optimization flags can produce slower binaries; more often than not the default “-O2” optimizations perform equally to “-O3”.

Modern CPU’s include several new instruction set extensions which compilers can take advantage of, e.g. SSE3 and MMX. These provide low level opcodes operations for certain CPU tasks which can improve performance by requiring less CPU cycles. GCC supports several of these extensions and can be turned on using the flags “-msse -mmmx -msse2 -msse3” – your CPU of course must support these extensions (as do most modern Intel / AMD CPU’s). Intel supports the extensions by using the “-xX” range of compiler flags.

The Intel C/C++ compiler software can further improve performance on systems with Intel and some AMD CPU’s. Compiler flags specific to the Intel C/C++ compiler include “-fast” which turns on very aggressive optimizations such as interprocedural optimization (IPO) and “-parallel” (which attempts to auto-parallelize algorithms); both can be used when building PHP. The Intel C++ compiler software ships with proprietary libraries which are optimized for certain architectures. Using the Intel C++ compiler and these libraries can increase performance in comparison to the standard GNU libraries; most noticeably in memory operations.

The GNU C compiler, GCC, and Intel’s C/C++ software both allow tuning the compiler optimizations based on architecture and model. GCC provides “-march=X” and Intel C/C++ has “-mtune=X”. These help the compilers produce binaries intended to run on the target architecture and in some cases might improve performance.

The flag “-ftree-parallelize-loops=X” is available in newer versions of GCC and may improve performance by auto-parallelizing loops where possible. I haven’t tested this particular compiler flag (it’s not supported in my version of GCC) nor do I know for certain whether the PHP C code base contains code which can take advantage of this functionality.

Real world performance gains can be observed when using software compiled by the Intel C++ compiler software but this is often very modest. For those that champion free non-proprietary software, the GNU suite of compiler tools is a worthy adversary and thanks to the nature of the open source community gets better with each release.

Disabling unnecessary functionality that you will never use can help reduce the size of the PHP binaries. It may also improve the speed of function lookups in the internal PHP function hash table. Removing functionality sometimes bypasses code that is no longer required by the compiler. This can have positive effects on security because the potential for something to go wrong or software bugs decreases – security threats on functionality that you chose to disable simply ceases to exist.

For Speeple I compile PHP with very limited functionality past the core features. This configuration is certainly not recommended for most setups because commonly used functionality (SimpleXML PDO, sessions) has been removed (I do not require them).

To get a list of configuration options run “./configure --help”, this will output a list of switches to enable / disable features. You can disable functionality you won’t use.

Here is a copy of my configuration for building PHP from source (on Linux) for Speeple:

CFLAGS="-O3 -march=nocona -msse -mmmx -msse2 -msse3 -mfpmath=sse -fomit-frame-pointer -funroll-loops" \
./configure \
        --prefix=/usr/local/php \
        --with-apxs2=/usr/local/apache/bin/apxs \
        --with-mysql-sock=/tmp/mysql.sock \
        --with-mysqli=/usr/local/mysql-client/bin/mysql_config \
        --enable-mysqlnd \ # I use the PHP MySQL native driver which is seamlessly compatible with the MySQLi classes
        --with-libxml-dir=/usr/local/libxml \
        --with-xsl=/usr/local/libxslt \
        --with-config-file-path=/etc \
        --enable-force-cgi-redirect \
        --enable-inline-optimization \
        --with-zlib \
        --enable-mbstring \
        --enable-sockets \
        --with-pear \
        --disable-cgi \ # Apache 2 loads PHP via a shared object, CGI not required
        --disable-pdo \
        --disable-debug \ # This is a production enviroment, debbuging turned off
        --disable-json \ # Some "web 2.0" services might make use of JSON (the data exchange format of choice for "web 2.0") - I don't
        --disable-hash \ # I don't require an extensive list of hashing functionality beyond MD5 and SHA1 shipped in the PHP core
        --disable-session \ # Most people require session support - I don't so I disabled it
        --disable-simplexml \ # In regards to XML: I only use PHP as a middle man to serve XSL transformations
        --disable-tokenizer \
        --disable-filter \
        --disable-xmlreader \
        --disable-xmlwriter \
        --disable-sockets \
        --disable-reflection \
        --without-sqlite \
        --without-unixODBC \
        --without-mysql \ # I use the MySQLi classes to access MySQL
        --without-odbc \
        --without-gd # I use ImageMagick that can be installed as a .so via PECL

As you can see the list of disabled features is quite extensive and suited only to my setup.

This configuration makes use of GCC’s “-march” option, use of “-mfpmath” to use scalar floating point instructions present in the SSE instruction set and “-fomit-frame-pointer” to remove debugging data. The flag “-funroll-loops” allows loop unwinding on loops whose numer of iterations can be determined at compile time. “-funroll-all-loops” unrolls all loops – which can be detrimental to performance.

Conclusion

Depending on your technical knowledge creating an optimized build of PHP might be worth your time. I would suggest attempting to optimize your build of PHP; it can be a useful learning process (especially learning the way around Linux and the excellent GNU tools) and can certainly result in measurable performance improvements. But remember that compilation optimizations are never a cure for bad programming practices and at the best of times only produces moderate gains in performance.

Resources for Compiling PHP