Tester unitairement la performance en Java

L'importance accordée aux tests lors du développement joue un rôle primordial dans la réussite et la qualité d'une application. Si dans bon nombre d'applications il existe des tests unitaires, les tests de performance sont souvent absents ou interviennent tardivement (bien souvent lorsque des problèmes commencent à être remontés).
Pour diagnostiquer au plus tôt ces problèmes, il existe des outils permettant de tester unitairement la performance. Parmi ceux disponibles, j'ai retenu ContiPerf.

Petit tour d'horizon des fonctionnalités offertes par l'outil.

La performance des tests fonctionnels

Vous avez un projet Java (ou avec une autre technologie Web). Si dans votre projet, vous avez des scénarios Selenium pour vous assurer que votre projet ne présente pas de régressions fonctionnelles, c'est bien, vous êtes un bon élèves. Si en plus, vos tests sont automatisés par une plate-forme d'intégration continue (du type Jenkins), alors vous méritez une mention honorable. Mais est-ce que vous avez pensé à collecter des données de performance pendant l'exécution de ces tests ?

Un outil à la rescousse

Pour nous aider dans cette tache, dynaTrace met à notre disposition un outil gratuit qui peut facilement se glisser une plate-forme existante de tests Selenium. L'outil en question se nomme "dynaTrace Ajax Edition" et vous pouvez le trouver à l'adresse suivante : http://ajax.dynatrace.com/ajax/en/

Lorsqu'on lance à la main l'outil, on alors la possibilité d'exécuter le navigateur de son choix et l'outil capturera, au cours d'une session d'analyse, toutes les requêtes qui passe par le navigateur et rendra compte du temps passé dans le réseau, celui passé dans le rendu de la page ou dans les scripts :

Chaque session est ensuite archivée. C'est donc une vision assez complète de la performance de la requête du point de vue client que nous obtenons. Si vous êtes en train de tester en lisant mes explications, vous allez surement me dire que c'est bien joli tout ça mais comment peut-on faire pour que les données soient collectées pendant l'exécution de mes tests Selenium. Rien ne l'empêche car dans les faits, dynaTrace Ajax Edition est un plugin ajouté au navigateur, il est constament présent (même lorsqu'on lance le navigateur en dehors d'une session de l'outil). Il suffit de savoir communiquer avec ce plugin ; et le langage disponible est la variable d'environnement. Pour ma part, j'en utilise 3 :

  • DT_AE_AGENTACTIVE       # active la collecte des données par dynaTrace Ajax Edition ; à noter que l'outil doit être lancé pour agréger les données capturées par le plugin
  • DT_AE_AGENTNAME    # donne un nom aux données collectées
  • DT_AE_CLEARCACHE    # nettoie le cache avant de lancer les requêtes ou non

Dans la pratique avec Selenium, vous avez surement un script de lancement votre Remote Control qui ressemblera à :

set DT_AE_AGENTACTIVE=true
set DT_AE_AGENTNAME=IDEO_SELENIUM
set DT_AE_CLEARCACHE=true
ant -Dport=5557 -Dhost=localhost -DhubURL=http://localhost:4444 -Denvironment="ie 8 windows" launch-remote-control

Dorénavant, à chaque fois que le Remote Control lancera un navigateur et que dynaTrace Ajax sera démarré, les données de performance seront archivées dans l'outil :

Les inconvénients

C'est prometteur mais ce n'est pas parfait. En tout cas, personnellement, j'y vois quelques inconvénients :

  • Tout d'abord une limitation de la version gratuite : seul les navigateurs Internet Explorer 8, 9 et 10 et Firefox 9 et 10 sont officiellement supportés. Si vous voulez supporter de plus ancienne version, il faudra soit regarder du côté de la version payante, soit rechercher d'autres outils
  • Ce n'est pas une solution centralisée : en effet, les données ne sont visibles et archivées que sur le client lourd sur le poste où le client web s'exécute. Dans le cas d'un Grid Selenium, où il y a certainement autant de machines (certainement virtuelles) que de versions de navigateur à tester, il y aura autant de client lourd dynaTrace à lancer.
  • Le suivi des performance n'est pas aisé : ce qui est principalement interressant avec ce genre de mesure, c'est d'avoir un suivi des mesures pour voir rapidement les dégradations induites par les nouveaux développements. Ici, je ne trouve pas ça évident. Tout d'abord, le nom des données archivées est celui données dans la variable d'environnement DT_AE_AGENTNAME. Il n'est donc déterminé qu'au moment de lancer le Remote Control, autant dire que toutes les archives porteront le même nom (que ce soit pour tester l'affichage d'une liste ou d'un message d'alerte). De toute façon, la comparaison n'est pas facile, il faut ouvrir les archives prendre les mesures à la main et les comparer soit même.

Un début de solution

Nous ne sommes pas pour autant totalement dépourvu si on décide de prendre le temps de développer ses propres outils. Avec l'aide de quelques paramètres, dynaTrace peut émettre une requête HTTP avec un contenu JSON synthétisant les données enregistrées pendant une session d'analyse. Avec une simple servlet et un parser du type google-gson, il est alors possible de récupérer les valeurs et de les archiver soi-même de manière centralisée.

Les paramètres sont à ajouter dans le fichier dtajax.ini dans le répertoire d'installation de dynaTrace :

-Dcom.dynatrace.diagnostics.ajax.beacon.uploadurl=http://localhost:8080/beaconstorage/endpoint
-Dcom.dynatrace.diagnostics.ajax.beacon.portalurl=http://localhost:8080/beaconstorage/endpoint
-Dcom.dynatrace.diagnostics.ajax.beacon.autoupload=true

Et la requête JSON reçu alors par votre Servlet (ou autre technologie) sera de la forme :

{
 "version":"2.0.0",
 "url": "www.mydomain.com",
 "rank":95,
 "ranks":{
 "cache": {"rank":100, "comment":"" },
 "net": {"rank":98, "comment":"" },
 "server": {"rank":94, "comment":"2 dynamic server-requests" },
 "js": {"rank":89, "comment":"4 slow JS handlers"}
 },
 "timetoimpression":1587,
 "timetoonload":1645,
 "timetofullload":2747,
 "reqnumber":9,
 "xhrnumber":0,
 "pagesize":264562,
 "cachablesize":0,
 "noncachablesize": 264562,
 "timeonnetwork": 400,
 "timeinjs": 30,
 "timeinrendering":200
}

Vous trouverez de plus ample information sur le site officiel de dynaTrace bien sûr : http://ajax.dynatrace.com/ajax/en/ mais aussi sur le blog officiel du produit : http://blog.dynatrace.com/2010/10/30/web-performance-optimization-use-cases-part-3-automation/

Java et la gestion de la mémoire

Les problèmes de performance  les plus couramment rencontrés en Java peuvent provenir de quatre causes :

  • Le code de l'application
  • L'environnement sur lequel s'exécute l'application (serveur d'application, jvm, os)
  • Dépendances externes (base de données, web services, ...)
  • Charge excessive

