Join Jon Peck for an in-depth discussion in this video Profiling performance to find bottlenecks, part of Debugging PHP: Advanced Techniques.
One of Xdebug's features is a profiler, which analyzes program execution to measure memory usage, duration, and frequency of function calls. The profiler generates files that can be analyzed with third-party tools, known as cache grind, which I will demonstrate. Similar to other techniques that I've demonstrated, profiling is susceptible to the observer effect, as it has an impact on the speed of program execution. Therefore, Xdebug leaves profiling off by default. I'm going to selectively enable the profiler.
Meaning, instead of recording every single page, I will need to pass an additional header or cookie to manually trigger it. This way I don't have to sort through all the generated files to find the particular one I'm interested in. By default, Xdebug will write to/tmp/cashgrind.out.processID. Switching to the terminal, I'm going to edit the PHP configuration. sudo nano -w /etc/php5/apache2/php.ini.
Skipping to the end of the file, I'm going to add one line that will allow Xdebug's profiler to be manually triggered. xdebug.profiler_enable_trigger = 1. Exit and Save then Restart the Web server, sudo /etc/init.d/apache2 restart. Now that Xdebug is ready to profile, I'm going to demonstrate how profiling can find a bottleneck. Go to the IDE and scroll to the bottom and add two new functions.
The first will be to simulate slow execution of a function by counting to 100,000. Slow execution, so function slow for ($i = 0; $i < 100000; $i++) and then do nothing. The second will be to simulate an even slower function, slow execution even more.
Function slower, usleep(50000). Before the function call to a, add calls to the new functions. I'm going to loop the execution of slow in order to simulate a real-world problem, where slow function gets called a lot of times. for ($i=0; $i<50; $i++) and we'll call slow and then we'll call slower once.
Returning to the browser, I'm going to manually profile page execution. Navigate to the root, but this time we'll specify index.php and pass the parameter XDEBUG_PROFILE = 1 in the URL. Script execution takes quite a bit longer now and the stack trace from the errors highlights that. Now to analyze the profile. Included in the Exercise Files, is a copy of webgrind, a utility for analyzing profiler results. Navigate to sandbox.dev port 8080/webgrind.
At the top select Show 100% of the Auto (newest) in microseconds and click update. A large table is shown. On the left is an icon showing the type of call. Hovering over the image will indicate what kind it is. In this case, there are three procedural calls and the rest are internal. The next column is the Function column, which displays the function in question. If I click the arrow next to the Function, it will show where the function was called from and provide additional context.
To the right is a link to a formatted view of the code in question. As this is a development site not visible to the public, it's not a security risk, but do consider the audience before using this utility. Invocation Count is the number of times the Function has been evoked. Total Self Cost is the aggregate cost in milliseconds for the function itself, while Total Inclusive Cost is how long the function takes to execute, including everything that was executed in it. There is an additional button, Show Call Graph, which uses Python in an additional library for generating a nice flowchart of script execution.
However, this requires a lot more configuration and installation, so I will not cover it within this course. By default, webgrind sorts by Total Self Cost. This indicates that the function slow is the slowest. However, this isn't useful because comparing to the PHP function usleep, it's saying that it has a high self cost as well and the slower function, which we know is slow, has a Total Self Cost of 48. Since I know that the PHP core function is not the problem, I'm going to click Hide PHP functions and press update.
Now, only the functions I wrote are shown. Notice that the Total Self Cost of slow is the highest along with the Invocation Count. Compare this to slower, which has a very tiny Self Cost. What this indicates is that something in slow is causing a problem, as the Self Cost is identical to the Inclusive Cost. In contrast, the Self Cost for slower is basically nothing, while the Inclusive Cost is very high. This indicates that something that slower is calling is actually slowing down execution, not the slower function itself.
By comparing Invocation Counts and Costs, I can make a determination about the greatest return of investment of my optimizing efforts. In particular, if something is invoked a lot and has nearly identical Self and Inclusive Cost, it's a good candidate for optimization. Fortunately, in this case, I know that slow and slower are the problem and serve no functional purpose, so the optimization step will be their elimination. In this chapter, I've introduced Xdebug, the debugging PHP extension.
I first discussed what Xdebug is and how it can be used. Then I demonstrated how to install Xdebug and gave links to additional documentation if there were problems. I showed how Xdebug changes how Variables are displayed and how Call Stacks can be shown. Next, I discussed the Xdebug remote workflow, configuring and performing remote debugging with NetBeans. Finally, I demonstrated how Xdebug can be used to profile script execution and how to analyze the results. In the next chapter, I'll turn to Web browsers and how they can be leveraged as effective debugging tools.
This course covers installation of Xdebug on Apache as well as working with the NetBeans IDE (integrated development environment). Jon then introduces native web browser developer tools for Firefox and Chrome, and demonstrates browser independent web debugging tools. Best practices for debugging and profiling web application failures and performance issues are also covered.
- Configuring PHP error reporting
- Logging errors to file
- Gracefully handling fatal errors
- Installing Xdebug
- Understanding the principles of remote debugging
- Remote debugging with NetBeans
- Extending your browser with Firebug, FirePHP, or ChromePHP