Newsgroup: it.comp.lang.c
Titolo: [CROSS] Performance codice X ESPERTI

Ho scritto un codice ottimizzato in sse ma non ho nessun incremento di 
prestazioni anzi ho un rallentamento! Possibile?
Il codice è una semplice rotazione di un vettore tramite matrice!Il 
codice originale è questo:
    for (float j=0; j<COUNTER1; j++)
    for (float i=0; i<COUNTER2; i++)
        {
        	out.X = in.X*M[0] + in.Y*M[4] + in.Z*M[8] + M[12];
		out.Y = in.X*M[1] + in.Y*M[5] + in.Z*M[9] + M[13];
		out.Z = in.X*M[2] + in.Y*M[6] + in.Z*M[10] + M[14];
        	in = out;
        }   
Tempo di esecuzione 5.35s!
Ho riscritto il codice ottimizzato:
    for (float j=0; j<COUNTER1; j++)
    for (float i=0; i<COUNTER2; i++)
            {
#ifdef __SSE__
            sse4 outf;
            __m128 Vin,out1;
            Vin = _mm_set1_ps ((float)TestVectorA.X);
            out1 =_mm_mul_ps(*((__m128*) &M[0]),Vin);  
            outf.m =_mm_add_ps(out1,*((__m128*) &M[12]));  
            Vin = _mm_set1_ps ((float)TestVectorA.Y);
            out1 =_mm_mul_ps(*((__m128*) &M[4]),Vin);  
            outf.m =_mm_add_ps(out1,outf.m);  
            Vin = _mm_set1_ps ((float)TestVectorA.Z);
            out1 =_mm_mul_ps(*((__m128*) &M[8]),Vin);  
            outf.m =_mm_add_ps(out1,outf.m);  
            TestVectorA.X=outf.f[0];            
            TestVectorA.Y=outf.f[1];
            TestVectorA.Z=outf.f[2];            
#endif
    }
Tempo di esecuzione 7.81s
Compilatore MinGW 3.4.X con sse attivo e -O2, processore athlon XP 2.8 !
Ho guardato anche l'assemblato e il nuovo codice e sono meno righe di 
codice! Perchè va più lento !
	109	    for (float i=0; i<COUNTER2; i++)
-	0x401a90	<main+2048>:		fldz   
-	0x401a92	<main+2050>:		lea    0x0(%esi),%esi
-	0x401a99	<main+2057>:		lea    0x0(%edi),%edi
-	0x401aa0	<main+2064>:		movss  %xmm7,0xfffffe04(%ebp)
-	0x401aa8	<main+2072>:		mov    0xffffff18(%ebp),%eax
-	0x401aae	<main+2078>:		movaps %xmm6,%xmm1
-	0x401ab1	<main+2081>:		movaps %xmm4,%xmm2
-	0x401ab4	<main+2084>:		fld1   
-	0x401ab6	<main+2086>:		faddp  %st,%st(1)
-	0x401ab8	<main+2088>:		mov    %eax,0xfffffe84(%ebp)
-	0x401abe	<main+2094>:		mov    0xffffff1c(%ebp),%eax
-	0x401ac4	<main+2100>:		movss  0xfffffe84(%ebp),%xmm0
-	0x401acc	<main+2108>:		flds   0xfffffe04(%ebp)
-	0x401ad2	<main+2114>:		mov    %eax,0xfffffe80(%ebp)
-	0x401ad8	<main+2120>:		mov    0xffffff20(%ebp),%eax
-	0x401ade	<main+2126>:		shufps $0x0,%xmm0,%xmm0
-	0x401ae2	<main+2130>:		mulps  %xmm0,%xmm1
-	0x401ae5	<main+2133>:		movss  0xfffffe80(%ebp),%xmm0
-	0x401aed	<main+2141>:		addps  %xmm5,%xmm1
-	0x401af0	<main+2144>:		mov    %eax,0xfffffe7c(%ebp)
-	0x401af6	<main+2150>:		fucomip %st(1),%st
-	0x401af8	<main+2152>:		shufps $0x0,%xmm0,%xmm0
-	0x401afc	<main+2156>:		mulps  %xmm0,%xmm2
-	0x401aff	<main+2159>:		addps  %xmm1,%xmm2
-	0x401b02	<main+2162>:		movaps %xmm3,%xmm1
-	0x401b05	<main+2165>:		movss  0xfffffe7c(%ebp),%xmm0
-	0x401b0d	<main+2173>:		shufps $0x0,%xmm0,%xmm0
-	0x401b11	<main+2177>:		mulps  %xmm0,%xmm1
-	0x401b14	<main+2180>:		movaps %xmm1,%xmm0
-	0x401b17	<main+2183>:		addps  %xmm2,%xmm0
-	0x401b1a	<main+2186>:		movaps %xmm0,0xfffffe88(%ebp)
-	0x401b45	<main+2229>:		ja     0x401aa0 <main+2064>
-	0x401b4b	<main+2235>:		fstp   %st(0)
	110	            {
	111	#ifdef __SSE__
	112	            sse4 outf;
	113	            __m128 Vin,out1;
	114	
	115	            Vin = _mm_set1_ps ((float)TestVectorA.X);
	116	            out1 =_mm_mul_ps(*((__m128*) &M[0]),Vin);  
	117	            outf.m =_mm_add_ps(out1,*((__m128*) &M[12]));  
	118	
	119	            Vin = _mm_set1_ps ((float)TestVectorA.Y);
	120	            out1 =_mm_mul_ps(*((__m128*) &M[4]),Vin);  
	121	            outf.m =_mm_add_ps(out1,outf.m);  
	122	
	123	            Vin = _mm_set1_ps ((float)TestVectorA.Z);
	124	            out1 =_mm_mul_ps(*((__m128*) &M[8]),Vin);  
	125	            outf.m =_mm_add_ps(out1,outf.m);  
	126	
	127	            TestVectorA.X=outf.f[0];            
-	0x401b21	<main+2193>:		mov    0xfffffe88(%ebp),%eax
-	0x401b27	<main+2199>:		mov    %eax,0xffffff18(%ebp)
	128	            TestVectorA.Y=outf.f[1];
-	0x401b2d	<main+2205>:		mov    0xfffffe8c(%ebp),%eax
-	0x401b33	<main+2211>:		mov    %eax,0xffffff1c(%ebp)
	129	            TestVectorA.Z=outf.f[2];            
-	0x401b39	<main+2217>:		mov    0xfffffe90(%ebp),%eax
-	0x401b3f	<main+2223>:		mov    %eax,0xffffff20(%ebp)
	130	#endif
	131	    }
	132	        
	133	
