Xdebug en PHP (KCachegrind y Webgrind)

Cuando queremos que nuestros scripts php sean más rápidos y sin atascos tenemos varias opciones, cachear, acelerar código, depurar... todas ellas complementarias y elementales para aplicaciones de alto rendimiento.
Hoy hablaremos de la depuración y localización de cuellos de botella. Para ello tenemos varias herramientas indispensables en PHP que pueden facilitar mucho la vida del programador. Entre ellas se encuentran Xdebug y APD. En este artículo trataremos la instalación y configuración de la primera, así como varias herramientas de análisis y representación gráfica de informes.
Xdebug con PEAR
La instalación de Xdebug puede llevarse a cabo de varias formas distintas, aquí se abordarán las dos más frecuentes, a través de PEAR o compilándolo como extensión Zend. Empecemos por la primera.
Para instalar Xdebug en Debian/Ubuntu lo haremos a través de PEAR (pecl):
# apt-get install php-pear
Intentamos la instalación de Xdebug, pero nos dará un error:
# pecl install xdebug
downloading xdebug-2.0.3.tgz ...
Starting to download xdebug-2.0.3.tgz (286,325 bytes).........done: 286,325 bytes
66 source files, building
running: phpize
sh: phpize: not found
ERROR: `phpize' failed
Necesitamos phpize, una herramienta que viene disponible en el paquete de desarrollo de php, lo instalamos:
# apt-get install php5-dev
Y repetimos:
# pecl install xdebug
[...]
Build process completed successfully
Installing '/usr/lib/php5/20060613+lfs/xdebug.so'
install ok: channel://pecl.php.net/xdebug-2.0.3
configuration option "php_ini" is not set to php.ini location
You should add "extension=xdebug.so" to php.ini
Agregamos la extensión y configuramos para que el profiler se active de forma automática y guarde los logs en el directorio /var/log/xdebug:
extension = xdebug.so
xdebug.profiler_enable = 1
xdebug.profiler_output_dir = "/var/log/xdebug"
xdebug.profiler_output_name = "-%H%R-%u.webgrind"
xdebug.auto_trace = On
xdebug.trace_output_dir = "/var/log/xdebug"
xdebug.trace_output_name = "trace-%H%R-%u"
Ojo: El directorio /var/log/xdebug debe tener permisos para el usuario www-data, que es el que escribirá el informe.
Como paso final creamos un típico phpinfo.php y reiniciamos el servidor para ver si -con la nueva configuración- genera el informe cuando visitemos http://localhost/phpinfo.php:
# echo "<?php phpinfo(); ?>" >> /var/www/phpinfo.php
# /etc/init.d/apache2 restart

Xdebug en phpinfo()
La visualización de ésta página generará un informe /var/log/xdebug/cachegrind.out.3159, que podremos analizar bien por Webgrind o por Kcachegrind.
Xdebug como extensión Zend
Antes de nada veremos si tenemos instalado php5-dev o no. Si no es así lo instalamos:
# dpkg -l | grep php5-dev
# apt-get install php5-dev
Una vez instalado bajamos Xdebug a una carpeta temporal, descomprimimos, preparamos la extensión para compilarla, compilamos e instalamos:
# wget http://xdebug.org/link.php?url=xdebug203
# tar xfvvz xdebug-2.0.3.tgz
# cd xdebug-2.0.3
# phpize
Configuring for:
PHP Api Version: 20041225
Zend Module Api No: 20060613
Zend Extension Api No: 220060519
# ./configure --enable-xdebug
# make
# make install
Installing shared extensions: /usr/lib/php5/20060613+lfs/
Para la configuración posterior tenemos que usar el archivo php.ini que esté cargado, con lo que abrimos ese archivo (/etc/php5/apache2/php.ini) y agregamos las siguientes lineas antes de ;End:
zend_extension=/usr/lib/php5/20060613+lfs/xdebug.so
xdebug.profiler_enable=1
xdebug.remote_enable=1
xdebug.profiler_output_dir=/var/www/webgrind/log/
Debemos cerciorarnos de que el directorio de log tiene los permisos adecuados para que el usuario de apache (www-data en este caso) pueda escribir ahí sus informes. El último paso será reiniciar Apache:
# /etc/init.d/apache2 restart
Si todo ha salido correctamente veremos en phpinfo() algo parecido a lo siguiente:
This program makes use of the Zend Scripting Language Engine:
Zend Engine v2.2.0, Copyright (c) 1998-2007 Zend Technologies
with Xdebug v2.0.3, Copyright (c) 2002-2007, by Derick Rethans

Xdebug en phpinfo()
KCacheGrind
Es una herramienta en QT (KDE) que analiza y representa el informe creado por Xdebug, tan solo hay que abrir el archivo cachegrind.out correspondiente y echar un vistazo. Para instalar es tan sencillo como hacer un:
# apt-get install kcachegrind
Varios pantallazos de ejemplo:

Ejemplo de KCacheGrind con phpinfo()

Ejemplo de KCacheGrind con Kohana

Ejemplo de KCacheGrind con Code Igniter
Webgrind
Llega el turno para Webgrind, un frontend web para analizar los logs generados por Xdebug. Instalarlo es tan sencillo como bajarse el fuente y descomprimirlo en un documentroot accesible:
# cd /var/www/webgrind/
# wget http://webgrind.googlecode.com/files/webgrind-release-0.81.zip
# unzip webgrind-release-0.81.zip
Una vez lo tenemos descomprimido y listo solamente hemos de configurar el directorio de donde ha de leer los cachegrind.out generados por el profiler de Xdebug. Eso se hace en el config.php:
/**
* Writable dir for information storage.
* If empty, will use system tmp folder or xdebug tmp
*/
static $storageDir = '/var/www/webgrind/log/';
Ahora nos vamos al interfaz web (http://localhost/webgrind/ por ejemplo) y seleccionamos en el combo superior el archivo grind a pintar:

Webgrind en acción
El informe detallado de profiling será algo similar a lo siguiente:

Informe detallado en Webgrind
Referencias
- Página oficial de Xdebug
- Profiling PHP (por Alex Sancho)
- Xdebug en DevZone Zend 1 (2, 3, 4 y 5)