Setting up PHP build environment on Windows

One of the things I have done many times in the past year is setting up a build environment for PHP on Windows. I have been using a simple script to do this which I am releasing today with this blog. Here is the zip file contains the script winbuild.bat along with essential tools (wget and unzip) which the script requires. Before you run winbuild.bat, make sure Visual Studio (or VC9 expression edition) and TortoiseSVN are installed on the machine. If you do not have these already installed, you can install VC9 express edition from http://www.microsoft.com/express/downloads/ (select visual studio 2008 express) and TortoiseSVN from http://tortoisesvn.net/downloads. Installation of TortoiseSVN might require a reboot. Once machine is ready, download the attached zip, unzip files in a folder, say c:\winbuild, launch visual studio command prompt and then run c:\winbuild\winbuild.bat. By default this script will setup PHP 5.3 build environment in %systemdrive%\php\php_sdk\php_53_dev folder. If you want to choose a different branch and folder location, open winbuild.bat, change variable values on top of the script before running it. This script does the following for setting up the build environment.
 
·         Create folder structure recommended here.
·         Download and unzip binary tools package.
·         Download and unzip all dependency libraries.
·         Download php source code from http://svn.php.net.
·         Run buildconf and configure commands.
 
After the script is complete, PHP root will be set to c:\php\php_sdk\php_53_dev\vc9\x86\PHP_5_3. If you change branch/folder locations in the script, this will be different. With the build environment set, you can now run “nmake snap” to build PHP in the PHP root folder. If you want to change configure options, open config.nice.bat (present in PHP root), change the options and run it. Running “nmake snap” will now build PHP using new configure options. Once the build is complete, release binaries will be under the release folder under php root.
 
Hope this makes setting PHP build environment much simpler. If you run into a bug in winbuild.bat, let me know by leaving a comment. Feature suggestions are also welcome.

Download script here.
 

Thanks.
Kanwal

Goodness of dynamic maxInstances in FastCGI

One of the major pain points in FastCGI 1.0 was that users were required to set maxInstances to a number which works best for their application. Many users didn’t tune this value and were running FastCGI with default value of maxInstances which didn’t give them optimal performance. We recommended users to set maxInstances to (10 * number of processors) if they don’t want to go through the pain of finding the ideal maxInstances for them which worked much better than default value but still didn’t give optimal performance. Even when users fine-tuned maxInstances to ideal value, they didn’t always get best possible performance at all times due to variations in traffic, server/application configuration changes and code changes.
 
In IIS 7.5 we fixed this pain point by making FastCGI module capable of monitoring system state and adjust this number dynamically to give best possible performance. This feature is referred to as dynamic maxInstances or auto maxInstances and can be enabled by setting maxInstances value to 0. As we intend to maintain a consistent platform for PHP developers on WinXP and above, we have added this feature to FastCGI ISAPI 1.5 and made it available on IIS 7.0 as well (read more here). Last week I spent some time comparing dynamic maxInstances results with suggested maxInstances value (10 * processor count) results and below is what I got.
 
Hardware: Quad core machine with 4 GB RAM
Application: Joomla
 

 

 
MaxInstances = 40
MaxInstances = 0
%age difference
Path Length (less is good)
154177
142294
7.66%
Response Time (less is good)
844 ms
783 ms
7.22%
Context switches/sec (less is good)
171.76
79.69
-53.60%
Requests/Sec (more is good)
59.06
63.76
7.95%
 
As you can see, all performance parameters improved considerably just by changing maxInstances to 0. Our testing showed similar improvements in performance of other PHP applications as well. So we changed the default value of maxInstances to 0 in FastCGI ISAPI 1.5 and Win7. Note that if a value is explicitly set in fcgiext.ini or applicationHost.config, that value will override default value. Due to restrictions of QFE release process, we couldn’t change the default of maxInstances in IIS 7.0. So you are required to enable dynamic maxInstances after install this update on IIS 7.0.
 
We typically run many applications on our performance bench machines and were required to choose one maxInstances number for all applications. Choosing a different maxInstances number for each application was a better way to do performance testing but that was painful. Now with dynamic maxInstances, we get optimal performance for each application without any pain. Our performance testing is loving this feature and I hope you love it too.
 
Thanks.
Kanwal

What’s new in WinCache 1.1 Beta2 and what’s next

After WinCache 1.0 release, two most requested features were user cache and session cache. We added both of these features in WinCache 1.1 beta1. We are very happy with the rate of adoption of user cache by PHP application developers. Many application developers have already added support for WinCache user cache in their applications and many are in the process of adding it. Earlier we were planning to add only these two features in WinCache 1.1 and then do more performance optimizations in WinCache 1.2 but later we decided to add these additional optimizations in 1.1 release itself. Because of this, we did beta2 release which has file change notification and function hooks support along with some small feature additions. Below is the full list of features which got added to WinCache 1.1 up to beta2 release.
 
