7 votes

Ce code peut-il être optimisé ?

J'ai un code de traitement d'image qui boucle sur deux tableaux d'octets multidimensionnels (de même taille). Il prend une valeur dans le tableau source, effectue un calcul dessus, puis stocke le résultat dans un autre tableau.

int xSize = ResultImageData.GetLength(0);
int ySize = ResultImageData.GetLength(1);

for (int x = 0; x < xSize; x++)
{                
   for (int y = 0; y < ySize; y++) 
   {                                                
      ResultImageData[x, y] = (byte)((CurrentImageData[x, y] * AlphaValue) +
                                    (AlphaImageData[x, y] * OneMinusAlphaValue));
   }
}

La boucle prend actuellement ~11ms, ce qui je suppose est principalement dû à l'accès aux valeurs des tableaux d'octets car le calcul est assez simple (2 multiplications et 1 addition).

Y a-t-il quelque chose que je puisse faire pour accélérer le processus ? C'est une partie critique de mon programme et ce code est appelé 80-100 fois par seconde, donc tout gain de vitesse, même minime, fera une différence. En outre, pour le moment, xSize = 768 et ySize = 576, mais cela augmentera à l'avenir.

Mise à jour : Merci à Guffa (voir réponse ci-dessous), le code suivant me fait gagner 4-5ms par boucle. Bien que ce soit non sécurisé code.

int size = ResultImageData.Length;
int counter = 0;
unsafe
{
    fixed (byte* r = ResultImageData, c = CurrentImageData, a = AlphaImageData)
    {
        while (size > 0)
        {
            *(r + counter) = (byte)(*(c + counter) * AlphaValue + 
                                    *(a + counter) * OneMinusAlphaValue);
            counter++;
            size--;
        }
    }
}

3voto

torial Points 9883

Rapidement, vous pouvez obtenir une optimisation en bouclant en sens inverse et en comparant avec 0. La plupart des CPU ont une opération rapide pour la comparaison avec 0.

Par exemple

int xSize = ResultImageData.GetLength(0) -1;
int ySize = ResultImageData.GetLength(1) -1; //minor optimization suggested by commenter

for (int x = xSize; x >= 0; --x)
{                
     for (int y = ySize; y >=0; --y) 
     {                                                
          ResultImageData[x, y] = (byte)((CurrentImageData[x, y] * AlphaValue) +
                                         (AlphaImageData[x, y] * OneMinusAlphaValue));
     }
}

Voir http://dotnetperls.com/Content/Decrement-Optimization.aspx

3voto

Henk Holterman Points 153608

Vous souffrez probablement de Boundschecking. Comme le dit Jon Skeet, un tableau en dents de scie au lieu d'un tableau multidimensionnel (c'est à dire data[][] au lieu de data[,] ) sera plus rapide, aussi étrange que cela puisse paraître.

Le compilateur optimisera

for (int i = 0; i < data.Length; i++) 

en éliminant la vérification de la portée par élément. Mais c'est une sorte de cas spécial, il ne fera pas la même chose pour Getlength().

Pour la même raison, la mise en cache ou le stockage de la propriété Length (en la plaçant dans une variable comme xSize) était également une mauvaise chose, bien que je n'aie pas pu le vérifier avec le Framework 3.5.

2voto

Jasper Bekkers Points 4949

Essayez de permuter les boucles for x et y pour obtenir un modèle d'accès à la mémoire plus linéaire et (donc) moins de ratés de cache, comme ceci.

int xSize = ResultImageData.GetLength(0);
int ySize = ResultImageData.GetLength(1);

for (int y = 0; y < ySize; y++) 
{
    for (int x = 0; x < xSize; x++)
    {
        ResultImageData[x, y] = (byte)((CurrentImageData[x, y] * AlphaValue) +
            (AlphaImageData[x, y] * OneMinusAlphaValue));
    }
}

1voto

Ed S. Points 70246

Si vous utilisez LockBits pour accéder au tampon d'image, vous devez boucler sur y dans la boucle externe et sur x dans la boucle interne, car c'est ainsi qu'il est stocké en mémoire (par ligne et non par colonne). Je dirais que 11 ms est assez rapide...

1voto

Jon Skeet Points 692016

Les données de l'image doivent-elles être stockées dans un tableau multidimensionnel (rectangulaire) ? Si vous utilisez plutôt des tableaux en dents de scie, il se peut que le JIT offre davantage d'optimisations (y compris la suppression de la vérification des limites).

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X