Profiling applicatif et XDebug
Optimiser les performances d’un site doit passer avant tout chose par le profiling applicatif et c’est bien souvent là que l’on peut gagner une bonne partie des temps de réponse et optimiser la charge à moindre coût. Le profiling applicatif constiste à analyser l’exécution du code que l’on a mis en place pour voir les dépendances entre les méthodes/fonctions, le nombre de fois qu’elles sont appelées et surtout le temps que l’on passe dans chacune d’elles. Une fois ces informations extraites, une partie importante du travail est délivrée par les outils de mise en page (frontend) qui vont nous présenter les résultats agrégés de manière plus intelligible et analysable.
Commençons par le début
Avant de passer à la phase de code profiling, rappelons quelques unes des premières règles à respecter dans tout développement :
- Un code modulaire afin de pouvoir le faire évoluer rapidement, par exemple en changeant le mode d’accès au stockage de données pour toute l’application en modifiant une seule méthode centralisée, en optimisant les temps de réponse de l’application par la modification d’une fonctionnalité appelée dans tout le code, …
- Une séparation de l’IHM et du traitement.
- Une séparation des fonctionnalités de l’application et des APIs.
- Une séparation des ressources et du code.
- Le respect de cinématiques éprouvées de récupération, traitement et affichage des données afin de ne pas maintenir de connexions inutiles aux ressources : gestion d’un pool de connexions afin d’optimiser les temps d’accès aux ressources, connexion aux ressources, récupération des données avec groupage des requêtes, fermeture (ou plutôt replacement dans le pool) de la connexion, traitement des informations récupérées, affichage (HTML, …).
- L’utilisation des types de variables correspondant aux valeurs à positionner dedans afin d’optimiser l’espace requis en mémoire ou en base (par exemple, ne pas mettre un entier dans un varchar…).
- …
La phase de conception du code et le respect des règles fondamentales sont les fondements de toute application. En respectant ces règles, vous partez sur des bases solides et surtout laissez la porte ouverte à des évolutions rapides suite aux informations remontées par les outils de profiling. Par exemple, si le code n’est pas modulaire et que l’on retrouve la cinématique de connexion aux données partout dans le code, et si le profiling du code indique qu’il faut remplacer la méthode d’accès aux données… Cela risque d’être fastidieux.
Le profiling par l’exemple, XDebug
XDebug est un outil de code profiling pour PHP.

L’installation est on ne peut plus simple, disons sous Ubuntu par exemple :
apt-get install php5-xdebug
La première chose à faire est de choisir le déclenchement du profiling. Le profiling étant très verbeux et présentant un overhead certain, je vous conseille le mode trigger dans le xdebug.ini :
xdebug.profiler_enable_trigger=1
Cela permettra de ne déclencher l’analyse du code et la génération de traces que sur l’envoi du paramètre XDEBUG_PROFILE en GET/POST, par exemple : http://localhost/samplepage.php?XDEBUG_PROFILE
Ce paramétrage vous permet également de mettre en place cet outil sur l’environnement de production. A noter de faire attention tout de même sur les sites ouverts au grand public de ne pas se faire avoir par un hackeur taquin qui pourrait provoquer un DOS (Deny Of Service ou déni de service) en appelant vos URLs systématiquement avec ce paramètre ! ;ob Mais ces considérations sont un peu extrémistes et je n’ai jamais rencontré le problème.
Paramétrez également le fichier de destination des traces dans le xdebug.ini :
xdebug.profiler_output_dir=/mnt/xdebug
C’est ce répertoire qui sera utilisé par votre outil d’analyse de traces.
Voilà le type de résultat obtenu :
…
cfn=php::number_format
calls=1 0 0
363 1
fl=php:internal
fn=php::str_replace
340 2
fl=/var/www/mon_site/mon_fichier.inc.php
fn=SimplePrint
39 15
cfn=php::str_replace
calls=1 0 0
340 2
fl=php:internal
fn=php::number_format
363 2
fl=/var/www/mon_site/mon_fichier.inc.php
fn=makeNumberFormat
40 19
cfn=php::number_format
calls=1 0 0
363 2
…
C’est là qu’intervient le frontend
KCacheGrind, puissant mais… sur KDE
KCacheGrind est en effet l’outil le plus complet que j’ai vu pour l’analyse de ces traces, cependant il ne fonctionne que dans un environnement KDE. « Sous Linux donc ! » me direz-vous… Pas forcément. KDE fonctionne sur un certain nombre d’UNIX et a été porté sur Windows (KDE on CygWin), et même sur MacOS X (Fink project).
Heureux (ou pas) utilisateur de Windows (Vista), je n’ai pu résister à vouloir l’installer sur mon poste. Il faut tout d’abord avoir installé Cygwin qui est un émulateur Linux pour Windows qui permet de retrouver les commandes et outils Linux sur son Windows dans un environement émulé (bluffant je dois dire sur certaines commandes). Non intrusif, il installe dans un répertoire une arborescence *NIX et se lance via un « .bat ». Là où j’ai rencontré quelques difficultés, c’est pour l’installation du KDE sur Cygwin. Problème sur la version du KDE, problème sur un package de la distribution Cygwin, … Problème Vista ? Je n’ai pas eu le temps de pousser les investigations plus loin. Mais je ne doute pas que la combo fonctionne.
Si vous êtes un heureux possesseur d’un Linux, allez-y.
KcacheGrind propose des analyses poussées et surtout un système de graphes qui représentent les appels et dépendances entre les méthodes/fonctions.