1.       User cache APIs – We have added APIs like wincache_ucache_get, wincache_ucache_set etc. (see full list here) which can be used to store and retrieve application data from the cache. Since the cache is shared among all PHP processes under an application pool, application developers can calculate data once, store it in the cache and then retrieve it in next request instead of calculating it every time. Database query results, site counters etc. are good candidates to be stored in user cache. These APIs behave much like user cache APIs available in APC to make it easier for developers to use existing code written for APC.
 
2.       WinCache session handler – PHP provides three session handlers (files, shm, user) out of the box of which shared memory (shm) handler doesn’t work on windows. Session handler “files” is the most commonly used session handler on windows which is slow as it requires file read on every request. We have implemented a session handler in WinCache which keeps session data in shared memory which is much faster compared to files. Since session data is expected to survive PHP and IIS process recycles, data is persisted on disk by WinCache in the folder specified by session.save_path. Since session.save_path is not a system level configuration, WinCache creates a separate session cache for different values of session.save_path. WinCache 1.1 stored this data in memory allocated for user cache but WinCache beta2 allocates separate memory for session cache.
 
3.       File change notification – WinCache now registers for change notifications to all folders under which a file is requested by file cache or opcode cache. When a file change notification is received, that file is removed from all the caches immediately. Doing this without incurring performance penalty required us to make all processes not listen to all the folders. So we designed a distributed change notification infrastructure which works without any master. Of all PHP processes running on the system for an application pool, only one of them listens to one folder. Other processes detects that a listener is present for the folder and do nothing. If a process dies, another process detects this situation and registers for a change listener itself. We made sure that no change is ever missed by this system and this system can easily scale to 100s of folders.
 
4.       Function hooks – With file cache and file change notification infrastructure in place, we decided to rewrite some PHP APIs like file_get_contents, is_file etc on top of this infrastructure to make them faster. For this we have added ability to define function hooks in WinCache.  WinCache 1.1 beta2 include this infrastructure but doesn’t include any function hooks. I am in the process of rewriting some functions and we will enable these hooks in WinCache 1.1 RC release.
 
5.       In WinCache 1.0, we create separate cache for PHP processes running under one process. This didn’t work too well in web garden scenarios. WinCache 1.1 has solved this problem by sharing cache for all PHP processes running under worker processes belonging to one application pool. If application pool id is not available (as in Apache), it will switch to old behavior.
 
