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;
}

 
Si', succede che potresti avere risposte piu' esaurienti su un newsgroup 
piu' consono al tuo problema.
Senza offesa.
-- 
Roal Zanazzi

 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

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

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.
--
Giorgio Silvestri
DSP/Embedded/Real Time OS   Software Engineer

 Vedi il mio commento sopra.
ciò malgrado, ne so quanto prima su quello
mah
Soviet-Perplesso


 Che diavolo sono in e out ? che tipo hanno, che metodi hanno ?
Dal post originale sembrano (tipo: vector3df) dei vettori 3D di float.
Come detto in assenza di ulteriori informazioni questo
sembra ampiamente sufficiente per risolvere il problema dell'OP
senza bisogno di altro, vedi it.comp.lang.c.
Meno perplesso ? :-)


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

 
Se cerchi su Google troverai un bel po' di pagine sulle convenzioni di 
scrittura del codice, ma ti consiglio di non accettarle passivamente 
come regole. Se una indicazione non ti convince ragiona sulla sua 
utilita' o chiedi a qualcuno piu' esperto di te (magari su questo NG).
N.B. molte "indicazioni" sono assurde e non portano alcun beneficio se 
seguite.
 > Avevo sentito parlare di uno standard ungherese o qualcosa del
 > genere ma non vorrei dire una stupidata.
 >
Gia'... la "notazione ungherese" a cui mi riferivo piu' sopra.
Lasciala perdere, e' una gran ca... ehm, buffonata.
-- 
Roal Zanazzi

 Lasciala perdere, e' una gran ca... ehm, buffonata.
Permettimi di dissentire. Esiste un grosso equivoco sulla notazione 
ungherese, che ha portato tanti a disprezzarla come fai tu :-)
Tutti sanno che la notazione ungherese prevede l'uso di un sistema di 
prefissi che indicano il tipo della variabile, è vero, ma nessuno ha 
capito che vanno usati per indicare il TIPO SEMANTICO della variabile e 
non quello "grammaticale".
Faccio un esempio preso dall'articolo: dwDialog non significa "variabile 
Dialog di tipo DWORD" ma "delta width Dialog" cioè "differenza in 
larghezza della dialog"... il tipo della variabile in questione (int, 
long o che cavolo è) non c'entra una fava col prefisso. In questo modo 
se nel codice vedi una riga "dwQualcosa + hndQualcosaltro" SAI 
immediatamente che è un errore anche se magari sono tutti e due int.
Il principio alla base della notazione ungherese è quello elementare 
della "dimensione delle grandezze" che ti insegnano in seconda 
elementare secondo cui "non si sommano mele e pere, ma solo oggetti 
uguali fra loro": è lo stesso principio che poi ritrovi in fisica con le 
equazioni dimensionali.

 immediatamente che è un errore anche se magari sono tutti e due int.
In C++ semplicemente non serve.
Se poi il programmatore usa due DWORD per entrambe le variabili deve 
solo biasimare sé stesso.
Con la notazione ungherese si torna all'asm.
Kiuhnm

 equazioni dimensionali.
 >
Capisco il tuo punto di vista, ma proprio perche' gli strumenti che 
abbiamo a disposizione gia' oggi per lo sviluppo del software consentono 
di evitare controlli noiosi ed error-prone sulle "dimensioni delle 
grandezze", arrivo alla conclusione che la notazione ungherese e' 
quantomeno obsoleta, essenzialmente inutile ed in alcuni casi 
controproducente.
Non sto dicendo che bisognerebbe vietarne l'uso, per carita', ma non la 
consiglierei ad uno che sta imparando a programmare.
-- 
Roal Zanazzi