Podcast on Running PHP on Windows

Peter Laudati & Dmitry Lyalin host the edu-training Connected Show developer podcast on cloud computing and interoperability. I met Peter in Chicago during Tek-X and we along with Don and Wade recorded a podcast on evolution of PHP on the Windows Platform. We talked about the improvements made to Windows in order to support PHP, including: Fast CGI, WinCache, PHP 5.3, the Web PI, and the SQL Server driver for PHP. Check out episode #31, “PHP On Windows” on Connected Show. Interview starts at 24:31.


If you like what you hear, check out previous episodes of the Connected Show at www.connectedshow.com.  You can subscribe on iTunes or Zune.  Peter and Dmitry publish new episodes approximately every two weeks!


Impact of name resolution on mysql_connect perfomance

I spend lot of time profiling popular PHP applications finding where exactly processing time is spent during PHP execution. Few months ago, one thing which caught my attention was performance of mysql_connect API. On my windows test bench, xdebug output showed that one call to mysql_connect was taking 0.31 seconds which is huge. While playing with the API, I noticed that when IP address of the MySQL machine is used instead of the hostname, performance of mysql_connect API is much better. Below is a simple script I ran to test this.
1. <?php 
2.     $hostname = "hostname";
3.     $ipaddress = "";
5.     $starttime = microtime(true);
6.     for($cnt = 0; $cnt < 10; $cnt++) {
7.         $connection = mysql_connect($hostname, 'username', 'password');
8.         mysql_close($connection);
9.     }
10.    $endtime = microtime(true);
11.    echo ($endtime $starttime . "\n");
13.    $starttime = microtime(true);
14.    for($cnt = 0; $cnt < 10; $cnt++) {
15.        $connection = mysql_connect($ipaddress, 'username', 'password');
16.        mysql_close($connection);
17.    }
19.    $endtime = microtime(true);
20.    echo ($endtime $starttime);
21. ?>
Below is the output I got when I ran the above script on my test bench.

3.14003 seconds (time taken for 10 mysql_connect calls when hostname was used)
0.01396 seconds (time taken for 10 mysql_connect calls when IP address was used)

As you can see in the results, hostname resolution slows down mysql_connect significantly and the performance hit seems to happen on each mysql_connect call. This slowdown only happens when connection is made to a remote machine. When MySQL and web server both ran on the same machine, there was no performance difference between hostname and ipaddress case. So if you are running MySQL on a remote machine, use IP address in the mysql_connect call. Alternatively you can add an entry in %windir%\system32\drivers\etc\hosts file to tell your system IP address of MySQL machine. System will find this entry in the hosts file and pick the IP address of MySQL box directly without going through more expensive name resolution. Change hosts file only if you have a static IP address. Name resolution performance will depend on your DNS/WINS configuration and on your network topology. So you should run the script above to find out performance impact of hostname resolution before making any changes.

Hope this helps.

Work items collected from Tek-X

