Archive for April 5th, 2008

xdebug y PHP5 - Haciendo profiling de aplicaciones

Saturday, April 5th, 2008

Hacer profiling de aplicaciones consiste en hacer un mapa (trace) de todas las ejecuciones realizadas por nuestra aplicación con el respectivo tiempo (de CPU, en milisegundos, consumo de RAM, etc) consumido para determinar posibles mejoras en el código, cuellos de botella (bottlenecks) etc.

Quien pensaba que esto era solo una característica de lenguajes como C (que tienen a Valgrind) entonces conozcan la característica de Profiling de Xdebug.

Para instalar Xdebug existen numerosas guías y artículos, me centraré en la posibilidad de realizar el profile de una aplicación como tal.

Configurando xdebug

Para la activación de xdebug he creado un archivo (dentro del directorio conf.d de php5) llamado xdebug.ini que contendrá las instrucciones para activar la extensión y activar de una vez el profiling.

como root:

>touch /etc/php5/conf.d/xdebug.ini

luego, agregamos:

>vim /etc/php5/conf.d/xdebug.ini

zend_extension_ts=”/usr/lib/php5/extensions/no-debug-zts-20060613/xdebug.so”
[xdebug]
xdebug.profiler_enable=1
xdebug.profiler_output_dir=/tmp/php5/profiler

donde fijense que la ruta es donde phpize envía mis extensiones (en este caso, xdebug.so)

Agrego adicionalmente una sección xdebug (se agradece mantener ordenado los archivos ini) y activar “profiler_enable” (1 lo activa, 0 lo desactiva) e indicar la ruta (especificada por profiler_output_dir) donde se ha de crear el archivo de profiling.

guardamos:

:wq!

y reiniciamos nuestro apache:

>/etc/init.d/apache2 restart

En este momento, todas las aplicaciones que ejecutemos de php en nuestro servidor local, generarán un perfil de ejecución en la ruta indicada en profiler.output_dir

Ejecutando la aplicación

Ejecutar la aplicación es simplemente … … “ejecutar la aplicación!” … ya está, sin magia ni trucos …

dentro del directorio indicado se han creado unos archivos, cada uno con un timestamp de ejecución:

cachegrind.out.4286  cachegrind.out.4287  cachegrind.out.4288

Cada archivo es un archivo de texto, conteniendo el perfil de ejecución de la aplicación; ahora bien, ¿con qué lo vemos de una manera más “entendible”? …

Instalando y ejecutando Kcachegrind 

Bueno, el archivo es compatible con los archivos generados por valgrind; así que instalaremos una aplicación para KDE llamada Kcachegrind; simplemente:

>aptitude install kcachegrind

y  luego ejecuten la aplicación (kcachegrind)

Estudiando el perfil

kcachegrind consta de una ventana de 3 paneles:

pantallazo.png

El panel de la izquierda muestra las distintas funciones ejecutadas, desde el comienzo hasta el final, indicando en qué archivo se encontraban, cuando del porcentaje total de ejecución se han consumido y cuanto tiempo en milisegundos les ha tomado en ejecutarse; el panel superior derecho muestra las líneas de código que representa la función seleccionada en el panel derecho y la parte inferior derecha muestra un mapa como este:

profiler.png

Que representa todo el camino (ciclo) de ejecución del código desde donde estamos hasta el final de la ejecución de la clase (objeto), función o archivo seleccionado.

Detectando bottlenecks (cuellos de botella)

Detectar cuellos de botella es fácil de esta manera, simplemente buscamos los mayores tiempos de ejecución y revisamos bloque a bloque hasta encontrar la línea (o líneas) de código que representan la mayor cantidad de tiempo consumido.

bloque.png

De la siguiente ventana de bloque de código deducimos que splib_tomates::init (una función estática de la clase splib_tomates) tiene una duración de 41.10 ms en la línea 57 (call to splib_config::init en el archivo splib_config.php); para no tener que buscar ese archivo en la lista de profiler; simplemente con hacer doble click sobre la linea seleccionada se abrirá el bloque de código (función, archivo) que representa ese bloque de código.

En revisión posterior; determiné que el exceso de tiempo ocurría porque estaba llamando a una librería de caché (de terceros) que estaba ejecutando varios NOTICE y WARNING (aunque Tomates removía los errores); al retirar la librería, se pudo reducir ese tiempo a 26ms.

Conclusiones

No en el 10, el 20 o el 50; casi en el 100% de las aplicaciones web en PHP; los errores y lentitud de ejecución son fáciles de determinar y corregir si todos los desarrolladores antes de liberar una aplicación, ejecutaran debugging y profiling de su código más frecuentemente, realizaran y liberaran pruebas y mantuvieran a raya los “bottlenecks”; pero ya sabemos que eso no ocurre muy a menudo así que queda de parte de los nuevos desarrolladores aprender este tipo de técnicas para mejorar en el desarrollo de sus aplicaciones.

Fallos y cuelgues en Eclipse PDT (standalone edition) en Debian

Saturday, April 5th, 2008