contro quello non ottimizzato
	91	    for (float i=0; i<COUNTER2; i++)
-	0x4018f6	<main+1638>:		fldz   
-	0x4018f8	<main+1640>:		jmp    0x401908 <main+1656>
-	0x4018fa	<main+1642>:		lea    0x0(%esi),%esi
-	0x401900	<main+1648>:		fstp   %st(0)
-	0x401902	<main+1650>:		fstp   %st(1)
-	0x401904	<main+1652>:		fstp   %st(1)
-	0x401906	<main+1654>:		fstp   %st(1)
-	0x40192c	<main+1692>:		movss  %xmm7,0xfffffe04(%ebp)
-	0x401994	<main+1796>:		fld1   
-	0x401996	<main+1798>:		fxch   %st(4)
-	0x40199a	<main+1802>:		flds   0xfffffe04(%ebp)
-	0x4019a0	<main+1808>:		fxch   %st(6)
-	0x4019a2	<main+1810>:		fadd   %st(4),%st
-	0x4019a4	<main+1812>:		fxch   %st(2)
-	0x4019b2	<main+1826>:		fucomip %st(1),%st
-	0x4019b4	<main+1828>:		fxch   %st(1)
-	0x4019c8	<main+1848>:		ja     0x401900 <main+1648>
-	0x4019ce	<main+1854>:		fstp   %st(1)
-	0x4019d0	<main+1856>:		fxch   %st(1)
	92	        {
	93	
	94	        out.X = in.X*M[0] + in.Y*M[4] + in.Z*M[8] + M[12];
-	0x401908	<main+1656>:		flds   0xfffffef8(%ebp)
-	0x40190e	<main+1662>:		flds   0xfffffefc(%ebp)
-	0x401914	<main+1668>:		flds   0xfffffe3c(%ebp)
-	0x40191a	<main+1674>:		flds   0xfffffe30(%ebp)
-	0x401920	<main+1680>:		flds   0xffffff00(%ebp)
-	0x401926	<main+1686>:		fxch   %st(2)
-	0x401928	<main+1688>:		fmul   %st(4),%st
-	0x40192a	<main+1690>:		fxch   %st(1)
-	0x401934	<main+1700>:		fmul   %st(3),%st
-	0x40193e	<main+1710>:		faddp  %st,%st(1)
-	0x401940	<main+1712>:		fxch   %st(1)
-	0x401944	<main+1716>:		flds   0xfffffe50(%ebp)
-	0x40194a	<main+1722>:		fxch   %st(5)
-	0x401954	<main+1732>:		fmul   %st(3),%st
-	0x401956	<main+1734>:		faddp  %st,%st(2)
-	0x401960	<main+1744>:		fadds  0xfffffe44(%ebp)
-	0x401966	<main+1750>:		fxch   %st(2)
	95			out.Y = in.X*M[1] + in.Y*M[5] + in.Z*M[9] + M
[13];
-	0x401936	<main+1702>:		flds   0xfffffe38(%ebp)
-	0x40193c	<main+1708>:		fxch   %st(2)
-	0x401942	<main+1714>:		fmul   %st(4),%st
-	0x401958	<main+1736>:		flds   0xfffffe58(%ebp)
-	0x40195e	<main+1742>:		fxch   %st(2)
-	0x401968	<main+1752>:		fmul   %st(4),%st
-	0x40196a	<main+1754>:		fxch   %st(4)
-	0x40197c	<main+1772>:		faddp  %st,%st(4)
-	0x40197e	<main+1774>:		flds   0xfffffe4c(%ebp)
-	0x401984	<main+1780>:		fxch   %st(5)
-	0x40198a	<main+1786>:		fmul   %st(2),%st
-	0x40198c	<main+1788>:		fxch   %st(2)
-	0x401998	<main+1800>:		faddp  %st,%st(3)
-	0x4019aa	<main+1818>:		fadds  0xfffffe40(%ebp)
-	0x4019b0	<main+1824>:		fxch   %st(5)
	96			out.Z = in.X*M[2] + in.Y*M[6] + in.Z*M[10] + 
M[14];
-	0x40194c	<main+1724>:		fmuls  0xfffffe34(%ebp)
-	0x401952	<main+1730>:		fxch   %st(5)
-	0x40196c	<main+1756>:		fmuls  0xfffffe54(%ebp)
-	0x401972	<main+1762>:		fxch   %st(2)
-	0x401974	<main+1764>:		fsts   0xfffffef8(%ebp)
-	0x40197a	<main+1770>:		fxch   %st(1)
-	0x401986	<main+1782>:		faddp  %st,%st(2)
-	0x401988	<main+1784>:		fxch   %st(4)
-	0x40198e	<main+1790>:		fmuls  0xfffffe48(%ebp)
-	0x4019a6	<main+1814>:		faddp  %st,%st(1)
-	0x4019a8	<main+1816>:		fxch   %st(2)
-	0x4019b6	<main+1830>:		fadd   %st(5),%st
-	0x4019b8	<main+1832>:		fxch   %st(4)
-	0x4019ba	<main+1834>:		fsts   0xfffffefc(%ebp)
-	0x4019c0	<main+1840>:		fxch   %st(4)
-	0x4019c2	<main+1842>:		fsts   0xffffff00(%ebp)
	97	        in = out;
	98	
	99	        }   
