Bienvenue à Blogs CodeS-SourceS Identification | Inscription | Aide

Tkfé

.Net passionnément, tout simplement

Actualités



  • Frédéric Mélantois
    A part boire du café ou du thé à longueur de journées, il m'arrive de coder ;-)
    Petite citation :
    Je n'éblouis pas mon entourage, je le fais rayonner. F.M. @1986
Copier des blocs de mémoire en c# et VB.NET

Comment faîtes-vous actuellement ? Il y a de fortes chances que vous utilisiez le Marshal.copy pour la mémoire non-managée. Vous utilisez peut-être une dll via l'interop

C'est en étudiant le langage IL (intermediate language) que je me suis aperçu qu'une instruction IL permettait de le faire : cpblk

L'idée de me faire une petite dll pour me permettre de réaliser des copies rapides de blocs sous c# ou Vb.net m'est vite venu. Démonstration rapide :

Copiez le code suivant dans notepad :

.assembly extern mscorlib
{
  .ver 2:0:0:0
}

.assembly Memoire
{
  .ver 1:0:0:0
}
.module Memoire.dll


.class public abstract auto ansi sealed beforefieldinit Memoire.Memory
       extends [mscorlib]System.Object
{
  .method public hidebysig static void  MemCpy(int32 destination,
                                             int32 source,
                                             int32 nboctet) cil managed
  {
    .maxstack  3
    ldarg.0
    ldarg.1
    ldarg.2
    cpblk
    ret
  }

  .method public hidebysig static void  MemCpy(native int destination,
                                             native int source,
                                             int32 nboctet) cil managed
  {
    .maxstack  3
    ldarg.0
    ldarg.1
    ldarg.2
    cpblk
    ret
  }
}

A noter que j'ai laissé les noms comme destination, source et nboctet afin qu'il puisse apparaître dans l'éditeur visual studio après le référencement de la dll. Ces noms d'argument ne sont pas obligatoires en IL. De même l'instruction hidebysig ne sert à rien, si ce n'est pour préciser à c# ou vb.net que la méthode
possède une autre signature semblable.
ldarg.0, ldarg1, ldarg2 sont des instructions permettant de déposer les arguments de la méthode sur la pile.
L'instruction cpblk s'excute à partir des valeurs de la pile. A noter que celle-ci est classé comme invérifiable, c'est à dire que cela correspond au contexte unsafe du c#. Ce qui correspond au SkipVerification des permissions .NET

Sauvegardez le code IL sous Memoire.IL
ouvrez une invite DOS et tappez : ILASM Memoire.il /dll

N'hésitez pas à regardez les options de ilasm /?

Memoire.dll a été généré. Il vous suffit maintenant d'ajouter comme référence dans votre projet c# ou VB.NET.

Effectuons un test pour voir si ceci est concluant :

        public static void CopyGDI(Bitmap destination, Bitmap source)
        {
            Graphics g = Graphics.FromImage(destination);
            g.DrawImage(source, 0, 0, source.Width, source.Height);
            g.Dispose();
        }

        public static void CopyPointer(Bitmap destination, Bitmap source)
        {
            int width = source.Width;
            int height = source.Height;

            unsafe
            {

                BitmapData bmpData = source.LockBits(new Rectangle(0, 0, width, height), ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb);

                BitmapData bmpDataMirror = destination.LockBits(new Rectangle(0, 0, width, height), ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb);

                //image source
                int* newPixel = (int*)(void*)bmpData.Scan0;
                //image destination
                int* mPixel = (int*)(void*)bmpDataMirror.Scan0;
               
                for (int y = 0; y < height; y++)
                {
                    //on copie ligne à ligne comme doit le faire sans doute le DrawImage 
                    Memoire.Memory.MemCpy((int)mPixel, (int)newPixel, width * 4);

                    newPixel += width;
                    mPixel += width;
                }
                source.UnlockBits(bmpData);
                destination.UnlockBits(bmpDataMirror);
            }

        }

  public static void CopyIntPtr(Bitmap destination, Bitmap source)
  {
   int width = source.Width;
   int height = source.Height;

   BitmapData bmpData = source.LockBits(new Rectangle(0, 0, width, height), ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb);

   BitmapData bmpDataMirror = destination.LockBits(new Rectangle(0, 0, width, height), ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb);

   
            Memoire.Memory.MemCpy(bmpDataMirror.Scan0, bmpData.Scan0, width * height * 4);

   source.UnlockBits(bmpData);
   destination.UnlockBits(bmpDataMirror);

  }


Résultat des tests : les méthodes copyIntPtr et copyPointer, une fois la première initialisation faîte, sont 6 à 7 fois plus rapide que la méthode CopyGDI.

Je vous détaillerai bientôt sous forme d'un article ce que je viens de vous présenter succintement dans ce post. J'espère que ceux qui recherchaient un peu plus de performance en c# et vb.net, trouveront ici leur bonheur.

ps : l'exemple ci-dessus n'est peut-être pas le plus adapté pour la pédagogie mais je n'ai pas résisté à vous présenter cette perspective.