Les causes ci-dessus sont données dans l'ordre de leur probabilité d'occurrence.

Il faut bien comprendre que l'upgrade du serveur physique n'intervient qu'en dernier lieu ! En effet, La cause est souvent logicielle avant d'être matérielle.

Dans ce billet, je vais rentrer plus en détail sur l'optimisation de la JVM Sun et plus particulièrement sur la gestion de la mémoire.

Pour optimiser le fonctionnement de tortoiseSVN et reduire la mémoire utilisée

I've got a lot of background processes running and killing my disk performance with all the I/O they're doing.  One of the primary offenders is the TortoiseSVN cache that helps put the icon overlays in Explorer.  Several folks I know disabled the cache altogether, but I like the icons.

Rather than disable the cache, you can optimize the paths it looks at so it only actually looks at working copies and not your whole disk.  If you keep all of your working copies in specific known locations, this is a really simple thing to do.  For example, I keep all of my checked out code in one of three places - a "dev" folder I have, the "Visual Studio 2005" folder in "My Documents," and the "Visual Studio Projects" folder in "My Documents."

To optimize the disk usage...

  1. Right-click on your desktop and select "TortoiseSVN -> Settings..."
  2. In the tree view, find the "Look and Feel/Icon Overlays" branch.
  3. In the "Exclude Paths" box, put C:* to exclude the entire C drive.  If you have more drives than that, exclude them all at the top level.  Separate the values by newlines.
  4. In the "Include Paths" box, list all of the locations you have working copies, separated by newlines.  Again, this is easier if you keep all of your working copies in a specific folder or set of folders.  Using my example, this is what I put in the "Include Paths" box:
    C:dev*
    C:Documents and SettingstilligMy DocumentsVisual Studio 2005*
    C:Documents and SettingstilligMy DocumentsVisual Studio Projects*
    And here's a screen shot:
    TortoiseSVN icon overlay options - set the "Exclude paths" and "Include paths" values
  5. Click OK to apply the changes.
  6. Either reboot or open Task Manager and kill "TSVNCache.exe" so it restarts when needed.  You have to restart it for these options to take effect.

After I did this, the icon overlays still worked great but the disk I/O went down to nearly nothing.  YMMV.