Qualcuno sa cosa sta succedendo?
Grazie
	SAX
Allego il codice completo:
#include <stdlib.h>
#include <stdio.h>
#include <time.h>
#include <irrlicht.h>
#ifdef __SSE__
        #include <xmmintrin.h>
#endif
#define COUNTER1 500
#define COUNTER2 500000
#ifdef __SSE__
union sse4{
           __m128 m;
           float f[4];
};
#endif
using namespace irr;
using namespace core;
#pragma comment(lib, "Irrlicht.lib")
int main()
{
  matrix4 TestMatrix;
    matrix4 TestMatrixA;
    matrix4 TestMatrixB;
    vector3df TestVectorA;
    vector3df TestVectorB;
    int start, stop;
    TestMatrixA.setInverseRotationRadians(vector3df(30,60,75));
 
    float M[16];
    M[0]= TestMatrixA(0,0);
    M[1]= TestMatrixA(0,1);
    M[2]= TestMatrixA(0,2);	
    M[3]= TestMatrixA(0,3);
    M[4]= TestMatrixA(1,0);
    M[5]= TestMatrixA(1,1);
    M[6]= TestMatrixA(1,2);	
    M[7]= TestMatrixA(1,3);
 
    M[8]= TestMatrixA(2,0);
    M[9]= TestMatrixA(2,1);
    M[10]= TestMatrixA(2,2);	
    M[11]= TestMatrixA(2,3);
 
    M[12]= TestMatrixA(3,0);
    M[13]= TestMatrixA(3,1);
    M[14]= TestMatrixA(3,2);	
    M[15]= TestMatrixA(3,3);    
    printf("Matrix\n");
    printf("%f %f %f %f\n",M[0],M[1],M[2],M[3]);
    printf("%f %f %f %f\n",M[4],M[5],M[6],M[7]);
    printf("%f %f %f %f\n",M[8],M[9],M[10],M[11]);
    printf("%f %f %f %f\n\n",M[12],M[13],M[14],M[15]);                        
    TestVectorA=  vector3df (20, 40,-5);
    printf("Vector (A) %f %f %f\n
\n",TestVectorA.X,TestVectorA.Y,TestVectorA.Z);
    printf("Clock per Sec %d\n\n",CLK_TCK );
    time(NULL);
    clock_t StartClock = clock ();
    printf("Start Test\n");
 
    vector3df in ,out;
    in = TestVectorA;
    for (float j=0; j<COUNTER1; j++)
    for (float i=0; i<COUNTER2; i++)
        {
        in = out;
        }   
    clock_t StopClock = clock ();
    printf("Differenza[0] Only For\t\t%f s\n",((float)StopClock - 
StartClock)/CLK_TCK);
 
     StartClock = clock ();
    printf("Start Test\n");
 
    in = TestVectorA;
    for (float j=0; j<COUNTER1; j++)
    for (float i=0; i<COUNTER2; i++)
        {
        out.X = in.X*M[0] + in.Y*M[4] + in.Z*M[8] + M[12];
		out.Y = in.X*M[1] + in.Y*M[5] + in.Z*M[9] + M[13];
		out.Z = in.X*M[2] + in.Y*M[6] + in.Z*M[10] + M[14];
        in = out;
        }   
     StopClock = clock ();
    printf("Differenza[A]\t\t%f s\n",((float)StopClock - 
StartClock)/CLK_TCK);
    printf("Start SSE Test\n");    
     StartClock = clock ();    
    for (float j=0; j<COUNTER1; j++)
    for (float i=0; i<COUNTER2; i++)
            {
#ifdef __SSE__
            sse4 outf;
            __m128 Vin,out1;
            Vin = _mm_set1_ps ((float)TestVectorA.X);
            out1 =_mm_mul_ps(*((__m128*) &M[0]),Vin);  
            outf.m =_mm_add_ps(out1,*((__m128*) &M[12]));  
            Vin = _mm_set1_ps ((float)TestVectorA.Y);
            out1 =_mm_mul_ps(*((__m128*) &M[4]),Vin);  
            outf.m =_mm_add_ps(out1,outf.m);  
            Vin = _mm_set1_ps ((float)TestVectorA.Z);
            out1 =_mm_mul_ps(*((__m128*) &M[8]),Vin);  
            outf.m =_mm_add_ps(out1,outf.m);  
            TestVectorA.X=outf.f[0];            
            TestVectorA.Y=outf.f[1];
            TestVectorA.Z=outf.f[2];            
#endif
    }
 
     StopClock = clock ();
    printf("Differenza[B] SSE \t\t%f s\n",((float)StopClock - 
StartClock)/CLK_TCK);
    system("PAUSE");
	return 0;
}

codice! Perchč va piů lento !

Di per sé la lunghezza del codice assembler non vuol dire molto.
Hai provato a fare un paragone tra i seguenti frammenti ?
    for (float j=0; j<COUNTER1; j++)
    for (float i=0; i<COUNTER2; i++)
        {
        in = out;
        }
e
    for (float j=0; j<COUNTER1; j++)
    for (float i=0; i<COUNTER2; i++)
            {
#ifdef __SSE__
            sse4 outf;
            __m128 Vin,out1;
            TestVectorA.X=outf.f[0];
            TestVectorA.Y=outf.f[1];
            TestVectorA.Z=outf.f[2];
#endif
     }
sarebbe interessante !
E' anche ineressante vedere quanto costa un cast del tipo
(float)TestVectorA.X
Prova a fare un ulteriore test come questo:
    for (float j=0; j<COUNTER1; j++)
    for (float i=0; i<COUNTER2; i++)
            {
#ifdef __SSE__
            sse4 outf;
            __m128 Vin,out1;
            volatile float x,y,z;
            x = (float)TestVectorA.X;
            y = (float)TestVectorA.Y;
            z = (float)TestVectorA.Z;
#endif
     }
Prova a vedere se con i tempi ottieni qualche indicazione in piů.
--
Giorgio Silvestri
DSP/Embedded/Real Time OS   Software Engineer

 Ho riscritto il codice ottimizzato:
Ottimizzato per te :) Il tuo PC non la pensa allo stesso modo!
Esistono vari manuali di Intel e AMD sull'ottimizzazione in generale e 
sull'uso delle istruzioni MMX/SSE/SSE2/... Non ti resta che studiarteli.
Comunque qui sei OT.
Kiuhnm

 sull'uso delle istruzioni MMX/SSE/SSE2/... Non ti resta che studiarteli.
