A short explication on how to extract profile information for PHP on your server using XDebug and KCacheGrind or WinCacheGrind.
Yii has some built in profiling features, but I find that they require you to instrument your code yourself, while I prefer a way where instrumentation is automatic. Also, I preferred to run this on the production server where the problem occurs, so I wanted a 'non-intrusive' way of profiling.
Finally, I wanted to automatically start the profiling when the problem occurs, without human monitoring.
The used method is not Yii specific, but usefull for Yii developers!
In my case the function begin sluggish is a commandline command.
Here is what I did after reading the documentation for XDebug profiling:
sudo aptitude install php5-xdebug.
Or XDebug may already be in your local installation.
Do check that 'xdebug' is really loaded (check /etc/*/conf.d/*xdebug.ini on debian and make sure that the '.so' specification is not commented).
/usr/bin/php5 -d xdebug.profiler_enable=1 -d xdebug.profiler_output_dir=/var/log/prof /.../yiic.php myconsolecommand 2>&1
The first option 'xdebug.profiler_enable' enables the profiles, the second one 'xdebug.profiler_output_dir' sets where the log should be written.
I did not want to enable profiling all the time but only when interesting, and only once. So I did some bash scripting. I already have monitoring enabled on my server which creates a file like "checkresult" which is empty when monitoring is ok, and "non-empty" when there is an issue. As the issue I monitored in particular has 'count' in the message, I filter for 'count'.
Here is the script:
PHP_EXTRAOPT="" FILE_TAG=/mypath/prof LOG_PATH=/logpath MONITOR_FILE=mymonfile # The next test checks if profiling already happened, and profiles only if not. if [ ! -f $FILE_TAG ] ; then # The next test looks for 'count' in the monitor file as a condition to start profiling. if [ $(grep -c count $MONITORFILE) != 0 ] ; then echo "Profile" # Touch $FILE_TAG to indicate that profiling is initiated once. touch $FILE_TAG # Create log directory (to make sure it exists, can be skipped if created beforehand) mkdir -p $LOG_PATH # Modify ownership of log directory (to make sure that the target process can write to it) chown fcgi $LOG_PATH # Enable XDebug options. PHP_EXTRAOPT="-d xdebug.profiler_enable=1 -d xdebug.profiler_output_dir=$LOG_PATH" fi fi sudo -u fcgi /usr/bin/php5 $PHP_EXTRAOPT -d max_execution_time=420 /pathtoprotected/yiic.php myconsolecommand 2>&1 >> /pathtoscriptlog/myscriptlog.log
If you want to profile a webpage fetch, you can enable 'xdebug.profiler_enable_trigger' in your php.ini file and add the POST or GET variable XDEBUG_PROFILE to your request. Unfortunately that requires the "user" to add 'XDEBUG_PROFILE', or alternatively, you have to add it from the server to the URL that is used (either by click or ajax call).
Personally, I compressed the file on the server and transferred it to my PC using scp where I visualized the uncompressed results on WinCacheGrind.
I validated the flow, now I am waiting for the trigger to happen.