Instruction optimale ? [Résolu]

Messages postés
968
Date d'inscription
samedi 3 avril 2004
Statut
Membre
Dernière intervention
4 mars 2010
- - Dernière réponse : cs_juju12
Messages postés
968
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.
Afficher la suite 

3 réponses

Meilleure réponse
Messages postés
141
Date d'inscription
mercredi 19 juillet 2006
Statut
Membre
Dernière intervention
20 avril 2011
3
Merci
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 ...

Dire « Merci » 3

Quelques mots de remerciements seront grandement appréciés. Ajouter un commentaire

Codes Sources 128 internautes nous ont dit merci ce mois-ci

Commenter la réponse de _dune2_
Messages postés
552
Date d'inscription
jeudi 28 novembre 2002
Statut
Membre
Dernière intervention
26 mars 2016
1
0
Merci
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
Commenter la réponse de ToutEnMasm
Messages postés
968
Date d'inscription
samedi 3 avril 2004
Statut
Membre
Dernière intervention
4 mars 2010
4
0
Merci
Merci pour ces réponses
Commenter la réponse de cs_juju12