Instruction optimale ?

Résolu
cs_juju12 Messages postés 966 Date d'inscription samedi 3 avril 2004 Statut Membre Dernière intervention 4 mars 2010 - 12 sept. 2006 à 15:57
cs_juju12 Messages postés 966 Date d'inscription samedi 3 avril 2004 Statut Membre Dernière intervention 4 mars 2010 - 12 sept. 2006 à 17:53
Bonjour;
   Je code un bout d'asm inline sous C++ en utilisant les instructions SSE et des données alignées sur 16 octets.
J'aurais voulu savoir, des deux opérations suivantes, laquelle est la plus rapide, ou si elles sont équivalentes :
MOVDQA xmm1, xmmword ptr[eax];
ADDPS xmm1, xmmword ptr[ebx];
ou bien :
MOVDQA xmm1, xmmword ptr[eax];
MOVDQA xmm2, xmmword ptr[ebx];
ADDPS xmm1, xmm2; 
merci d'avance.

3 réponses

_dune2_ Messages postés 141 Date d'inscription mercredi 19 juillet 2006 Statut Membre Dernière intervention 20 avril 2011
12 sept. 2006 à 17:44
Salut,


Tout comme ToutEnMasm, je conseille le test pour ce genre question.

J'ai réalisé un prog en C avec asm inline :


=========================================

#include <stdio.h>

#include <stdlib.h>


unsigned int timing_test1[1024];

unsigned int timing_test2[1024];


void *ptr1, *ptr2;

char _ptr1[16+16];

char _ptr2[16+16];


inline void test1()

{

    __asm(

        "mov    (%0),%%ebx    \n"

        "mov    (%1),%%ecx    \n"

        "movdqa    (%%ebx),%%xmm1    \n"

        "addps    (%%ecx),%%xmm1    \n"

        :: "m" (ptr1) , "m" (ptr2)

        : "ebx", "ecx");

}


inline void test2()

{

    __asm(

        "mov    (%0),%%ebx    \n"

        "mov    (%1),%%ecx    \n"

        "movdqa    (%%ebx),%%xmm1    \n"

        "movdqa    (%%ecx),%%xmm2    \n"

        "addps    %%xmm2,%%xmm1    \n"

        :: "m" (ptr1) , "m" (ptr2)

        : "ebx", "ecx");

}


int main(int argc, char **argv)

{

    int loop;

   

    ptr1 = (void *)((unsigned long)(_ptr1+15)&(~0x0F));

    ptr2 = (void *)((unsigned long)(_ptr2+15)&(~0x0F));

   

    unsigned int result_test1=0, result_test2=0;

    unsigned int debut,fin;

    // boucles de test ...

    __asm__ volatile ("rdtsc":"=A" (debut));

    for(loop=0;loop<4096;loop++) test1();

    __asm__ volatile ("rdtsc":"=A" (fin));

    result_test1 = ((debut<fin)?(fin-debut):(debut-fin))/4096;

   

    __asm__ volatile ("rdtsc":"=A" (debut));

    for(loop=0;loop<4096;loop++) test2();

    __asm__ volatile ("rdtsc":"=A" (fin));

    result_test2 = ((debut<fin)?(fin-debut):(debut-fin))/4096;

    // affichage du résultat ...

    printf("Test1 : %u cycles d'horloge et Test2 : %d cycles d'horloge\n",result_test1,result_test2);

    return EXIT_SUCCESS;

}

=========================================


Et le résultat chez moi me donne :

Test1 : 34 cycles d'horloge et Test2 : 32 cycles d'horloge


de manière répétitif.


On peut donc déduire que utiliser 2x movdqa + 1x addps est plus rapide.


Celà est surement dû au fait que les 2 méthodes ont une contrainte sur
les 2 opérandes (que ce soit sur xmm2 ou sur le chargement des
128bits). Mais movdqa est à priori mieux géré en terme de cycles cpu
que addps pour le chargement des données alignées sur 128bits.

Addps doit gaspiller de precieux cycles cpu en considérant le chargement pas forcément aligné.


Dune2.

Gentoo... que du bonheur ...
3
ToutEnMasm Messages postés 587 Date d'inscription jeudi 28 novembre 2002 Statut Membre Dernière intervention 13 décembre 2022 3
12 sept. 2006 à 16:21
Salut,
Pour ça il faut utiliser un compteur.

                          ToutEnMasm


.586


;------------------- constantes ---------------------------


ITER EQU 1 ; number of iterations


OVERHEAD EQU 15 ; 15 for PPlain, 17 for PMMX


;************ Data segment: ********************


ALIGN 4


COUNTER DD 0 ; loop counter


TICS DD 0 ; temporary storage of clock


RESULTLIST DD ITER DUP (0) ; list of test results





;---------------------- code -----------------------------------


;calcul du temps


BEGIN:


MOV DWORD ptr COUNTER,0 ; reset loop counter


TESTLOOP: ; test loop


;************ Do any initializations here: ********************


FINIT


;************ End of initializations ********************


RDTSC ; read clock counter


MOV TICS,EAX ; save count


CLD ; non-pairable filler


REPEAT 8


NOP ; eight NOP's to avoid shadowing effect


ENDM


;---------------- bloc d'instruction ------------------------


 


;---------- resultat --------------------------


CLC ; non-pairable filler with shadow


RDTSC ; read counter again


SUB EAX,TICS ; compute difference


SUB EAX,OVERHEAD ;15 subtract clocks used by fillers etc.


MOV EDX,COUNTER ; loop counter


MOV [RESULTLIST+EDX],EAX ; store result in table


ADD EDX,TYPE RESULTLIST ; increment counter


MOV COUNTER,EDX ; store counter


CMP EDX,ITER * (TYPE RESULTLIST)


JB @F ; repeat ITER times


jmp AfficheITER


@@:


jmp TESTLOOP





;affichage


AfficheITER:


mov CPT,ITER


mov ebx,0


mov al,0


mov byte ptr [ZoneMessagesErreurs],al





.while(CPT)


mov edx,[RESULTLIST+ebx*4]


invoke dwtoa,edx,addr buffer


invoke lstrcat,addr ZoneMessagesErreurs,addr buffer


invoke lstrcat,addr ZoneMessagesErreurs,SADR(" ")


inc ebx


dec CPT


.endw


invoke MessageBox,NULL,addr ZoneMessagesErreurs,addr buffer,MB_OK
0
cs_juju12 Messages postés 966 Date d'inscription samedi 3 avril 2004 Statut Membre Dernière intervention 4 mars 2010 4
12 sept. 2006 à 17:53
Merci pour ces réponses
0
Rejoignez-nous