Hace algún tiempo escribí los miles de fallos, cuelgues raros y errores que generaba la versión standalone de Eclipse PDT en Debian (y la versión plugin era horrorosamente lenta!); la razón es que la mitad de Java 1.6 en Debian está corrupto o causa errores extraños (ya me ha pasado con otras aplicaciones Java como Druid o Power Architect).

La forma medio extraña y jocosa de resolver la situación es seguir la siguiente receta:

  • Descargarse el último Java 1.6 de la página de Sun (la versión tar.gz descomprimible, el rpm no sirve en Debian si usas alien).
  • Descomprimir en una carpeta x (yo lo puse en /home/jesuslara/jre1.6.0_05/)
  • Crear un enlace simbólico (si, verdad que es raro?) con el nombre jre de la carpeta anterior dentro de la carpeta principal de Eclipse

En mi caso, he descomprimido el PDT en /home/jesuslara/eclipse por lo que he ejecutado en consola:

cd eclipse

ln -s  /home/jesuslara/jre1.6.0_05/ jre

Pueden ver que se ha creado en:

ls -l

lrwxrwxrwx  1 root      root          28 mar 24 03:05 jre -> /home/jesuslara/jre1.6.0_05/
y ejecuten Eclipse, verán que entre las variables de entorno (Help > About … > Configuration Details …)  verán los siguientes interesantes cambios:

java.class.version=50.0
java.home=/home/jesuslara/jre1.6.0_05
java.runtime.version=1.6.0_05-b12
java.specification.name=Java Platform API Specification
java.specification.vendor=Sun Microsystems Inc.
java.specification.version=1.6
java.version=1.6.0_05

Lo que nunca podremos resolver es que sea 150x veces más pesado que Komodo IDE; al menos es de agradecer que sea licencia Apache.

Aunque con estos cambios, ¡les aseguro! que les agradará el cambio no solo en el performance sino la eliminación de todos (bueno, casi todos :p) los fallos y cuelgues del Eclipse PDT corriendo en Debian.

PHP5 / Eclipse PDT y Subversion

Saturday, April 5th, 2008

Una de las interesantes características por las cuales he usado Eclipse PDT en estos días es por su capacidad de conectarse a un recurso SVN para de manera automática gestionar todo el proceso de desarrollo conectado a un sistema de versiones como Subversion.

En el caso de PHP5, Eclipse PDT puede usar (al igual que cualquier suite basada en eclipse) subclipse; subclipse es un plugin para Eclipse que permite gestionar todo el proceso básico de trabajo con un sistema de versiones (add, update, commit, diff, merge son realizados casi sin ningún problema).

Como instalarlo

Para instalarlo tenemos que ir al menú Help -> Software Updates -> Find and Install …

En la ventana que aparece debemos indicar que vamos a instalar nuevas características (”Search for new features to install” y Next >)

En la ventana de componentes, indicamos que deseamos agregar un nuevo remote site …

El Plugin que vamos a agregar es el siguiente:

Name: Subclipse 1.2.x (Eclipse 3.2+)
URL: http://subclipse.tigris.org/update_1.2.x

Siguiendo los pasos de “next, next, next, finish” (:D ¡Que dificil es Linux!) tendremos nuestro plugin funcionando correctamente.

Nuestros primeros “pinitos” con Subclipse

Aun cuando subclipe tiene la posibilidad de hacer Checkout y agregarlo como un proyecto nuevo en nuestro arbol de proyectos; realmente preferí hacerlo de la manera tradicional; en mi caso:

Una consola:

>svn co http://svn.covetel.com.ve/tomates/trunk/ tomates/

*he descargado de mi sitio web una copia del fuente de Tomates Framework.

Me ha creado una carpeta donde yo me encontraba (en este caso, /var/www/tomates/) y puedo usar ahora esa carpeta como proyecto de Eclipse.

Creando un proyecto de Eclipse PDT

En la perspectiva PHP (menú Window -> Open Perspective -> PHP) indicar File -> new -> PHP Project

Llenar la ventana siguiente con los datos del proyecto (ruta, nombre, si es PHP5 especificamente, etc)

pantallazo-php-project.png

Luego de llenados los datos, presionen Finish y se creará un árbol de proyecto como el siguiente:

php-project.png

Ahora solamente basta con sincronizar dicho proyecto con un repositorio existente:

En la perspectiva SVN Repository ejecutamos botón derecho > New  >  Repository Location … En la ventana (para qué screenshot?, si tiene un único cuadro de texto!) agregamos el URL del repositorio SVN, Finish! y este es cargado como un repositorio de trabajo.

La otra forma consiste en Botón derecho sobre el proyecto > Team > Share Project e indicar “New repository” en la opción de “cual repositorio se usará” para el proyecto actual.

El Menú Team

El menú Team se actualiza una vez que nuestro proyecto está asociado a un repositorio SVN; este muestra las distintas tareas que se pueden realizar con nuestro proyecto y su sincronización con el repositorio:

menu-team.png

