SSE Geschwindigkeit
-
Ich arbeite zzt daran eine 4x4Matrix Klasse auf SSE umzustellen. Bei Geschwindigkeits vergleichen für 100.000 Berechnungen zwischen der alten nicht SSE Funktion und der neuen SSE Funktion musste ich aber feststellend as das Ergebniss nicht ganz meinen Erwartungen entspricht. Wärend alle Intel Systeme auf denen ich getestet habe mir durchweg um die 20% Zeitersparniss bieten, fiel der Vorteil bei AMD CPUs mit um die 2,5-5% relativ mager aus.
Hier ein kurzes Beispiel:
Klassenvariablen von Matrix
union { struct { float m11,m12,m13,m14; float m21,m22,m23,m24; float m31,m32,m33,m34; float m41,m42,m43,m44; }; float matrix4x4[4][4]; __declspec(align(16)) float matrix16[16]; };
non SSE Version
Matrix& Matrix::operator+= (const Matrix &rhs) { m11+=rhs.m11; m12+=rhs.m12; m13+=rhs.m13; m14+=rhs.m14; m21+=rhs.m21; m22+=rhs.m22; m23+=rhs.m23; m24+=rhs.m24; m31+=rhs.m31; m32+=rhs.m32; m33+=rhs.m33; m34+=rhs.m34; m41+=rhs.m41; m42+=rhs.m42; m43+=rhs.m43; m44+=rhs.m44; return *this; };
SSE Version
Matrix& Matrix::operator+= (const Matrix &rhs) { float *lhsMatrix=matrix16; const float *rhsMatrix=rhs.matrix16; __asm { mov edx, [lhsMatrix] mov esi, [rhsMatrix] movaps xmm0, [edx] movaps xmm1, [edx+16] movaps xmm2, [edx+32] movaps xmm3, [edx+48] movaps xmm4, [esi] movaps xmm5, [esi+16] movaps xmm6, [esi+32] movaps xmm7, [esi+48] addps xmm0, xmm4 addps xmm1, xmm5 addps xmm2, xmm6 addps xmm3, xmm7 movaps [edx], xmm0 movaps [edx+16], xmm1 movaps [edx+32], xmm2 movaps [edx+48], xmm3 }; return *this; };
Da ich keine Informationen finden kontne wieso diese Beobachtung so ist würde ich gern wissen ob ich beim SSE etwas falsch gemacht habe oder ob mir hier schlicht die Architektur der AMD Prozessoren einen Strich durch die Rechnung macht.
Ich nutze zzt Visual Studio 2008 SP1.
-
SSE ist halt von Intel, AMD hatte 3Dnow und mapped die SSE-Befehle auf 3Dnow glaube. Da geht schon etwas Performance verloren. Ob du etwas falsch gemacht hast oder mehr herauszuholen ist, kann ich dir nicht sagen. Ich kenne mich zu wenig aus mit SSE.
-
Also Ummappen könnte ja eigentlich garnicht gehend a 3Dnow ja wie MMX nur über 64Bit Register verfügt.
-
Ich kenne mich zwar auch nicht mit SSE aus, aber probiere doch mal ob das besser funktioniert:
mov edi,[lhsMatrix] ;obwohl ich bezweifle das es einen unterschied macht ob du edx oder edi nimmst mov esi,[rhsMatrix] movaps xmm0,[edi] movaps xmm4,[esi] movaps xmm1,[edi+16] movaps xmm5,[esi+16] movaps xmm2,[edi+32] movaps xmm6,[esi+32] movaps xmm3,[edi+48] movaps xmm7,[esi+48] addps xmm0,xmm4 addps xmm1,xmm5 addps xmm2,xmm6 addps xmm3,xmm7 movaps [edi],xmm0 movaps [edi+16],xmm1 movaps [edi+32],xmm2 movaps [edi+48],xmm3
Das einzige was mir noch einfällt, was SSE Performance betrifft, ist das die Performance auch daran liegt an was für einer Adresse (vom Alignment her) die Matrizen gespeichert werden.
Guck dir doch mal den Link an:
http://www.cortstratton.org/articles/HugiCode.html
-
Danke für das Dokument habs mir mal angeschaut und die letzten tage etwas rumprobiert, aber erfolglos. Das durchmischen von Lese, Schreib und Rechenoperationen hat nichts gebracht, genauso der Versuch prefetchnta oder zumr ausschreiben movntps zu verwenden. Alles bewegte sich im selben Rahmen oder war etwas langsammer.
-
Ich sehe auch keinen Fehler. Möglicherweise wird SSE tatsächlich nur so schlecht von AMD unterstützt.
-
lupo1977 schrieb:
Ich sehe auch keinen Fehler. Möglicherweise wird SSE tatsächlich nur so schlecht von AMD unterstützt.
Ich denke nicht, dass AMD sich das heute noch leisten kann. Damals, als man de Facto 3Dnow! für tot erklärt hat mit der Aufnahme der neuesten SSE in AMDs Prozessorgeneration war es tatsächlich so, dass Performance sekundär war. Bei billigen Prozessoren wurde SSE angeblich teilweise sogar emuliert, hauptsache es lief irgendwie.
Aber heute kann ich mir das nicht mehr vorstellen. Bist du sicher, dass dein SSE-Code den Flaschenhals deiner Applikation darstellt und nicht sonst irgendwo ein Problem besteht?
-
Hier wurde vermutlich mal wieder Unfug gemessen.
-
Ein paar (vermutlich) offensichtliche Dinge, aber zur Sicherheit:
Bist du sicher dass der Compiler intern aus der non-SSE-Version nicht selbst eine SSE-Version bastelt? Sprich: verwendest du extra Compiler-Flags, um das zu verhindern? Hast du dir den ASM-Output angeschaut? Schaut der so aus wie du erwartest?
Ist deine Matrix auch richtig aligned? Non-Aligned reads kosten bei SSE ungemein viel. Das "__declspec(align(16))" allein garantiert kein korrektes Alignment, du musst beim Speicher-Allokieren auch alles richtig machen.
-
wenn du align loads hast und eine addresse uebergibst die nicht alligned ist, gibt es normalerweise eine exception.
@Xebov poste mal den assembler von der compilierten c version, wie hier schon gesagt wurde kann der compiler auch eventuel sse code generieren. kann sein, dass er loop unrollt, dass instructions besser interleaved werden, dass die funktion geinlined wird waehrend deine es nicht wird, kann sein dass teile in registern behalten werden in der c version waehred deine immer daten nachlaedt.
kurz:
du musst den assembler code von beiden versionen vergleichen, nicht den source.