1

J'ai un algorithme de traitement d'image simple. En bref, une image (moyenne) dans le flotteur est soustrait par une image 8 bits le résultat est alors enregistrer une image flottante (dest)Optimisation d'une boucle avec peu d'instructions (SSE2, SSE4) avec TBB

cette fonction est principalement écrit par intrinsics.

J'ai essayé d'optimiser cette fonction avec TBB, parrallel_for, mais je n'ai reçu aucun gain de vitesse mais de pénalité.

Que dois-je faire? Devrais-je utiliser un schéma de niveau inférieur tel que la tâche TBB pour optimiser le code?

float   *m, **m_data, 
       *o, **o_data; 
unsigned char *p, **src_data; 
register unsigned long len, i; 
unsigned long nr, 
       nc; 

src_data = src->UByteData; // 2d array 
m_data  = mean->FloatData; // 2d array 
o_data  = dest->FloatData; // 2d array 
nr   = src->Rows; 
nc   = src->Cols; 

__m128i xmm0; 

for(i=0; i<nr; i++) 
{ 
    m = m_data[i]; 
    o = o_data[i]; 
    p = src_data[i]; 
    len = nc; 
    do 
    { 
     _mm_prefetch((const char *)(p + 16), _MM_HINT_NTA); 
     _mm_prefetch((const char *)(m + 16), _MM_HINT_NTA); 

     xmm0 = _mm_load_si128((__m128i *) (p)); 

     _mm_stream_ps(
         o, 
         _mm_sub_ps(
            _mm_cvtepi32_ps(_mm_cvtepu8_epi32(_mm_srli_si128(xmm0, 0))), 
            _mm_load_ps(m + offset) 
           ) 
        ); 
     _mm_stream_ps(
         o + 4, 
         _mm_sub_ps(
            _mm_cvtepi32_ps(_mm_cvtepu8_epi32(_mm_srli_si128(xmm0, 4))), 
            _mm_load_ps(m + offset + 4) 
           ) 
        ); 
     _mm_stream_ps(
         o + 8, 
         _mm_sub_ps(
            _mm_cvtepi32_ps(_mm_cvtepu8_epi32(_mm_srli_si128(xmm0, 8))), 
            _mm_load_ps(m + offset + 8) 
           ) 
        ); 
     _mm_stream_ps(
         o + 12, 
         _mm_sub_ps(
            _mm_cvtepi32_ps(_mm_cvtepu8_epi32(_mm_srli_si128(xmm0, 12))), 
            _mm_load_ps(m + offset + 12) 
           ) 
        ); 

     p += 16; 
     m += 16; 
     o += 16; 
     len -= 16; 
    } 
    while(len); 
} 
+1

Je ne serais pas surpris si IPP avait déjà une fonction pour cela. –

+2

Si vous utilisez le compilateur Intel, pourquoi ne pas simplement écrire une version naïve de la fonction et voir si le compilateur peut la vectoriser elle-même? Je ne connais pas le CCG à cet égard. –

Répondre

1

Vous faites presque aucun calcul ici, par rapport au nombre de charges et les magasins, il est donc probable que vous êtes limité par la bande passante de la mémoire plutôt que le calcul. Cela expliquerait pourquoi vous ne constatez aucune amélioration du débit lorsque vous optimisez le calcul.

Je me débarrasser des instructions _mm_prefetch bien - ils sont presque certainement pas aider ici et peut même être mal aux performances.

Si possible, vous devez combiner cette boucle toute autre opération que vous faites avant/après - de cette façon vous amortir le coût de la mémoire d'E/S sur plus de calcul.

+0

pourquoi _mm_prefetch n'est pas utile dans ce cas? – prgbenz

+2

@prgbenz: _mm_prefetch doit émettre quelques centaines de cycles d'horloge avant tout défaut de cache potentiel, et aide uniquement si vous avez une bande passante libre - le mettre immédiatement avant les charges pertinentes ne va pas aider, et peut même l'impact sur toute préextraction automatique que la CPU peut déjà faire. En plus de cela, il gaspille des cycles dans ce qui est déjà une boucle assez courte. –