Scusatemi tanto non pensavo di essere OT

 >codice originale è questo:


, 
no...@none.it
 
says...


 Non ti resta che studiarteli.
Non ti resta che *studiarli*.
Kiuhnm


modifica sse4:
#ifdef __SSE__
union sse4{
           __m128 m;
           float f[4];
           vector3df  vect3d; /* non piů di 3 float ? */
};
#endif
vector3df  *p;
/* fai questo una volta sola, porta tutte le variabili fuori dal ciclo */
p = &outf.vect3d;
potresti poi fare un assegnamento come questo:
TestVectorA = outf.vect3d;
o anche (prova il piů veloce):
TestVectorA = *p;
invece di
TestVectorA.X=outf.f[0];
TestVectorA.Y=outf.f[1];
TestVectorA.Z=outf.f[2];
Controlla che il tipo vector3df possa andare bene
per questa variante (3 float consecutivi ...).
Eventualmente crea un nuovo tipo piů adatto per
fare poi l'assegnamento.


SAX ha scritto:

Non c'e' problema, adesso lo sai ;-)
E' comunque buona norma leggere il MANIFESTO di un newsgroup prima di 
postare, in modo da sapere di quale/i argomento/i si puo' discutere su 
di esso.
Buona fortuna per l'ottimizzazione.
-- 
Roal Zanazzi

         }   
