SSE

Thomas Huxhorn
Endlosschleifenbastler
Endlosschleifenbastler
Beiträge: 171
Registriert: 6. Okt 2011 15:25

SSE

Beitrag von Thomas Huxhorn » 12. Jan 2012 18:45

Sagmal, hat jemand ne Idee, warum mein Programm um 10% LANGSAMER wird, wenn ich z.b. eine einfache vec3 Multiplikation in SSE einbaue?
Das war um 2. Praktikum aber nicht so :(
Es rechnet noch richtig.

Ankou
Mausschubser
Mausschubser
Beiträge: 85
Registriert: 15. Mai 2011 18:23

Re: SSE

Beitrag von Ankou » 12. Jan 2012 19:34

wenn du eine einzelne Vektormultiplikation mittels SSE umsetzt ist der overhead für den asm Block vermutlich größer als der Gewinn.

Thomas Huxhorn
Endlosschleifenbastler
Endlosschleifenbastler
Beiträge: 171
Registriert: 6. Okt 2011 15:25

Re: SSE

Beitrag von Thomas Huxhorn » 12. Jan 2012 21:10

Hm, ja stimmt. Blöd.

mw1039
Computerversteher
Computerversteher
Beiträge: 346
Registriert: 12. Apr 2011 12:18

Re: SSE

Beitrag von mw1039 » 13. Jan 2012 09:53

Du kannst mal versuchen dir von gcc automatisch SSE-Code generieren zu lassen. Tipp mal ein "man gcc", dann "/-msse" und dann mit "n" weitersuchen, bis du das richtige gefunden hast (ungefaehr bei Zeile 6429). Mit "q" kommst du aus der manpage wieder raus.
Du kannst gcc (z.B. ueber die CMakeLists.txt) beispielsweise die Schalter "-msse", "-msse2", "-msse3", "-msse4" oder "-mfpmath=sse" uebergeben. Keine Ahnung wie gut das klappt, aber einen Versuch waere es wert.

Thomas Huxhorn
Endlosschleifenbastler
Endlosschleifenbastler
Beiträge: 171
Registriert: 6. Okt 2011 15:25

Re: SSE

Beitrag von Thomas Huxhorn » 13. Jan 2012 11:59

Danke, aber habe ich schon alles versucht. Bringt sogut wie garkein Unterschied in der Laufzeit.

Benutzeravatar
Ronny
BASIC-Programmierer
BASIC-Programmierer
Beiträge: 133
Registriert: 18. Nov 2005 14:33
Wohnort: IGD

Re: SSE

Beitrag von Ronny » 13. Jan 2012 15:55

Ein asm-Block an sich erzeugt keinen Overhead. Wie hast du denn den Vektor in ein SSE Register geladen?
Am besten sind leider nur float Vektoren mit vier Komponenten fuer SSE geeignet die auch noch aligned sind um sie mit movaps zu laden.
Es lohnt sich dazu sogar, einen dreidimensionalen Vektor um eine vierte Dummy-Komponente zu erweitern.

Thomas Huxhorn
Endlosschleifenbastler
Endlosschleifenbastler
Beiträge: 171
Registriert: 6. Okt 2011 15:25

Re: SSE

Beitrag von Thomas Huxhorn » 13. Jan 2012 15:59

Hier ein Beispiel. Habe die vec3 Klasse natürlich um eine 4. float Zahl erweitert.

Code: Alles auswählen

                "movups (%[src]), %%xmm1\n"
                :
                : [src] "a" (&a.x),
                  [dest] "b" (&result.x)
                : "%esi"
                );

Benutzeravatar
Ronny
BASIC-Programmierer
BASIC-Programmierer
Beiträge: 133
Registriert: 18. Nov 2005 14:33
Wohnort: IGD

Re: SSE

Beitrag von Ronny » 13. Jan 2012 17:07

Wenn deine Vektor Klasse nicht 16 Byte aligned ist, resultiert die movups Anweisung in mehreren Speicherzugriffen.
Und wenn du nach dem Laden dann auch nur eine einzige Multiplikation ausfuehrst, ist fragwuerdig ob sich der Aufwand lohnt.

x539
Windoof-User
Windoof-User
Beiträge: 30
Registriert: 24. Nov 2010 15:52

Re: SSE

Beitrag von x539 » 13. Jan 2012 17:48