6.       Added optional boolean argument summaryonly to all WinCache info functions. Ruslan requested this feature so that wincache_ocache_fileinfo function calls made by his wordpress widget on his site (http://ruslany.net) are faster. And based on customer feedback we changed wincache_ucache_info to accept an optional key to make it return information on just one user cache entry and exposed user cache entry size in each entry.
 
7.       Drupal application developers requested us to add wincache_lock, wincache_unlock APIs and we have added these in 1.1 Beta2 release. By default lock created by wincache_lock is scoped to all PHP processes sharing the cache. If you want a global lock, set optional argument isglobal to true.
 
8.       WinCache statistics page (wincache.php) has been changed to show user cache and session cache data and fixed bugs reported by customers on http://pecl.php.net/bugs/.
 
We are planning to add replacement APIs for PHP functions which deal with files in WinCache 1.1 RC release. We will also enable function hooks so that calls to PHP file APIs gets re-routed to these APIs. And as always, we will implement feature requests and fix bugs reported by you.
 
Thanks,
Kanwal

How to add traces to IIS log from PHP

One of the new features added to FastCGI module in IIS 7.5 is ability to use IIS tracing infrastructure from FastCGI applications. This feature request was made by a customer who wanted to consolidate logging of the request processing in one log. All IIS events were present in IIS trace logs but traces generated by PHP applications were separate. So IIS trace log didn’t give a holistic view for PHP applications. ASP.Net already has a way to use IIS traces. So this limitation was specific to PHP. We closed this gap in PHP by providing a way for PHP developers to send traces to IIS using FastCGI’s STDERR stream which are then extracted by FastCGI module and sent to IIS tracing subsystem. This feature has been included in KB 980363 so that this can be made to work on IIS 7.0 as well. On IIS6 and below, these trace messages will be ignored as there is no tracing subsystem available.
 
FastCGI module parses STDERR stream looking for markers which identify the content as trace messages. Messages starting with “IIS_TRACE_ERROR:” are parsed as errors, “IIS_TRACE_WARNING:” as warnings and “IIS_TRACE_INFO” as info messages. Message end is recognized by marker “:IIS_TRACE_END”. Any function in PHP which can write to STDERR stream can be used to send these traces to FastCGI. So calling error_log(“IIS_TRACE_ERROR:This is an error.:IIS_TRACE_END”) will appear in IIS trace log as an error. Traces appear for CGI trace provider on IIS 7.0 and FastCGI trace provider on IIS 7.5. Trace messages are removed from STDERR stream before STDERR stream content goes through StderrMode logic so that traces don’t disturb existing STDERR behavior. Below is a simple helper class which you can use to generate trace messages.
 
<?php
 
class IIS_TRACE {
 
 const NONE    = 0;
 const ERROR   = 1;
 const WARNING = 2;
 const INFO    = 3;
 
 private static $verbosity = self::NONE;
 
 private static $traceErrorStart   = "IIS_TRACE_ERROR:";
 private static $traceWarningStart = "IIS_TRACE_WARNING:";
 private static $traceInfoStart    = "IIS_TRACE_INFO:";
 private static $traceEnd          = ":IIS_TRACE_END";
 
 public static function SetVerbosity ( $verbose )
 {
    if( $verbose != self::NONE    && $verbose != self::ERROR   &&
        $verbose != self::WARNING && $verbose != self::INFO )
    {
        throw new Exception( 'Function SetVerbosity called with invalid value' );
    }
 
    self::$verbosity = $verbose;
 }
 
 public static function WriteError ( $msg )
 {
    if (self::$verbosity >= self::ERROR )
        error_log( self::$traceErrorStart . $msg . self::$traceEnd );
 }
 
 public static function WriteWarning ( $msg )
 {
    if (self::$verbosity >= self::WARNING )
        error_log( self::$traceWarningStart . $msg . self::$traceEnd );
 }
 
 public static function WriteInfo ( $msg )
 {
    if (self::$verbosity >= self::INFO )
    error_log( self::$traceInfoStart . $msg .self::$traceEnd );
 }
}
 
?>
 
With this class present in your code, you can use WriteInfo, WriteWarning, WriteError functions available in IIS_TRACE class in your code to add traces to IIS trace log as below. When you have tracing enabled, these traces will appear with all other information about request processing.
 
<?php
 
require_once(‘iistrace.php’);
.
.
If($percent > 100)
{
    IIS_TRACE::WriteError(‘Invalid data provided. Percent = ’ . $percent);
}
.
.
 
?>
 
Hope this helps.
Kanwal

Comparing WinCache user cache APIs with other caches

 WinCache 1.1 beta release added two new major features to WinCache. These are user cache APIs which can be used to store custom data in the cache and “wincache” session handler. User cache APIs was the biggest feature gap WinCache 1.0 had compared to other caching solutions which are frequently used on Linux. WinCache 1.1 release was aimed to fill this gap. WinCache session handler, which internally uses user cache, is included so that php session data can be stored in in-memory shared cache instead of on disk which tend to be slower. Read more about these features here.

 

 

Both the features are very well received by customers and many open source application developers are working to include support for these in the applications. If you want to use WinCache user cache APIs to speed up your php application, it will be useful to first look for code which is doing that with other caches like APC, Xcache and Eaccelerator. If the application is written to make use of a caching solution, chances are that there will be plug-in available for APC or Xcache or Eaccelerator. Once you have the code you can use the following table to easily map API calls to other caches to WinCache.
 

 

WINCACHE
APC
XCACHE
EACCELERATOR
wincache_ucache_get
apc_fetch
xcache_get
eaccelerator_get
wincache_ucache_set
apc_store
xcache_set
eaccelerator_put
wincache_ucache_add
apc_add
NONE
NONE
wincache_ucache_exists
NONE
xcache_isset
NONE
wincache_ucache_delete
apc_delete
xcache_unset
eaccelerator_rm
wincache_ucache_clear
apc_clear_cache
xcache_clear_cache
eaccelerator_clear
wincache_ucache_inc
apc_inc
xcache_inc
NONE
wincache_ucache_dec
apc_dec
xcache_dec
NONE
wincache_ucache_cas
apc_cas
NONE
NONE
wincache_ucache_info
apc_sma_info
xcache_info
eaccelerator_list_keys
 
Other than unset_by_prefix functionality in Xcache, WinCache provides a superset of the functionality offered by other caching solutions. Another piece missing in WinCache is APIs similar to eaccelerator_lock and eaccelerator_unlock. We are trying to understand scenarios in which these APIs will be required by developers while working with user cache APIs. If we see these are required, we will add these in future. I hope this table makes it easy to use WinCache user cache APIs and port code written for existing caches.
 
Thanks.
Kanwal