ps2 : Si vous faîtes un coup de reflector sur la dll, il vous mettra Memcpy aussi bien en c# qu'en VB.NET car il n'a pas d'équivalent pour le c# ou le VB.NET. En fait, il s'agit d'une instruction de c++.

ps3 : Ce post est un peu brute, je vous le présenterai mieux dans un prochain article.

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 :
Posted: lundi 13 novembre 2006 13:18 par tkfe

Commentaires

sebmafate a dit :

waouh... t'es un grand malade !

# novembre 13, 2006 14:35

themit a dit :

Si ca continue, il nous faudra un reflector pour te comprendre :D :D :D

Mon dieu, il lit mieux l'IL que le code

TKFE tu es impressionnant!

(compliment pas boutade)

# novembre 13, 2006 14:56

cyril a dit :

rien à redire ...

Respect !

Tu es le premier que je connais qui code en IL ! :-)

# novembre 13, 2006 15:13

tkfe a dit :

Je dois rendre hommage à Michel Perfetti qui m'a initié à l'IL, après avoir repris un de mes articles sur le mapping de données par attributs sur THB.

On doit toujours quelque chose à quelqu'un. Dernièrement, c'est Bruno Nati qui me donnait quelques conseils (natifs:-) pour avoir un peu plus de performance dans mes boucles.

# novembre 13, 2006 15:22

badrbadr a dit :

.class public abstract auto ansi sealed beforefieldinit Memoire.Memory

      extends [mscorlib]System.Object

Si j'ai bien compris, t'ajoutes deux méthodes à la classe Object? Je pensais que c'était une feature du C# 3.0 que d'ajouter des méthodes à des classes déjà compilées :)

# novembre 13, 2006 15:36

ROMELARD Fabrice a dit :

Simplement un mot :

- respects

Franchement passer directement par de l'IL pour améliorer du code C#, il fallait y penser.

Fabrice.

# novembre 13, 2006 15:37

Bidou a dit :

Très intéressant!

J'espère avoir un jour le même niveau :-)

# novembre 13, 2006 16:34

Laurent GEFFROY a dit :

Ca me troue le ....

Quand est-ce que tu publies ton article sur la mise en cluster de smartphones ?

Je crois que la manie de fouiller au plus profond lui vient de ces études supérieures.

# novembre 13, 2006 18:01

tkfe a dit :

Après m'être investi pendant plus d'un an dans la finance pour permettre le développement d'un nouveau S.I. pour le cabinet de courtage en assurances qui m'emploie, alors que je me suis écarté forcément un peu de l'actualité, et comme aurait dit Desproges, le doute m'habite, vos commentaires me font beaucoup de bien. Merci!

Pour ce qui est de l'IL, n'hésitez pas à vous plonger dans les spécifications ECMA : http://msdn2.microsoft.com/en-us/netframework/aa569283.aspx dans la partition 3 (cpblk est défini page 63).

BadrBadr, ".class" ne spécifie pas en IL une classe comme on pourrait s'y attendre. L'"extends" va déterminer s'il s'agit d'un objet de type référence (System.Object), d'une structure (System.ValueType) ou d'une énumération (System.Enum).

# novembre 13, 2006 23:08

white_mage a dit :

Très intéressant cet article !! J'adore...

C'est bien la preuve que l'IL peut-être très utile dans certains cas et que les langages bas niveau ont encore de long jours devant eux...

# novembre 14, 2006 09:02

Matthieu MEZIL a dit :

Tu es devenu maître dans l'art de programmer en IL. Ton article sur C#3.0 (plus récent) le prouve une fois de plus ;-)

Félicitations

# juillet 13, 2007 20:30
Les commentaires anonymes sont désactivés

Les 10 derniers blogs postés

- Silverlight 3 : Communication et multicast par Kévin Gosse le il y a 8 heures et 6 minutes

- [Perso] Découvertes estivales : Linux (Part I) par Le blog de FremyCompany le il y a 10 heures et 48 minutes

- [Refactoring] ReSharper pour Visual Studio 2010 (Preview) par Thomas Jaskula le 07-04-2009, 00:50

- [Refactoring] Analyser vos exceptions avec ReSharper Exceptional par Thomas Jaskula le 07-03-2009, 23:36

- SharePoint 2007 : patterns & practices SharePoint Guidance par Philippe Sentenac [MVP SharePoint] le 07-03-2009, 09:56

- [Visual Studio 2010] Les tests cases c’est bien, mais je vais devoir tout réécrire ? par Etienne Margraff le 07-03-2009, 09:00

- MVP[Gribouillon].AddYear par The Grib's Lair [Sébastien PICAMELOT - MVP SharePoint] le 07-03-2009, 08:45

- Clinique INSIA - Projet de fin d’Etudes (Silverlight 3 MVVM et OutOfBrowser, WCF, TFS) - Part 1 par David REI le 07-02-2009, 23:38

- C’est la crise ? Bah pourquoi cramer du budget pub alors ? par Nix's Blog le 07-02-2009, 15:31

- Soyons MVP ! par TheSaib .NET blog le 07-02-2009, 12:15