Troubleshooting PHP Performance in Microsoft Azure Web Sites with Xdebug
Web applications with slow performance issues tend to be challenging to troubleshoot regardless of the platform in which your application is running on. This is due in great part to the sometimes random nature of these issues and because often these types of issues do not result in a specific error being logged.
If you’re running PHP applications in Azure App Service Web Apps (such as WordPress or Joomla), the Xdebug extension can help you identify which function(s) or method(s) inside your application is(are) taking a long time to execute.
Note: As with any other profiler, Xdebug profiling may have an impact on your website’s performance. Therefore, it’s not recommended to leave it enabled all the time. Enable it only while you are troubleshooting a specific issue and then disable it. If possible, always try to use the trigger optioned as detailed in Selectively Enabling Xdebug Using a Trigger later in this post.
Follow these steps to enable Xdebug and analyze the logs generated.
[Updated on 08/01/2018: Xdebug dlls for PHP version 5.6, 7.0, 7.1 and 7.2 are now available on all of the Azure WebSites under D:\devtools\xdebug folder. Per Jennifer Lee's article Updating steps to reflect this]
Check the version of PHP that your website is using by going to the Application Settings blade:
In the Azure Portal (portal.azure.com):- If you are using PHP version 5.6, 7.0, 7.1 or 7.2 then you can skip this step and go to step 3. If you have configured your own version of PHP and is different than 5.6, 7.0, 7.1 or 7.2 then you will need to download the Xdebug DLLs yourself.
To do this, download the non-thread safe version (identified by having ‘nts’ in the name of the file) of the Xdebug DLL file that matches the version of PHP of the application that you are currently running in Windows Azure Web Sites but make sure you always select the 32-bit version regardless of whether your website is using 32-bit or 64-bit. You can download the DLL from Xdebug’s download page at https://xdebug.org/download.php.
The links will be something like “PHP 7.2 VC15 TS (32 bit)”. Clicking on that link downloads a file called php_xdebug-2.6.0-7.2-vc15-nts.dll. Notice that 2.6.0 represents the version of Xdebug, 7.2 is the version of PHP that this extension is intended for and nts stands for non-thread safe. - Connect to your website using FTP, GIT, WebMatrix or Kudu console. You can download WebMatrix here or you can click on the Dashboard tab of your Azure App Service Web App and click on the WebMatrix icon in the toolbar at the bottom of the page if on the old portal.
Once connected to your website, create the following two folders (if they don't exist already):
- \bin
- \bin\xdebug_profiles
- If you are using PHP 5.6, 7.0, 7.1 or 7.2 then skip this step and go to step 5. If not then copy the Xdebug extension that you downloaded in Step 1 to the \bin folder you just created.
- Add a file called .user.ini (notice the dot at the beginning of the file name) to the root directory of your website.
- Xdebug allows you to either leave it enabled or selectively enable it via a trigger in a query string. It’s preferable to enable Xdebug using a trigger, but if the issue happens randomly and it’s difficult to catch, you can leave it enabled and stop it once the problem has happened. Be aware, however, that doing so may cause for your web site to experience performance problems, so you should test this carefully to see how it interacts with your application.
Select one of the following two methods:
Method 1: Leave Xdebug Enabled all the Time
Add the following lines to your .user.ini file depending on the version of PHP that your website is using:
a) If using PHP 5.6, 7.0, 7.1 or 7.2 then add the following lines to your .user.ini file:
PHP VERSION Lines to copy to .user.ini
PHP 5.6 zend_extension = "D:\devtools\xdebug\2.5.5\php_5.6\php_xdebug-2.5.5-5.6-vc11-nts.dll"xdebug.profiler_enable=1xdebug.profiler_output_dir="D:\home\site\wwwroot\bin\xdebug_profiles"
PHP 7.0 zend_extension = "D:\devtools\xdebug\2.6.0\php_7.0\php_xdebug-2.6.0-7.0-vc14-nts.dll"xdebug.profiler_enable=1
xdebug.profiler_output_dir="D:\home\site\wwwroot\bin\xdebug_profiles"
PHP 7.1 zend_extension = "D:\devtools\xdebug\2.6.0\php_7.1\php_xdebug-2.6.0-7.1-vc14-nts.dll"xdebug.profiler_enable=1xdebug.profiler_output_dir="D:\home\site\wwwroot\bin\xdebug_profiles"
PHP 7.2 zend_extension = "D:\devtools\xdebug\2.6.0\php_7.2\php_xdebug-2.6.0-7.2-vc15-nts.dll"xdebug.profiler_enable=1xdebug.profiler_output_dir="D:\home\site\wwwroot\bin\xdebug_profiles"
b) If you have configured your own version of PHP then use the same lines as above just reflecting the right path and DLL name of the XDebug file that you used in the zend_extension property.
Note: Make sure you have enough space in your xdebug.profiler_output_dir as the amount of information generated by the profiler can be enormous for complex scripts. Also note that “site” in the output path should not be replaced with your particular site name.
Method 2: Selectively Enable Xdebug via a Trigger
1. Add the following lines to your .user.ini file depending on the version of PHP that your website is using:
a) If using PHP 5.6, 7.0, 7.1 or 7.2 then add the corresponding lines to your .user.ini file:
PHP VERSION Lines to copy to .user.ini
PHP 5.6 zend_extension= "D:\devtools\xdebug\2.5.5\php_5.6\php_xdebug-2.5.5-5.6-vc11-nts.dll"xdebug.profiler_enable=0xdebug.profiler_output_dir="D:\home\site\wwwroot\bin\xdebug_profiles"xdebug.profiler_enable_trigger=1
PHP 7.0 zend_extension="D:\devtools\xdebug\2.6.0\php_7.0\php_xdebug-2.6.0-7.0-vc14-nts.dll"xdebug.profiler_enable=0xdebug.profiler_output_dir="D:\home\site\wwwroot\bin\xdebug_profiles"xdebug.profiler_enable_trigger=1
PHP 7.1 zend_extension= "D:\devtools\xdebug\2.6.0\php_7.1\php_xdebug-2.6.0-7.1-vc14-nts.dll"xdebug.profiler_enable=0xdebug.profiler_output_dir="D:\home\site\wwwroot\bin\xdebug_profiles"xdebug.profiler_enable_trigger=1
PHP 7.2 zend_extension= "D:\devtools\xdebug\2.6.0\php_7.2\php_xdebug-2.6.0-7.2-vc15-nts.dll"xdebug.profiler_enable=0xdebug.profiler_output_dir="D:\home\site\wwwroot\bin\xdebug_profiles"xdebug.profiler_enable_trigger=1
b) If you have configured your own version of PHP then use the same lines as above just reflecting the right path and DLL name that you used in the zend_extension property.
Note: If you use this option then you can leave Xdebug profiling OFF (set to 0) and then it can be triggered with a query string (e.g. https://<yoursite>/<pagename>.php?XDEBUG_PROFILE=1) to profile an individual request instead of profiling your whole site which will affect your website’s performance.
7. Open your website in the Windows Azure Portal, click on the Configure tab, scroll to the App Settings section and add a new key called PHP_ZENDEXTENSIONS with a value pointing to the location of the Xdebug dll:
a) If using PHP 5.4, 5,5, or 5.6 then add the corresponding lines to your Application Settings in the Azure portal:
PHP VERSION KEY VALUE PHP 5.6 PHP_ZENDEXTENSIONS D:\devtools\xdebug\2.5.5\php_5.6\php_xdebug-2.5.5-5.6-vc11-nts.dll PHP 7.0 PHP_ZENDEXTENSIONS D:\devtools\xdebug\2.6.0\php_7.0\php_xdebug-2.6.0-7.0-vc14-nts.dll PHP 7.1 PHP_ZENDEXTENSIONS D:\devtools\xdebug\2.6.0\php_7.1\php_xdebug-2.6.0-7.1-vc14-nts.dll PHP 7.2 PHP_ZENDEXTENSIONS D:\devtools\xdebug\2.6.0\php_7.2\php_xdebug-2.6.0-7.2-vc15-nts.dll b) If are using other version of PHP then configure the PHP_ZENDEXTENSIONS to the same value as the zend_extension property that you configured in Step 6.
8. In old portal, click Save at the bottom of the page, in new portal, click Save at the top of the blade:
9. If you are not enabling profiling using a trigger, wait for the problem to happen and then go to Step 10. If you are using a trigger to enable Xdebug profiling, when you notice your application is slow, enable Xdebug profiling by triggering it with a query string in the following form: https://<yoursite>/<pagename>.php?XDEBUG_PROFILE=1
10. All the files will be saved to the /bin/xdebug_profiles folder. The files will start with "cachegrind.out" and end with the PID (process ID) of the PHP-CGI process.
11. Download all the files via FTP using an FTP client like Filezilla. (For more information on accessing your website using FTP, see this blog post.)
12. Once you have collected the Xdebug logs, use WinCacheGrind to read the files and identify slow running methods. You can download WinCacheGrind from https://sourceforge.net/projects/wincachegrind/.
13. After opening the file, you will see a list of the pages and functions being called and the time spent on each. By drilling down into each parent function/method, you can identify which one(s) are taking the longest time. The screenshot below shows an example. Click the image for a larger image.
14. Once you have identified the function/methods taking the longest time, the application’s developer should take look at the source code and try to understand why is taking that long and how can be improved.
References
· PHP Troubleshooting in Windows Azure Web Sites
https://ruslany.net/2013/01/php-troubleshooting-in-windows-azure-web-sites/· How to Enable XDebug in Windows Azure Web Sites
https://blogs.msdn.com/b/silverlining/archive/2012/09/20/how-to-enable-xdebug-in-windows-azure-web-sites.aspx· XDEBUG EXTENSION FOR PHP | DOCUMENTATION
https://xdebug.org/docs/profiler- If you are using PHP version 5.6, 7.0, 7.1 or 7.2 then you can skip this step and go to step 3. If you have configured your own version of PHP and is different than 5.6, 7.0, 7.1 or 7.2 then you will need to download the Xdebug DLLs yourself.
Comments
Anonymous
April 28, 2014
This page seems to contain conflicting info in stating that the non-thread safe version is needed but that you deduced that you needed to download “PHP 5.5 VC11 TS (64 bit)”. (the thread safe version) and that by clicking the link it downloads the php_xdebug-2.2.3-5.5-vc11-nts-x86_64.dll (the non thread safe version)Anonymous
May 01, 2014
Thank you for catching that up, Mikey. The link has been fixed now.