scusa, a parte l'OT che ti hanno segnalato, mi sfugge l'ottica 
di questi tuoi due cicli annidati.
A parte l'uso di contatori float (peggio persino dei double) che 
pure esso ti hanno già segnalato, quello che non capisco è : 
DOVE vengono usati nel blocco da ripetere i due contatori ?
A me pare che scrivi sempre i medesimi elementi di IN e OUT (la 
cui tipologia di dati non ho capito dal contesto.
Forse in e out hanno iteratori automatici ?
A parte tutto il resto, se vuoi davvero ottimizzare le cose, 
cerca di capire qual'è il tipo di dato nativo floating point del 
processore per il quale compili.
Per la libreria software standard (C math-h), il codice era 
ottimizzato per i double. Ogni altro dato comporta almeno una 
coppia di conversioni in più.
Per alcuni vecchi coprocessori matematici, lo stack interno era 
a 80 bit (long double a 10 byte).
In tal caso, dovresti scrivere l'asm a mano (giusto quello 
interno al blocco, magari dopo avere caricato alcuni registri 
non espressamente usati dal compilatore, meglio se garantiti 
come non usati, tipo ESI, EDI, boh, e caricarci gli indirizzi di 
memoria degli elementi correnti di in e out, è facile distrarsi 
e fare cavolate, naturalmente)
altra buona cosa, visto che hai il disassemblato, da un occhio 
al manuale del tuo processore e guarda i cicli di clock delle 
varie istruzioni floating-point, magari viene fuori che ti sei 
stupito per niente.
CUT all

 A me pare che scrivi sempre i medesimi elementi di IN e OUT
Ogni ciclo sono diversi invece!!!
Vedi il mio commento sopra.


ciao a tutti.
dove posso reperire delle convenzioni usate per scrivere codice in C++
(ad esempio i nomi delle classi iniziano in maiuscolo, tutti in maiuscolo
i #define, le corrette spaziature tra esempio "int* ptr", se č meglio
dichiarare tutte le variabili all'inizio oppure no ecc...). Delle regole di
stile di scrittura in pratica con consigli di come usare i nomi delle
variabili. Ad esempio non ho capito se quando si dichiara una funzione
e quando la si definisce, conviene usare gli stessi nomi delle variabili
usate al momento del richiamo della funzione o conviene cambiarli.
ad esempio:
void write(char text[]);
main {
....
write(text);
....}
void write(char text[]) {
....}
oppure č meglio
void write(char tx[]);
main {
....
write(text);
....}
void write(char[tx]) {
... }
C'e' qualcosa in rete (non penso serva 1 libro intero per spiegarle).
Avevo sentito parlare di uno standard ungherese o qualcosa del
genere ma non vorrei dire una stupidata.
ciao