Last week I was in Chicago in the company of very passionate and smart PHP programmers at Tek-X. I got to meet some well-known members of PHP community and also fellow Microsoft employees who have been working on improving PHP experience of Windows. I would admit that meeting people was the best part of Tek-X for me. Sessions were great too and I learnt a great deal from them. I returned to Seattle more knowledgeable and passionate for PHP then ever. One of the things I wanted to get from Tek-X was a list of problems PHP users face on Windows so that we can work on solving them. Below is the list of work items I collected during informal discussions, questions during my talk and from other sessions.
1.       PHP 5.3 in WebPI
Today, Web Platform Installer (WebPI) only offers latest version of PHP 5.2. Folks want us to offer PHP 5.3 through WebPI. We receivedthis request during web developer summit and work for this is already in progress.
2.       PECL extensions in WebPI
There are few PECL extensions which are very popular (e.g. XDebug, uploadprogress) and people want us make them available in WebPI.
3.       WebPI to download PHP from windows.php.net
During my WebPI demo, Derick Rethans pointed out that we are downloading PHP from http://sourceforge and not http://windows.php.net. We used to install PHP from windows.php.net but moved recently to sourceforge when windows.php.net went down for maintenance. We will move back to windows.php.net once it has mirrors set.
4.       SQL driver for PHP extension on PECL
PHP community is very happy with the fact that WinCache source code is in PECL repository and documentation is exclusively available on php.net. They want SQL driver for PHP extension to move from codeplex to PECL. Even better will be moving related documentation from http://www.microsoft.com to http://www.php.net as well.
5.       PHP frameworks in WebPI
During my talk, people asked if there are any plans to add popular PHP frameworks like CakePHP and Zend Framework in WebPI. If a PHP application code already has framework code included, WebPI will just copy that as part of application install. Right now there are no plans to offer standalone PHP frameworks from WebPI. I will be discussing with the product team and see if this makes sense for us.
6.       Simplify setting up of PHP build environment on Windows
Many at Tek-X made fun of the fact that compiling PHP on Windows is incredibly hard. I have published a script (winbuild.bat) which makes this very easy. I will continue to produce documentation/scripts related to this unless building PHP on Windows is seen as a simple task.
7.       CHM file for PHP documentation script
Gennady told me that script which pulls in php.net documentation and creates a CHM file is broken and need some fixes. He loves access to php documentation even when offline and want the script to work. I will be looking at it and try to fix it.
8.       Pre-built PECL binaries for Windows
http://pecl4win.php.net has been down for ages. Many showed frustration with the fact that pre-built PECL binaries for Windows are hard to get. Pierre has few extensions built regularly and has them available for download here. Getting binary for an extension which is not available here is as easy as sending Pierre an email. If you want to build the PECL extension yourself, you can follow the instructions here. We still need to look into pecl4win.php.net or its replacement plans.
9.       Getting operating system information from PHP is hard
Elizabeth Marie Smith, in her awesome Cross Platform PHP talk, mentioned that getting system information on Windows is hard. I will be following up on this and make fixes to PHP as needed.
10.   Debugging dependency check errors is very hard
Elizabeth Marie Smith mentioned this in her talk. I will look into this and see what can be done.
I will be following up on each of these and hopefully will close on most of these requests before Tek-2011J. If this list doesn’t capture something you need for better php on Windows experience, please leave a comment and I will add it to this list.

PHP PGO build for maximum performance on Windows

In the last few years VC++ team have done some awesome work with profile guided optimizations (PGO). PGO improves performance of certain code paths which are more likely to be used in production environments. Most of the teams in Microsoft have been using this technology to speed up most commonly used scenarios. One of the ideas initially floated by Garrett was to start using PGO for building PHP. Garrett wrote a blog on how to produce a PGO build but the steps involved were little complex. I started looking into simplifying the process and came up with a simpler way. I am going to walk you through the steps I used in this blog. All the steps written in this blog are tested to work with VC9 compiler. I am assuming you already have a PHP build environment set. Go through this and this blog to setup a PHP build environment if you don’t have one. I am using PHPROOT environment variable to refer to root folder where PHP build environment is set. If you used winbuild.bat to setup build environment, PHPROOT refers to C:\php\php_sdk\php_53_dev\vc9\x86\PHP_5_3.

