Und noch ne Anfängerfrage
-
Also, ich hab zwar nicht wirklich verstanden, was genau in der new() funktion passiert, ich nehme aber an, sie liefert mir richtig ausgerichteten Speicher?
Wie sieht es eigentlich mit addps aus? In meiner Assembler Referenz steht nichts davon, dass, wenn der zweite Operand aus dem Speicher stammt, dieser auch aligned sein muss. Scheint aber so zu sein...
-
soerenP schrieb:
Also, ich hab zwar nicht wirklich verstanden, was genau in der new() funktion passiert, ich nehme aber an, sie liefert mir richtig ausgerichteten Speicher?
genau. so kannst du new/new[] ganz normal einsetzen.
soerenP schrieb:
Wie sieht es eigentlich mit addps aus? In meiner Assembler Referenz steht nichts davon, dass, wenn der zweite Operand aus dem Speicher stammt, dieser auch aligned sein muss. Scheint aber so zu sein...
Speicheroperanden müssen grundsätzlich ausgerichtet sein, es sei denn, der Befehl spezifiziert ausdrücklich etwas anderes, das ist an sich nur bei den entsprechenden movxyz-Befehlen der Fall.
-
Ich korrigiere mich (Das letzte Posting bezog sich auf das zwei vorher): Ich versteh nur noch Bahnhof. So etwas sag ich nicht gerne, aber es ist gerade angebracht. Ich glaube, die obige Version gefällt mir doch ganz gut...;)
Kannst du mir jetzt noch sagen, warum ich beim Rücksprung in eine übergeordnete (aufrufende) Funktion eine Acces-Violation bekomme. Im Call-Stack (ganz oben) steht nur 0a74fcfc()...
Ist irgendwas mit irgendwelchen Rücksprung-Adressen falsch?
Das kann doch eigentlich alles gar nicht so schwierig sein....Ein riesen Dank für deine Bemühungen!
Sören
-
naja, da ist auch jede Menge syntaktischer Lärm dabei, um für alle möglichen Eventualitäten vorzusorgen. Der wirklich interessante Teil ist der Gleiche wie zuvor.
Kannst du mir jetzt noch sagen, warum ich beim Rücksprung in eine übergeordnete (aufrufende) Funktion eine Acces-Violation bekomme. Im Call-Stack (ganz oben) steht nur 0a74fcfc()...
Ist irgendwas mit irgendwelchen Rücksprung-Adressen falsch?Code musst du schon zeigen.
-
Also, hier erstmal mein Assembler Code:
mov ecx,this movups xmm3,PMFdmOsString::m_a1[ecx]//Move coefficients to registers movups xmm4,PMFdmOsString::m_a2[ecx] movups xmm5,PMFdmOsString::m_a3[ecx] movups xmm6,PMFdmOsString::m_a4[ecx] movups xmm7,PMFdmOsString::m_a5[ecx] mov eax,8 //Prepare Loop mov ebx,16 //we are doing 4 steps at a time mov edx,end //eax is start and ecx is end of the loop schleife: movups xmm1,[pm_y_t+eax-8]//t[x-2]*a4 movups xmm2,[pm_y_t+eax+8]//t[x+2]*a4 addps xmm1,xmm2 mulps xmm1,xmm6//after having added, multiply with coefficient a4 movaps xmm0,xmm1//move to other register, where the multiplication results can be accumulated movups xmm1,[pm_y_t+eax-4]//t[x-1]*a3 movups xmm2,[pm_y_t+eax+4]//[t][x+1]*a3 addps xmm1,xmm2 mulps xmm1,xmm5//multiply with coefficient addps xmm0,xmm1//accumulate in xmm0 movups xmm1,[pm_y_t+eax]//[t][x]*a1 mulps xmm1,xmm3 addps xmm0,xmm1//accumulate in xmm0 movups xmm1,[pm_y_tm1+eax]//[t-2][x]*a2 mulps xmm1,xmm4 addps xmm0,xmm1//accumulate in xmm0 movups xmm1,[pm_y_tm2+eax]//[t-2][x]*a5 movups xmm2,[pm_y_tm1+eax-4] addps xmm1,xmm2 movups xmm2,[pm_y_tm1+eax+4] addps xmm1,xmm2 mulps xmm1,xmm7 addps xmm0,xmm1//accumulate in xmm0 movntps [pm_y_tp1+eax],xmm0 //write accumulation-result to memory add eax,ebx //increase loop counter by 16Bytes cmp eax,edx jb schleife ret
Dort, wo die Exception auftritt sieht die Dissemblierung so aus:
0A74FCFA je 0A74FD06 //Hier tritt der Fehler auf: 0A74FCFC les edx,fword ptr [ebx-6Bh] 0A74FCFF or eax,dword ptr [eax] 0A74FD01 add byte ptr [eax],al
und zwar ist ebx=0, was wahrscheinlich nicht so sein sollte.
Die Register zu sichern mit pusha, popa hat auch nichts gebracht.
Hat dir das was gebracht?
Ich weiß nicht, was sonst noch interessant sein könnte
Grüße
Sören
-
zeig immer den ganzen Funktionsrumpf. Ich würde aber darauf tippen, dass das ret dort nicht hingehört. Außer in naked-Funktionen solltest du Funktionen niemals direkt mit ret verlassen (und naked ist hier nicht angebracht).
-
nebenbei gesagt, gibt es eigentlich keinen Grund, die Koeffizienten m_a als sse-Vektor zu speichern, wenn sie sowieso in allen Komponenten gleich sind. Es dürfte sinnvoller sein, sie normal als float zu speichern und dann erst bei der Verarbeitung zu duplizieren:
movss xmm3,PMFdmOsString::m_a3[ecx] shufps xmm3,xmm3,0
-
Oha!
Ja, gut zu wissen, alles. Vielen Dank!
Was die koeffizienten angeht: Ich dachte, man könnte mit der Aktion vielleicht einen Schritt sparen. Mal schauen...
Sören
-
Und das nächste Problem:
Diesmal ist der this-Pointer nach der Aktion im Arsch. Der steht auf irgendeinem quatsch-Wert. Er sollte ungefähr auf:0x0b950063 stehen, steht aber auf 0xc79a39ab.
Gibt es irgendeine Stelle, wo der this Pointer von irgendwoher geladen wird und an dort nicht das richtige steht? ecx? In ecx steht übrigens noch die richtige Adresse, wie kann da der this Pointer kaputt gehen?
Grüße
Sören
-
soerenP schrieb:
Und das nächste Problem:
Diesmal ist der this-Pointer nach der Aktion im *****. Der steht auf irgendeinem quatsch-Wert. Er sollte ungefähr auf:0x0b950063 stehen, steht aber auf 0xc79a39ab.
Gibt es irgendeine Stelle, wo der this Pointer von irgendwoher geladen wird und an dort nicht das richtige steht? ecx? In ecx steht übrigens noch die richtige Adresse, wie kann da der this Pointer kaputt gehen?
Grüße
Sörenhöchstwahrscheinlich ist this irgendwo auf dem stack zu finden, jedenfalls im Assemblerteil. Aber ohne Code kann ich nur raten.
-
Den Code kennst du ja;)...
Direkt nach dem Rücksprung zu C++ ist der Pointer nicht mehr der alte und es gibt bei einem simplen t++ (member-Variable) natürlich eine Access-Violation, weil er logischerweise t dann auch nicht mehr kennt, wenn der this pointer falsch ist...//Hier steht der Code vom früheren Posting jb schleife }//asm t++;//hier tritt die Acces violation auf
Bis denn und schönen Abend
Sören
-
söän schrieb:
Den Code kennst du ja;)...
Eben nicht. Ich kenne den Rest der Funktion nicht. Um ehrlich zu sein, ich bin mir einigermaßen sicher, wo der Fehler liegt - Gewissheit erlange ich aber eben erst durch den Rest des Codes. Ich schreibe nur ungern über Dinge, die ich nur vermuten kann.
vor allem interessiert mich, wie pm_y_t, pm_y_tm1, pm_y_tm2, pm_y_tp1, end definiert wurden und welche Werte sie haben.
-
Na guuuut...
Hier haste ihn:float PMFdmOsString::getOutput() { if(m_disable)return 0; int end=4*(m_nElements-2);//!!!Hier ist END!!! m_forceBuffer[m_forceBufferPointer][2]=m_bodyInputBuffer*0.0005*m_bodyInteractionFactor; if(!tester.m_sse) { for(int i=0;i<m_osFactor;i++) { float *pm_y_tp1= m_y[tp1], *pm_y_tm1= m_y[tm1], *pm_y_tm2= m_y[tm2], *pm_y_t= m_y[t], *pm_forceBuffer_m_forceBufferPointer= m_forceBuffer[m_forceBufferPointer]; for(int x=2;x<m_nElements-2;x++) { pm_y_tp1[x]= m_coeff_a1*pm_y_t[x] +m_coeff_a2*pm_y_tm1[x] +m_coeff_a3*(pm_y_t[x+1]+pm_y_t[x-1]) +m_coeff_a4*(pm_y_t[x+2]+pm_y_t[x-2]) +m_coeff_a5*(pm_y_tm1[x+1]+pm_y_tm1[x-1]+pm_y_tm2[x]) +pm_forceBuffer_m_forceBufferPointer[x]; } /* for(int x=2;x<m_nElements-2;x++) { m_y[tp1][x]= m_coeff_a1*m_y[t][x] +m_coeff_a2*m_y[tm1][x] +m_coeff_a3*(m_y[t][x+1]+m_y[t][x-1]) +m_coeff_a4*(m_y[t][x+2]+m_y[t][x-2]) +m_coeff_a5*(m_y[tm1][x+1]+m_y[tm1][x-1]+m_y[tm2][x]) +m_forceBuffer[m_forceBufferPointer][x]; }*/ t++; tp1++; tm1++; tm2++; if(t==4)t=0; if(tp1==4)tp1=0; if(tm1==4)tm1=0; if(tm2==4)tm2=0; if(m_forceBufferPointer>0)m_forceBufferPointer--; if(i<m_osFactor-1)m_aaFilter->pushSample(m_y[t][2]); } } else { for(int i=0;i<m_osFactor;i++) { //Hier sind die Pointer deklariert und initialisiert float *pm_y_tp1= m_y[tp1], *pm_y_tm1= m_y[tm1], *pm_y_tm2= m_y[tm2], *pm_y_t= m_y[t], *pm_forceBuffer_m_forceBufferPointer= m_forceBuffer[m_forceBufferPointer]; /* for(int x=2;x<m_nElements-2;x++) { pm_y_tp1[x]= m_coeff_a1*pm_y_t[x] +m_coeff_a2*pm_y_tm1[x] +m_coeff_a3*(pm_y_t[x+1]+pm_y_t[x-1]) +m_coeff_a4*(pm_y_t[x+2]+pm_y_t[x-2]) +m_coeff_a5*(pm_y_tm1[x+1]+pm_y_tm1[x-1]+pm_y_tm2[x]) +pm_forceBuffer_m_forceBufferPointer[x]; }*/ __asm { mov ecx,this movups xmm3,PMFdmOsString::m_a1[ecx]//Move coefficients to registers movups xmm4,PMFdmOsString::m_a2[ecx] movups xmm5,PMFdmOsString::m_a3[ecx] movups xmm6,PMFdmOsString::m_a4[ecx] movups xmm7,PMFdmOsString::m_a5[ecx] mov eax,8 //Prepare Loop mov ebx,16 //we are doing 4 steps at a time mov edx,end //eax is start and ecx is end of the loop schleife: movups xmm1,[pm_y_t+eax-8]//t[x-2]*a4 movups xmm2,[pm_y_t+eax+8]//t[x+2]*a4 addps xmm1,xmm2 mulps xmm1,xmm6//after having added, multiply with coefficient a4 movaps xmm0,xmm1//move to other register, where the multiplication results can be accumulated movups xmm1,[pm_y_t+eax-4]//t[x-1]*a3 movups xmm2,[pm_y_t+eax+4]//[t][x+1]*a3 addps xmm1,xmm2 mulps xmm1,xmm5//multiply with coefficient addps xmm0,xmm1//accumulate in xmm0 movups xmm1,[pm_y_t+eax]//[t][x]*a1 mulps xmm1,xmm3 addps xmm0,xmm1//accumulate in xmm0 movups xmm1,[pm_y_tm1+eax]//[t-2][x]*a2 mulps xmm1,xmm4 addps xmm0,xmm1//accumulate in xmm0 movups xmm1,[pm_y_tm2+eax]//[t-2][x]*a5 movups xmm2,[pm_y_tm1+eax-4] addps xmm1,xmm2 movups xmm2,[pm_y_tm1+eax+4] addps xmm1,xmm2 mulps xmm1,xmm7 addps xmm0,xmm1//accumulate in xmm0 movntps [pm_y_tp1+eax],xmm0 //write accumulation-result to memory add eax,ebx //increase loop counter by four cmp eax,edx jb schleife }//asm t++; tp1++; tm1++; tm2++; if(t==4)t=0; if(tp1==4)tp1=0; if(tm1==4)tm1=0; if(tm2==4)tm2=0; if(m_forceBufferPointer>0)m_forceBufferPointer--; if(i<m_osFactor-1)m_aaFilter->pushSample(m_y[t][2]); } }//using sse //To prevent the denormalization bug: avoid too small values if(m_y[t][m_exciterElement]<0.0000000119f&&m_y[t][m_exciterElement]>-0.0000000119f)m_denormalGuardCounter++; else m_denormalGuardCounter=0; if(m_denormalGuardCounter>=40) { for(int i=0;i<4;i++) memset(m_y[i],0,m_nElements*sizeof(float)); m_disable=true; m_denormalGuardCounter=0; } float output=m_aaFilter->getOutput(m_y[t][2]); (*m_bodyOutput)+=output; return output; }
-
hat zwar nichts mit deiner frage zu tun, aber wo ich das hier gerade sehe...
if(m_denormalGuardCounter>=40)
...nehme ich an, dass dich evtl. das interessiert.
-
Nicht, dass es ein Problem wäre, aber habe ich das richtig verstanden, dass das nur unter SSE2 geht?
Dass DAZ und FZ Flag gibts nämlich erst da.
-
Das Problem sind alle Adressberechnungen:
[pm_y_t+eax-8] [pm_y_tp1+eax]
usw.
Ein einzelner Befehl für immer nur maximal einen Lese oder Schreibvorgang auf dem Speicher aus (Lesen und Schreiben zugleich nur, wenn ein Speicheroperand gleichzeitig Quelle und Ziel ist).
Das bedeutet, dass wenn eine Variable in einer komplexen Adressierung verwendet wird, zunächst nur die Adresse dieser Variablen für die Berechnung der Adresse des Speicheroperanden genutzt wird, und dann erst vom Ergebnis dieser Adressberechnung gelesen wird.
[pm_y_t+eax-8] ist also sinngemäß *(&pm_y_t+(eax-8)/sizeof(float)) - dein movntps zerstört also die Stackstruktur oberhalb von pm_y_t.Was du möchtest, ist erst den Zeiger zu lesen, und dann mit dem Ergebnis dieses Lesevorgangs eine Adresse zu berechnen, von der anschließend gelesen wird.
Tatsächlich - das muss bei komplexer Adressierung berücksichtigt werden - ist pm_y_t in als Adressausdruck keine Konstante, da es sich um eine automatische Variable handelt, sondern ein Ausdruck relativ zu ebp.Da du ja noch ein paar freie Register hast (ecx,esi,edi) kannst du diese Zeiger ja vor der Schleife einfach einmal laden.
-
Aha, fast schon amüsant, was man als Anfänger alles so verbocken kann...
Und noch einmal:
Besten Dank!
Sören
-
Na also, da hammas!
Nachdem ich den MOVNTPS noch in ein MOVUPS verwandeln musste. Der MOVNTPS ist bestimmt besser, verlangt aber natürlich auch aligned-Speicher. Und selbst, wenn mein Speicher aligned ist, hab ich immer einen Offset von 8 Bytes weil ich bei y[tp1][2] anfange zu zählen. Kann man auch Speicher machen, der genau NICHT auf 16 aligned ist, aber auf 8?
Viele Grüße
Sören
-
soerenP schrieb:
Kann man auch Speicher machen, der genau NICHT auf 16 aligned ist, aber auf 8?
Das ist doch trivial, oder (wenn du einmal auf 16 Byte ausgerichteten Speicher hast)?
Ich würde allerdings erst mal ein paar mehr (im Vergleich) high-level Optimierungen versuchen: ein ausgerichteter Speicherzugriff ist schneller als ein unausgerichteter - wesentlich besser aber ist es, den Zugriff gleich ganz zu eliminieren. Versuch also mal, die Anzahl der Speicherzugriffe zu veringern (SHUFPS sollte da sehr nützlich sein). Ich hab mich noch nicht dran versucht - aber mein Gefühl sagt mir, dass da einiges zu machen sein sollte. Dabei immer auch im Hinterkopf die multiskalare Architektur moderner Prozessoren (C3/C7 vergessen wir mal) haben - ein shuffle kann ohne weiteres parallel zu einem mov ausgeführt werden, wenn keine Abhängigkeiten bestehen.
-
falls soerenP kurz umschreiben moechte was sein filter denn ueberhaupt erreichen soll und in welcher art und weise die ganzen indizes auf seine datenstueckchen zeigen, haette man eine grundlage um ueber die optimierung des algorithmus' an sich nachzudenken, zb indem das signal auf geeignete weise gefaltet wird.