Und noch ne Anfängerfrage
-
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.
-
Ok, versuch ich mal...