La primera opción nos permite sincronizarnos con el repositorio para comenzar a trabajar (esta opción llena la perspectiva “Team Synchronizing Perspective” y es una perspectiva que me permite gestionar el estado de mi repositorio (mensajes de error, SVN annotates, estado de los conflictos de código, anteriormente tareas bastante engorrosas de hacer por consola y hacerlas con rapidSVN era como estar desligado del proceso mismo de desarrollo).

Comandos SVN: Su equivalencia con el Menú Team

svn update -> Update:  permite mantenernos actualizados con el código que terceros de nuestro proyecto han realizado.

svn commit -> Commit … permite agregar nuestros cambios al repositorio ; de manera interesante, Commit … gestiona automáticamente todo archivo nuevo que agreguemos y todo archivo que borremos, de manera que Commit … es una fusión de los comandos svn add y svn delete.

svn merge -> Merge … muchas veces tenemos código escrito por distintos programadores en distintas partes de un mismo archivo, svn merge permite fusionar el código de sectores diferentes

svn diff -> create patch … Si un archivo contiene diferencias a la versión que se encuentra en el repositorio y deseamos crear un patch (archivo de cambios), hacemos click sobre el archivo en conflicto y ejecutamos Team -> create patch …

Enviando nuestros cambios al servidor

Si somos muy activos escribiendo código entonces commit … es una de las ventanas que más usaremos; commit puede actuar sobre el proyecto entero (haciendo click sobre el proyecto, botón derecho > Team > commit …) con lo cual se agregarán todos los cambios globales realizados, o a nivel de un archivo único o carpeta (haciendo click en el archivo o carpeta específicos, puedo realizar botón derecho > Team > Commit … y solo se enviarán los cambios en dicho archivo).

commit.png

Fijense en la ventana anterior; además de la posibilidad de un comentario (svn commit -m ‘comentario’ como se hace en consola), fijense que commit … ha detectado que he borrado un archivo y he agregado una carpeta (aparecen como deleted y unversioned) además de el archivo modificado (que aparece marcado como modified); las carpetas .settings y .project son del Eclipse así que eso no lo envio al repositorio (aunque debería ocultarlo o algo así).

Pero me equivoqué!

Revertir cambios no deseados para no contaminar el repositorio es tan sencillo como detenerse en el archivo (o carpeta, en caso de ser muchos) y ejecutar Team > revert y los cambios serán regresados a la última revisión del repositorio sin causar conflicto entre archivo local y remoto.

Resolviendo diferencias

Otra de las cosas interesantes de Subclipse es la posibilidad de revisar en “Team Synchronizing Perspective” la posibilidad de que existan archivos con diferencias entre la versión local y la versión en el repositorio; para esto:

conflict.png

Al abrir un archivo en la perspectiva “Team Synchronization” veremos nuestro archivo local a la izquiera y el remoto a la derecha; las diferencias vendrán marcadas por una linea negra rodeando el sector de código diferente y un cuadro negro por cada diferencia en la scrollbar; con los botones de arriba podemos copiar el código de un lado a otro del archivo o resolver las diferencias no-conflictivas (para las conflictivas tendremos que editar nuestro código :p).

Para cuando hemos terminado de resolver los conflictos, podemos ejecutar botón derecho sobre el archivo “Mark as Resolved” o en caso de haber realizado un Merge de código “Mark as Merged” y posteriormente Commit … para así guardar los cambios en nuestro repositorio.

La estabilidad, creando branches

Si el proyecto es muy activo (o está en fases iniciales) y llegamos a un punto donde declaramos una cierta “estabilidad” al código, pero queremos seguir agregando cambios (sin afectar que los usuarios finales puedan descargar el código para su uso o prueba) decretamos la creación de una branch (rama) que no es más que la declaración de un release de nuestro código en el repositorio; es tan facil como hacer click en nuestro proyecto y ejecutar botón derecho > Team > Branches/Tags y definir hacia donde va el código de la nueva rama (en el caso de tomates, http://svn.covetel.com.ve/tomates/branches/).

Ver lo que los demás han hecho y comentado

Por lo general los comentarios de cada revisión y las anotaciones en la rama SVN ayudan de mucho a saber que están haciendo los programadores y a continuar el trabajo sin pasar media hora dando vueltas a ver que cosas nuevas agregaron; Team > view comments y Team > View History me permite ver las anotaciones y la historia de las revisiones del repositorio actual.

Conclusiones

Para un usuario de GUI e IDE’s esto es una caraterística más que nos mantiene acostumbrados al uso de herramientas de desarrollo fáciles y rápidas, es de agradecer las capacidades de mantener a mi equipo de desarrollo sincronizados con los cambios sin tener que estar ejecutando comandos por consola o preocupandose por algo más que contribuir con código al proyecto; también es de hacer notar que si un abyecto y abnegado usuario de vim (muy potente editor por cierto) como walter (alias elsanto) ha dejado de usar vim para programar para unirse a los usuarios de Eclipse (en su caso como le gusta javascript/jquery usa aptana IDE) y de verdad comenzar a trabajar de manera colaborativa y sin estar ejecutando comandos raros en la consola.