Note: PGO support is not available in VC++ express edition. To build PGO optimized binaries, you need a version of Visual Studio which supports this feature.
1. Add PGO support to build system
PHP build scripts, as available in PHP source tree, don’t have support for PGO. So first thing you need to do is download this patch to %phproot%\win32\build and apply it on your system. This patch will add support for “–enable-pgi” and “–with-pgo” options in PHP build system. When “–enable-pgi” option is used, PHP build system will add “/LTCG:PGINSTRUMENT” switch to linker command to build instrumented binaries. Option “–with-pgo” will make build system to add “/LTCG:PGOPTIMIZE” switch to linker commands. This switch will make linker use PGO data to produce final optimized binaries. Both “–enable-pgi” and “–with-pgo” cannot be used together. This patch will also make “nmake clean-all” option to delete PGO related files in addition to other cleanup tasks it already does. Additionally you will get an option to delete all files except PGO profile data using “nmake clean-pgo” command (used in step 4 below). After applying the patch, run %phproot%\buildconf.bat to regenerate configure.js again. You can verify this step by running “%phproot%\configure –help” and confirming that output shows “–enable-pgi” and “–with-pgo” options.
2. Build instrumented binaries
PGO build is a two-step process. First step is to collect data identifying most commonly used paths. Second step is to feed this data into build system which then optimizes these paths. Collecting training data requires you to build instrumented binaries which have code to collect profile data. Let’s go through steps to produce these instrumented binaries.
First delete the folder containing non PGO binaries using “rd /s /q %PHPROOT%\release” command. Open %PHPROOT%\config.nice.bat and add switch “–enable-pgi” option to the configure command. Run “config.nice.bat” to create a new makefile and use “nmake snap” to produce a PHP build containing instrumented binaries.

After the build is complete, you will see “.pgd” files created in the %PHPROOT%\release folder along with usual “.exe”, “.dll”, “.pdb” files. Build process uses php.exe to do few steps. So after the build is complete, you will see php!1.pgc and php5!1.pgc in release folder. Delete these files so that profile data doesn’t include code paths which were used during build process. Don’t touch any of the other files yet and move to step 3.

3. Collect training data
To collect training data, pick the build packages (php-*.zip and pecl-*.zip) from %PHPROOT%\Release folder and install it on your web server. For this blog I am training the binaries for wordpress. So I copied and installed instrumented binaries on my web server running wordpress. If your build machine itself has the web application installed, you can do this on the build machine itself. If your web server doesn’t have visual studio installed, it won’t have PGO runtime (pgort90.dll) which is required to run instrumented binaries. Pick this file from you build machine and copy to the folder your web server containing php-cgi.exe.
Now open “%windir%\system32\inetsrv\config\applicationHost.config” (for IIS 7.0 and IIS 7.5) or “%windir%\system32\inetsrv\fcgiext.ini” (for IIS 5.1 and IIS 6.0) and set PHP_FCGI_MAX_REQUESTS equal to number of requests you are going to send to cover most used paths. I changed this setting to 15. Keep “InstanceMaxRequests” setting in FastCGI process pool higher than PHP_FCGI_MAX_REQUESTS value so that PHP terminates itself before FastCGI forcibly kills it. When php-cgi.exe dies on its own, PGO data will be dumped to “.pgc” files. Now you are ready to collect training data.
Send requests which cover code paths you want to optimize the most. In my case, I sent 6 requests to home page and 6 to individual posts to identify these as the most requested parts of my website. I sent 2 requests to category home page and 1 to about page to optimize these paths as well but identified these pages as less hot than home page and individual posts. Choose these requests carefully and only send requests to most frequently visited pages so that this part gets optimized the most. If you cover too much surface area in training data, linker won’t be able optimize as effectively. After PHP_FCGI_MAX_REQUESTS, php-cgi.exe will die and dump “.pgc” files in PHP install root. Find and copy all the “.pgc” files in a folder and then copy to your build machine.
4. Merge training data and build optimized binaries
Copy all the “.pgc” generated in step3 to %PHPROOT%\release folder along with “.pgd” files. Run “nmake clean-pgo” to delete all files except “.pgd” and “.pgc” files. Now change config.nice.bat to use “–with-pgo” instead of “–enable-pgi” and then run config.nice.bat to generate new makefile. Run “nmake snap” to build optimized build and that’s it.

As PHP source code changes are incremental, you don’t need to collect training data for each build. For building latest PHP sources, you can just sync and run “nmake snap” again to use existing training data with latest sources. As source code changes increase, training data will be less accurate and less effective. You can update training data once a month and before the final release to produce useful PGO builds regularly. Run “nmake clean-all” before using new training data so that old training data is deleted.