KCacheGrind
Très complet, il est cependant difficile de l’installer sur un environnement de production ou tout simplement sur un environnement de développement mutualisé du fait des dépendances au KDE. Il faut rappatrier les traces sur son desktop pour les analyser et correspond plus à des analyses de traces ponctuelles, à mon avis, dans un environnement de développement mutualisé, car difficile à intégrer sur la plateforme distante.
Webgrind
Webgrind propose un sous-ensemble des fonctionnalités de KCacheGrind. On ne retrouvera pas notamment les graphes pourtant si pratiques. Cependant, son installation est moins contraignante (voire carrément simple) et il est plus facilement intégrable sur un environnement de développement mutualisé accessible à tous (accès via serveur web). Il suffit de faire pointer l’outil vers le répertoire de sortie de XDebug et on a l’anayse de la trace en direct.

Webgrind
Il permet de voir en un clin d’oeil les appels consommateurs de ressources et de temps et donc d’identifier les éléments du code à améliorer ou bien les librairies utilisées à réexaminer.
Le profiling oui, mais pas forcément PHP
Evidemment, cet exemple que je viens de donner avec l’outil XDebug peut être mis en oeuvre sur d’autres langages et également sur d’autres portées, tout dépend des outils de profiling que l’on va utiliser et leur cible.
Par exemple, j’ai regardé rapidement un outil qui a l’air intéressant et qui s’appelle DynaTrace : DynaTrace permet de tracer les technologies Java et .Net. Sa portée est plus importante car elle va du code jusqu’à la conservation de traces des transactions sur une architecture distribuée (comprendre SOA), cela implique probablement d’avoir des agents sur chaque serveur sur lequel s’exécute une partie du code et que les informations sont agrégées par la suite sur un serveur central sur lequel est installé un composant de la solution. Un viewer permet ensuite de visualiser et de naviguer dans les exports de ces traces. Il est aussi possible de mettre cette solution autant en développement qu’en production (probablement un déclenchement sur trigger, que ce soit par envoi d’un paramètre dans l’URL ou peut-être sur détection d’une erreur lors de l’exécution d’un code). Voilà donc une autre solution qui permet de tracer l’exécution du code dans 2 autres langages, mais aussi avec une portée plus importante puisqu’elle gère la notion de transactions sur une architecture distribuée (à approfondir, car les possibilités sont vastes et la solution probablement pas exhaustive non plus) et avec des possibités de monitoring. Je regarderai cette solution plus attentivement, si j’en ai l’occasion.
Cette solution, en revanche, n’est pas open source et est soumise à un système de licence payante.
Conclusion
Le profiling de code est, comme je le précisais en accroche, le moyen le plus rapide et le moins coûteux d’obtenir des gains de performances sur un site ou une application. Il est toujours (enfin j’espère…) plus aisé de modifier quelques lignes de code que de modifier les services ou l’infrastructure sous-jacente. Il repose tout de même sur de bonnes pratiques de développement afin d’être efficace et surtout afin de pouvoir mettre en oeuvre aisément les modifications qui découleront de l’analyse de l’exécution de code fournie.
Il est intéressant d’intégrer le profiling directement dans les environnements de développement/intégration et de se laisser la possibilité de l’utiliser dans l’environnement cible de production.
Frédéric FAURE


J’ai vu fonctionner DynaTrace par un prestataire de chez http://www.test-performance.com/ sur une application struts1 / hibernate et cet outil a été vraiment très intéressant pour comprendre pourquoi l’application ne montait pas en charge correctement (50 users maxi avant effondrement catastrophique des perfs).
J’ai déjà essayé de faire le même genre de choses avec Eclipse TPTP, mais je n’ai jamais réussi à mettre en place cette solution sur autre chose qu’un Hello World (beaucoup trop lent)… sans parler de la difficulté d’installation.
Merci pour ce topo sur les solutions de profiling pour des applications web.
Je rebondis sur un passage de votre conclusion:
« Il est toujours (enfin j’espère…) plus aisé de modifier quelques lignes de code que de modifier les services ou l’infrastructure sous-jacente. »
Je suis d’accord avec vous quand il s’agit effectivement de quelques lignes, dans ce cas c’est souvent une petite erreur, évidente, qui se corrige facilement.
Quand il s’agit d’une erreur de conception, le choix d’un protocole réseau trop gourmand par exemple et qu’il faut optimiser, c’est très différent. Les changements seront plutôt intrusifs et assez risqués pour la stabilité de l’application au final.
Dans ce cas, je préconiserais d’avantage une mise à jour au niveau CPU et mémoire des différents serveurs.
Le coût est déterminé à l’avance, les gains sont prévisibles, la phase de test est réduite et il n’y a pas de régressions particulières à redouter.
Pour moi, c’est donc un choix à faire au cas par cas :-)
Cordialement.