Manipulations de matrices avec du code non sécurisé

La classe Matrix

Dans cet article nous allons comparer 2 méthodes qui traitent de multiplication de matrices en .Net | C#.

Nous commençons par la définition de la classe matrice :  Matrix

    class Matrix
    {
        private readonly double[,] _matrix;
        public Matrix(int dim1, int dim2)
        {
            _matrix = new double[dim1, dim2];
        }

        public int Height { get { return _matrix.GetLength(0); } }
        public int Width { get { return _matrix.GetLength(1); } }

        public double this[int x, int y]
        {
            get { return _matrix[x, y]; }
            set { _matrix[x, y] = value; }
        }
    }

Multiplications de matrices

Voici le premier algorithme de multiplication de matrice qui réalise l’opération de manière standard.

    public static Matrix NaiveMultiplication(Matrix m1, Matrix m2)
    {
        Matrix resultMatrix = new Matrix(m1.Height, m2.Width);
        for (int i = 0; i < resultMatrix.Height; i++)
        {
            for (int j = 0; j < resultMatrix.Width; j++)
            {
                resultMatrix[i, j] = 0;
                for (int k = 0; k < m1.Width; k++)
                {
                    resultMatrix[i, j] += m1[i, k] * m2[k, j];
                }
            }
        }
        return resultMatrix;
    }

Voici le second algorithme qui réalise la même chose, mais cette fois en utilisant du code non sécurisé (unsafe)

   public unsafe static Matrix UnsafeMultiplication(Matrix m1, Matrix m2)
   {
       int h = m1.Height;
       int w = m2.Width;
       int l = m1.Width;
       Matrix resultMatrix = new Matrix(h, w);
       unsafe
       {
           fixed (double* pm = resultMatrix._matrix, pm1 = m1._matrix, pm2 = m2._matrix)
           {
               int i1, i2;
               for (int i = 0; i < h; i++)
               {
                   i1 = i * l;
                   for (int j = 0; j < w; j++)
                   {
                       i2 = j;
                       double res = 0;
                       for (int k = 0; k < l; k++, i2 += w)
                       {
                           res += pm1[i1 + k] * pm2[i2];
                       }
                       pm[i * w + j] = res;
                   }
               }
           }
       }
       return resultMatrix;
   }

 

Mesure des performances

Il est temps maintenant de comparer les performances des 2 opérations

Programme de test de performance

    class Program
    {
        [DllImport("kernel32.dll")]
        static extern void QueryPerformanceCounter(ref long ticks);

        static long Measure(Action action, int count)
        {
            long startTicks = 0;
            QueryPerformanceCounter(ref startTicks);
            for (int i = 0; i < count; i++)
            {
                action();
            }
            long endTicks = 0;
            QueryPerformanceCounter(ref endTicks);
            return endTicks - startTicks;
        }

        static void Main(string[] args)
        {
            Random random = new Random();

            Matrix m1 = new Matrix(20, 30);
            for (int i = 0; i < m1.Height; i++)
            {
                for (int j = 0; j < m1.Width; j++)
                {
                    m1[i, j] = random.Next(-100, 100);
                }
            }

            Matrix m2 = new Matrix(30, 40);
            for (int i = 0; i < m2.Height; i++)
            {
                for (int j = 0; j < m2.Width; j++)
                {
                    m2[i, j] = random.Next(-100, 100);
                }
            }

            Console.WriteLine(Measure(() => Matrix.NaiveMultiplication(m1, m2), 10000));
            Console.WriteLine(Measure(() => Matrix.UnsafeMultiplication(m1, m2), 10000));
        }
    }

Dans ce programme de test nous réalisons 10000 multiplications de 2 matrices générées de façon aléatoires avec des tailles de 20×30 et 30×40 éléments.

Résultat du test de performance

Méthode CPU cycles
multiplication unsafe 4485698
multiplication traditionnelle 58762273

Les résultats montrent que la multiplication de matrice réalisée de façon traditionnelle est plus lente d’un facteur de 13 comparée à la multiplication réalisée par le code non sécurisé et travaillant directement avec la mémoire.

Tags:

Laissez un commentaire

Votre adresse de messagerie ne sera pas publiée. Les champs obligatoires sont indiqués avec *

seize − 4 =

Ce site utilise Akismet pour réduire les indésirables. En savoir plus sur comment les données de vos commentaires sont utilisées.