gcc verwendet sse schon von alleine wenn man mit -O3 compiliert. Deshalb wird es schwer das per handgeschriebenen inline-Asm zu übertreffen. Im 2. praktikum war standard mäßig die Optimierung aus geschaltet, desshalb war der unterschied deutlicher zu sehen.

Außerdem kann der Compiler, den Code nicht mehr so gut Optimieren wenn du inline-Asm blöck reinschreibst. Zum Beispiel kann er die reinfolge der Befehle nicht mehr optimal den die pipline der CPU anpassen, weil er den inline-asm-block fest übernehemen muss. Schlecht ist außerdem wenn du feste Register vorgibst die du verwenden willst. Dann müssen eventuell werte sinnlos hin und hergeschoben werden, nur weil du dich auf rax, rbx, etc. festgelegt hast obwohl das genauso gut ein beliebiges anders Register hätte sein können, in dem der wert bereits steht, bzw. in dem der Wert später benötigt wird.
„Reality is that which, when you stop believing in it, doesn't go away.“ Philip K. Dick

Thomas Huxhorn
Endlosschleifenbastler
Endlosschleifenbastler
Beiträge: 171
Registriert: 6. Okt 2011 15:25

Re: SSE

Beitrag von Thomas Huxhorn » 13. Jan 2012 18:11

Hm wenn ich einfach vec() aufrufe, ja dann kann das sonstwo im Speicher liegen. Kenne nur die Möglichkeit mit malloc Speicher auszurichten.

Also mit -O3 war mein Programm sogar langsamer. Das erklärt es wohl.

simon.r
Mausschubser
Mausschubser
Beiträge: 59
Registriert: 4. Okt 2010 16:13

Re: SSE

Beitrag von simon.r » 13. Jan 2012 20:15

x539 hat geschrieben:gcc verwendet sse schon von alleine wenn man mit -O3 compiliert. Deshalb wird es schwer das per handgeschriebenen inline-Asm zu übertreffen. Im 2. praktikum war standard mäßig die Optimierung aus geschaltet, desshalb war der unterschied deutlicher zu sehen.

Außerdem kann der Compiler, den Code nicht mehr so gut Optimieren wenn du inline-Asm blöck reinschreibst. Zum Beispiel kann er die reinfolge der Befehle nicht mehr optimal den die pipline der CPU anpassen, weil er den inline-asm-block fest übernehemen muss. Schlecht ist außerdem wenn du feste Register vorgibst die du verwenden willst. Dann müssen eventuell werte sinnlos hin und hergeschoben werden, nur weil du dich auf rax, rbx, etc. festgelegt hast obwohl das genauso gut ein beliebiges anders Register hätte sein können, in dem der wert bereits steht, bzw. in dem der Wert später benötigt wird.
Ganz so stimmt das glaube ich nicht. Gibt man als Parameter "-mfpmath=sse" und "-msse2" an, dann verwendet gcc anstatt der FPU die xmm Register für skalare Operationen. Auf die Art und Weise lassen sich Berechnungen besser optimieren, da die Stack Struktur der FPU dafür eher ungeeignet ist. Kompiliert man auf 64bit (wie etwa auf dem Cluster), werden diese Flags automatisch gesetzt. Für automatische Vektorisierung (ps-Befehle) braucht man wahrscheinlich eher den Intel Compiler... Inwiefern gcc die Befehle konkret auf die Pipeline vom verbauten Prozessor optimieren kann weiß ich nicht, schließlich unterstüzt die g++Verison 4.5 auf dem Cluster als Architekturprofile maximal core2 und nicht corei7.^^

x539
Windoof-User
Windoof-User
Beiträge: 30
Registriert: 24. Nov 2010 15:52

Re: SSE

Beitrag von x539 » 13. Jan 2012 20:38

simon.r hat geschrieben:Inwiefern gcc die Befehle konkret auf die Pipeline vom verbauten Prozessor optimieren kann weiß ich nicht, schließlich unterstüzt die g++Verison 4.5 auf dem Cluster als Architekturprofile maximal core2 und nicht corei7.^^
Ich denke nicht das die sich starke unterscheiden, aber
mir ging es auch eher um allgemeine Optimierung:
z.B. ist

Code: Alles auswählen

movl foo, rax
xor  foo, rax
movl foo, rbx
xor foo, rbx
langsamer als,

Code: Alles auswählen

