Und noch ne Anfängerfrage


  • Mod

    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.


  • Mod

    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


  • Mod

    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...


Anmelden zum Antworten