To build non-PGO build, run “nmake clean-pgo” to delete all binaries (but keeping training data). Remove “–with-pgo” option from config.nice.bat and run it to generate new makefile. Use “nmake snap” to produce non-PGO build.
WordPress Performance Test Results
Let’s go through some quick results I got on my performance bench using PGO optimized build and compare it with non-optimized build from my build machine.

Response Time
Regular Build
726 ms
PGO Optimized
79.89 (17.40% better)
619 ms (14.74% better)
I got approx. 17% better throughput and 15% better response time with PGO build compared to non-PGO build for wordpress. For some other applications, I have seen as much as 30% improvement. If you are trying to get maximum performance output from your windows server, PGO build is something you should definitely consider. If you try out PHP PGO build and run into a problem, sending me email me will get you instant helpJ.

Adding a PECL extension to your PHP build environment

Last week I published winbuild.bat to setup PHP build environment on windows. In this blog I am covering how to add a PECL extension to the PHP build system. I will also show how to static link a PHP extension and how much performance benefit you can get by that.
Building a PECL extension
Let’s say you have the PHP build environment set in the folder c:\php\php_sdk\php_53_dev\vc9\x86\PHP_5_3. For adding PECL extension (e.g. WinCache) to the build process, first download source code of the extension in c:\php\php_sdk\php_53_dev\vc9\x86\pecl\ folder. You can use the following commands to do this.
pushd c:\php\php_sdk\php_53_dev\vc9\x86\
md pecl\wincache
cd pecl\wincache
tortoiseproc /command:checkout /path:. /url:http://svn.php.net/repository/pecl/wincache/trunk/ /closeonend:1
Once you have downloaded the source code, follow steps below to add the extension to your build process.
1.       Open visual studio command prompt and run c:\php\php_sdk\bin\phpsdk_setvars.bat to set PHP build window.
2.       Go to c:\php\php_sdk\php_53_dev\vc9\x86\PHP_5_3 andrun buildconf.bat. This will make PHP build environment to create configure.js again with option to build WinCache.
3.       Run “configure –help” to confirm that –enable-wincache option is now present in configure options.
4.       Open config.nice.bat and add “–enable-wincache=shared” option to the configure command.
5.       Run config.nice.bat to generate new makefile.
6.       Run “nmake snap” to build full PHP or just use “nmake php_wincache.dll” to build only WinCache extension.
Running “nmake” command will create php_wincache.dll under c:\php\php_sdk\php_53_dev\vc9\x86\PHP_5_3\release folder. Steps above add PECL extension wincache to the PHP build system. You can add any other PECL extension to the build system by replacing wincache with that extension name. You can add multiple extensions by adding multiple switches to your configure command.
Static linking and performance comparison
Above steps used “–enable-wincache=shared” option in the configure command to add wincache to the build system. “=shared” tells the system to link the extension dynamically. Removing “=shared” from “–enable-wincache” or for that matter any configure switch will make that extension link statically. Performance with static linking is significantly better than when extensions are dynamically linked. If you know what PHP extensions you use, you can create a custom build with all those extensions statically linked. Let’s see how much performance improvement we get by statically linking wincache compared to when wincache is dynamically linked. I am using wordpress as the sample application.


Response time
Dynamic linking of wincache and mysql. All others as set by winbuild.bat.
68.05 requests/sec
726 ms
Static Linking of wincache and mysql extensions. All others as set by winbuild.bat.
72.12 requests/sec (5.98% better)
692 ms (4.68% better)
As you can see, just static linking of two extensions increased performance by ~5%. A custom build with needed PHP extensions statically linked will almost always perform better than official build from php.net. I hope that my last blog and this blog makes it easier to create custom PHP build on windows. I am experimenting with PGO builds these days and I will share my findings about that soon as well. Till then, CHAO.