Connaissez-vous stackalloc du c# ou le localloc de l'IL ?
Suite à une demande d'un de nos experts francophones en création de contrôles winform, pour des contrôles like Vista, j'ai ressorti des placards mes vieux codes (datant de fin 2001, début 2002, eh oui ça passe...) que je lui ai transmis.
Mais je n'étais pas satisfait de la performance des routines. Comme dernièrement, je réécris tout une série d'articles sur les images pour Tech Head Brothers, j'en ai profité pour intégrer les petites trouvailles que j'ai pu faire en étudiant quelques instructions IL.
J'ai découvert que de gros gains peuvent être obtenus avec les tableaux de moins de 8600 octets. Les tableaux que nous utilisons en général sont alloués sur le tas managé. Les tableaux de moins de 8600 octets se trouvent en génération 0. Ils sont donc soumis fréquemment au garbage collector, ce qui provoque un souci de performance. Les tableaux de plus de 8600 octets environ se trouvent en génération 2. Ils sont donc plus rarement soumis au garbage collector.
L'idée est donc de placer à un autre endroit de la mémoire les tableaux de moins de 8600 octets. L'instruction IL localloc permet de réserver de la mémoire dans la zone réservée à la méthode courante. C'est à dire que les données du tableau se trouvent très proches de la pile d'évaluation, d'où un gain évident de performance. De plus, cette zone mémoire n'est pas soumise aux actions du garbage collector. Cette mémoire n'existe que le temps de vie de la méthode : dès que l'instruction IL ret est rencontré, ces zones mémoires ne sont plus accessibles et donc libérées.
En c#, le mot clé, permettant de ne pas avoir à générer de l'IL, est stackalloc. Je l'emploie donc dès que j'ai un tableau de moins de 8600 octets environ qui est souvent appelé. Si vous voulez avoir une idée de la popularité de cette instruction avec la manipulation d'image, n'hésitez pas rechercher sous google ou live search ces mots clés : stackalloc BitmapData. 
Bref, j'ai remis au goût du jour mes filtres de convolutions.
Le principe est simple, on applique une matrice à chaque pixel de l'image.
Voici un exemple de matrice que l'on peut appliquer à chaque pixel d'une image
-1 | -2 | -1
-2 | 16 | -2
-1 | -2 | -1
afin de réhausser la netteté de l'image.
La valeur de chaque pixel voisin est multiplié par un coefficient. On additione le tout puis on divise la somme par un facteur qui est en général la somme des coefficients. A ce résultat, on peut choisir d'ajouter une valeur. Le résultat donne la nouvelle valeur du pixel.
Vous trouverez la source ici : http://www.csharpfr.com/code.aspx?ID=40198
Sachez que j'ai amélioré de près de 65% la performance de mon code ! Je pense que l'on peut encore gagner quelques cycles CPU en analysant le code natif produit.
Concernant l'emploi de stackalloc, faîtes très attention aux possibles débordements de pile! C'est pourquoi, je me fixe comme limite d'utiliser cette instruction que pour les tableaux qui seraient habituellement placés en génération 0 sur le tas, c'est à dire faisant moins de 8600 octets.
Pour ce qui est de mon dernier article ( http://www.techheadbrothers.com/Articles.aspx?Id=8d3eb481-8a98-42a6-8033-e851c797aa60&p=1 ), j'avais laissé un problème à résoudre concernant la performance. Vous avez maintenant un peu la solution avant l'heure:-)
Mon prochain article (en cours d'élaboration) abordera pleinement le sujet.
Update à lire absolument ici : http://blogs.developpeur.org/tkfe/archive/2006/11/10/a-propos-de-mon-post-sur-stackalloc.aspx
Ce post vous a plu ? Ajoutez le dans vos favoris pour ne pas perdre de temps à le retrouver le jour où vous en aurez besoin :