Profiling shows up any bottlenecks in a program, it gives real metrics that can be analysed. Looking at the code and making educated guesses at the problem areas is usually ineffectual.
We need to profile the whole user experience so that it includes complex JavaScript and external effects due to latency and distance, load balancers and so on. Usefule tools may be Graphite, LogStash. But that's for another article. Here I am just dealing with backend.
- xhprof: Doesn't support PHP7. No detraction on performance so can be used on production servers. Can use it on s specified subset of data. It was developed by Facebook.
- Tideways: a fork of xhprof, it costs money but there is a 30 day free trial available.
- xdebug profiler: venerable but it works with php7.0 and it's opensource. It slows the program considerably so not suitable for production server, also speed benefits may be greater than indicated.
- cachegrind: companion to xdebug profiler in various forms - kCacheGrind, qCacheGrind and as a web app, WebCacheGrind.
At the time of writing I am using Debian Testing for development. The xdebug package installs php7.0, so that is being used with apache. Install xdebug:
apt-get install php-xdebug
relevant values from /etc/php/7.0/php.ini:
; xdebug debugging
zend_extension=/usr/lib/php/20151012/xdebug.so
xdebug.remote_enable=1
xdebug.remote_enable=0
xdebug.remote_handler=dbgp
xdebug.remote_host=local
xdebug.remote_port=9000
; xdebug profiling
xdebug.profiler_enable=0
xdebug.profiler_enable_trigger = 1
xdebug.profiler_output_dir = /tmp
xdebug.profiler_output_name = cachegrind.out.%R.%t
With the enable_trigger set to 1, we can profile any page by adding XDEBUG_PROFILE to the end of the url. The alternative is to set profiler_enable=1 and turn off trigger. This would profile every time.
By default the output is sent to a file in the tmp directory which we can we can pass on for viewing by kCacheGrind, WebCacheGrind or similar. The php.ini options for output_dir and output_name may be used - the directory must be writeable by PHP. Output from phpinfo() gives the following.
inifile item | value
-------------------------------------------|-----------
xdebug.profiler_aggregate | Off
xdebug.profiler_append | Off
xdebug.profiler_enable | Off
xdebug.profiler_enable_trigger | On
xdebug.profiler_enable_trigger_value | no value
xdebug.profiler_output_dir | /tmp
xdebug.profiler_output_name | cachegrind.out.%p
xdebug.remote_addr_header | no value
xdebug.remote_autostart | Off
xdebug.remote_connect_back | Off
xdebug.remote_cookie_expire_time | 3600
xdebug.remote_enable | On
xdebug.remote_handler | dbgp
xdebug.remote_host | localhost
xdebug.remote_log | no value
xdebug.remote_mode | req
xdebug.remote_port | 9000
Having got profiling in the browser working in Debian, and setting values in /etc/php/7.0/apache2/php.ini we can run the profiler:
xdebug.profiler_enable = 1
xdebug.profiler_enable_trigger = 0
xdebug.profiler_enable = 0
xdebug.profiler_enable_trigger = 1
for this method, run as http://localhost/phpinfo.php?XDEBUG_PROFILE
and view the results using kcachegrind. Remember that the results will be significantly
slower than in production.
- Perf Planet Profiling articles, how-to's, what to do next.
- PHP UK Conference 2014 - Profiling PHP Applications Introductions to XDEbug Profiler(starts around 22 mins), XHProf with Zend Toolbar Extension(starts around 24 mins), how to improve page loading - tools and techniques (starts around 49 mins).