Twitter iPhone pliant OnePlus 11 PS5 Disney+ Orange Livebox Windows 11

accélération SSE en langage C++

1 réponse
Avatar
tmblues
Bonjour,

ayant écrit un programme qui requiert des calculs sur de grosses matrices (512*512 bytes), j'ai voulu optimiser mon calcul avec les fonctions SSE fournit par msdn (#include <emmintrin.h>). J'ai donc programmer une fonction permettant de faire des combinaisons entre les lignes de la matrice en travaillant 16 bytes par 16 bytes. La fonction fonctionne pour des matrices de taille strictement inférieure à 128*128 (la taille devant être un multiple de 16 c'est-à-dire 16*16, 32*32, 48*48, 64*64, 80*80, 96*96, 112*112). Dès que l'on dépasse 128 bytes, la fonction se comporte n'importe comment et affiche des valeurs fausses.

Y aurait-il un rapport avec la mémoire (lors de l'exécution aucune erreur mémoire ne s'affiche ).
voici le code de la fonction :

void CDecoder::linearCombination(char* row1, char* row2, char factor, char rowSize, char* result)
{
int nLoop = rowSize/16;

__m128i* pResult = (__m128i*) result;
__m128i* pRow1 = (__m128i*) row1;
__m128i* pRow2 = (__m128i*) row2;
__m128i row1cp;
__m128i resultcp;

__m128i un = _mm_set1_epi8(1);
__m128i zero = _mm_setzero_si128();
__m128i compare;
__m128i overflowing;
__m128i over = _mm_set1_epi8((char) 0x80);
__m128i poly = _mm_set1_epi8((char) 0x1D);
__m128i m1;
__m128i m2;

for(int i = 0; i<nLoop; i++)
{
__m128i mfactor = _mm_set1_epi8(factor);
row1cp = _mm_loadu_si128(pRow1);
resultcp = zero;

while(_mm_movemask_epi8(_mm_cmpeq_epi8(zero, row1cp)) != 65535)
{
compare = _mm_cmpeq_epi8(_mm_and_si128(un, row1cp), un);
m1 = _mm_and_si128(compare, mfactor);
resultcp = _mm_xor_si128(resultcp, m1);
overflowing = _mm_cmpeq_epi8(_mm_and_si128(mfactor, over), over);
mfactor = _mm_andnot_si128(un,_mm_slli_epi32(mfactor, 1));
m2 = _mm_and_si128(overflowing, poly);
mfactor = _mm_xor_si128(m2, mfactor);
row1cp = _mm_andnot_si128(over,_mm_srli_epi32(row1cp, 1));
}
*pResult = _mm_xor_si128(resultcp, *pRow2); //addition


pRow1++;
pRow2++;
pResult++;
}
}

merci d'avance

1 réponse

Avatar
PEM
On May 5, 7:29 am, tmblues wrote:
Bonjour,

ayant écrit un programme qui requiert des calculs sur de grosses matric es
(512*512 bytes), j'ai voulu optimiser mon calcul avec les fonctions SSE f ournit
par msdn (#include <emmintrin.h>). J'ai donc programmer une fonction perm ettant
de faire des combinaisons entre les lignes de la matrice en travaillant 1 6 bytes
par 16 bytes. La fonction fonctionne pour des matrices de taille strictem ent
inférieure à 128*128 (la taille devant être un multiple de 16 c'est -à-dire
16*16, 32*32, 48*48, 64*64, 80*80, 96*96, 112*112). Dès que l'on dépa sse 128
bytes, la fonction se comporte n'importe comment et affiche des valeurs f ausses.

Y aurait-il un rapport avec la mémoire (lors de l'exécution aucune er reur
mémoire ne s'affiche ).
voici le code de la fonction :

void CDecoder::linearCombination(char* row1, char* row2, char factor, cha r
rowSize, char* result)
{
        int nLoop = rowSize/16;

        __m128i* pResult = (__m128i*) result;
        __m128i* pRow1 = (__m128i*) row1;
        __m128i* pRow2 = (__m128i*) row2;
        __m128i row1cp;
        __m128i resultcp;

        __m128i un = _mm_set1_epi8(1);
        __m128i zero = _mm_setzero_si128();
        __m128i compare;        
        __m128i overflowing;
        __m128i over = _mm_set1_epi8((char) 0x80);
        __m128i poly = _mm_set1_epi8((char) 0x1D);
        __m128i m1;
        __m128i m2;

        for(int i = 0; i<nLoop; i++)
        {
                __m128i mfactor = _mm_set1_epi8(factor) ;
                row1cp = _mm_loadu_si128(pRow1);
                resultcp = zero;

                while(_mm_movemask_epi8(_mm_cmpeq_epi8(ze ro, row1cp)) != 65535)
                {
                        compare = _mm_cmpeq_epi 8(_mm_and_si128(un, row1cp), un);                
                        m1 = _mm_and_si128(comp are, mfactor);            
                        resultcp = _mm_xor_si12 8(resultcp, m1);
                        overflowing = _mm_cmpeq _epi8(_mm_and_si128(mfactor, over), over);
                        mfactor = _mm_andnot_si 128(un,_mm_slli_epi32(mfactor, 1));  
                        m2 = _mm_and_si128(over flowing, poly);                                  
                        mfactor = _mm_xor_si128 (m2, mfactor);                                          
                        row1cp = _mm_andnot_si1 28(over,_mm_srli_epi32(row1cp, 1));
                }
                *pResult = _mm_xor_si128(resultcp, *pRo w2);    //addition

                pRow1++;
                pRow2++;
                pResult++;
        }

}

merci d'avance



Jettes un oeil à Eigen2 (http://eigen.tuxfamily.org). Il me semble que
cette bibliothèque traite déjà ce problème avec brio : automatisati on
du SSE en fonction des règles de compilation. Dans le pire des cas, tu
auras une modélisation matricielle en métaprogrammation sur laquelle
tu pourras t'appuyer.