movl foo, rax
movl foo, rbx
xor foo, rax
xor foo, rbx
weil die beiden mov befehle gleichzeitig ausführt werden können.
wenn jetzt

Code: Alles auswählen

movl foo, rax
xor foo, rax
ein inline-block ist fällt diese optimierung weg.


Hmm… das gcc SSE nur für skalare operationen verwendet ist mir noch gar nicht aufgefallen. Ich hatte erwartet, dass zumindest die vec3d Funktionen nicht skalar umgesetzt werden.
„Reality is that which, when you stop believing in it, doesn't go away.“ Philip K. Dick

Jörg B
Neuling
Neuling
Beiträge: 4
Registriert: 16. Jan 2012 00:23

Re: SSE

Beitrag von Jörg B » 16. Jan 2012 00:37

Auch ich wollte auch etwas mit SSE rumspielen und habe mich an der Normalisierung versucht, da die Methode schon recht viel Zeit frisst.

Meine Variante besteht meine einzelnen Tests immer und ist dort sogar schneller als die gegebene C++ Variante, jedoch wird sie beim gesamten Rendern immer langsamer und nach ca. 500 Aufrufen geht sie so gut wie gar nicht mehr.

Jetzt wo die Abgabe vorbei ist, kann mir ja vielleicht jemand einen Tipp geben wieso das so ist? Irgendwo muss ich ja irgendwas zu viel erzeugen was dann Resourcen blockiert.

Grüße Jörg


vec.cpp

Code: Alles auswählen

vec3 vec3::normalize() const
{
	vec3 result = *this;

	 asm (  
      "\n\tmovups (%1), %%xmm0"
      "\n\tmovups %%xmm0, %%xmm2"	  
      "\n\tmulps %%xmm0, %%xmm0"  
      "\n\tmovups %%xmm0, %%xmm1"  
	  
      "\n\tshufps $0b10010011,%%xmm0, %%xmm0"  
      "\n\taddps %%xmm0, %%xmm1"  
	  
      "\n\tmovaps %%xmm1, %%xmm0"  
      "\n\tshufps $0b01001110,%%xmm1, %%xmm1"

	  
      "\n\taddps %%xmm1, %%xmm0"  
      "\n\trsqrtps %%xmm0, %%xmm0"  	  
	  
      "\n\tmulps %%xmm2, %%xmm0"
      "\n\tmovups %%xmm0, %0"
	  	 	  
      : "=m"(result)
      : "r"(this) : "xmm0", "xmm1", "xmm2");
	
	/*
	float invL = 1.0f/length();
	result.x *= invL;
	result.y *= invL;
	result.z *= invL; */

	return result;
}

x539
Windoof-User
Windoof-User
Beiträge: 30
Registriert: 24. Nov 2010 15:52

Re: SSE

Beitrag von x539 » 18. Jan 2012 18:22

Jörg B hat geschrieben:Jetzt wo die Abgabe vorbei ist, kann mir ja vielleicht jemand einen Tipp geben wieso das so ist?
Hast du deine Implementierung mal getestet? Die sieht nicht aus als würde sie den Vektor auf Länge 1 normieren sondern nochmal um die Länge strecken.
Btw. Können die GRIS-Rechner kein SSE4.1, dann gäbe es da nämlich noch dpps für das Skalar(/Dot)-Produkt
„Reality is that which, when you stop believing in it, doesn't go away.“ Philip K. Dick

simon.r
Mausschubser
Mausschubser
Beiträge: 59
Registriert: 4. Okt 2010 16:13

Re: SSE

Beitrag von simon.r » 18. Jan 2012 20:47

Ich habe nochmal recherchiert, es gibt doch einen automatischen Vektorisierer, der bereits bei "-O3" eingesetzt wird, allerdings nur auf Schleifne operiert und dazu noch recht wählerisch zu sein scheint. Siehe http://gcc.gnu.org/projects/tree-ssa/vectorization.html, gibt man "-ftree-vectorizer-verbose=2" beim Kompilieren an, bekommt man mehr oder weniger detailliert aufgezählt, welche Schleifen vektorisiert wurden und welche nicht.
Die Cluster Rechner können auf jeden Fall SSE 4.1, wir haben sogar als einzige SSE Instruktion dpps expliziet verwendet - leider ohne wirkliche Geschwindigkeitsänderungen...

Antworten

Zurück zu „Archiv“