Lohnt sich SIMD in meiner Anwendung?



  • Hallo, liebe Leute!
    Ich habe eine sehr zeitkritische Funktion in meinem Audioplugin. Ich überlege deshalb, folgende Schleife mit SIMD zu beschleunigen. Lohnt sich das?

    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];
    	}
    

    Die Schleife wird pro Audiosample (44100*pro Sekunde)aufgerufen. m_nElements soll so um die 60 sein, da komm ich schon auf gut 30% Auslastung. Da das längst nicht alles ist: viel zu viel.
    Soweit ich das Überblicke kann ich die 5 Multiplikationen in 2 Schritten erledigen und die konstanten m_coeff in den Registern lassen. Das würde mich aber eine gewisse Umschicht und Align-Arbeit kosten, oder?
    Wie gesagt: Lohnt sich das?
    Viele Grüße
    Sören
    Edit: Und lohnt sich es dafür Assembler zu lernen? 😉


  • Mod

    soerenP schrieb:

    Das würde mich aber eine gewisse Umschicht und Align-Arbeit kosten, oder?

    Möglich. Es gibt mehr als eine Methode, SIMD einzusetzen.

    Wie gesagt: Lohnt sich das?

    wahrscheinlich.

    Edit: Und lohnt sich es dafür Assembler zu lernen? 😉

    vielleicht.

    SIMD erfordert nicht unbedingt den Einsatz eines Assemblers - obwohl Assemblerkenntnisse dabei durchaus nützlich sind. Es mag nicht einmal der beste Weg sein: die Portabilität ist erheblich eingeschränkt. Meist gibt es einen header mmintrin.h oder xmmintrin.h der geeignete intrinsics bereitstellt.

    Vielleicht bin ich ja interessiert, diese Optimierung zu versuchen - Nobuo T lässt mich hängen :p
    Für welchen Compiler/welche Plattform ist das denn gedacht?



  • camper schrieb:

    Vielleicht bin ich ja interessiert, diese Optimierung zu versuchen - Nobuo T lässt mich hängen :p

    Ja, sry - erstmal muss ich einige Klausuren optimieren, bevor ich wieder mit dem Assembler spiele. 😉 :p



  • Danke, danke!
    Ich glaube Hilfe ist nicht so gut, es soll für meine Diplomarbeit sein.
    Ich wollt mir das sowieso mal anschauen.
    Soviel Ehrgeiz habe ich dann auch noch, das selber zu machen. Wichtig ist mir nur, dass Ihr meint, es würde sich lohnen. Meint Ihr, man kann einen Faktor angeben, um den man die Performance steigern kann?
    Es ist übrigens für Visual C++ 6 (Ich weiss, völlig veraltet) soll vom Prozessor her möglichst kompatibel sein und das Plugin ist für die VST-Schnittstelle. Sonst noch Fragen?
    Viele Grüße
    Sören


  • Mod

    soerenP schrieb:

    Danke, danke!
    Ich glaube Hilfe ist nicht so gut, es soll für meine Diplomarbeit sein.
    Ich wollt mir das sowieso mal anschauen.
    Soviel Ehrgeiz habe ich dann auch noch, das selber zu machen. Wichtig ist mir nur, dass Ihr meint, es würde sich lohnen. Meint Ihr, man kann einen Faktor angeben, um den man die Performance steigern kann?
    Es ist übrigens für Visual C++ 6 (Ich weiss, völlig veraltet) soll vom Prozessor her möglichst kompatibel sein und das Plugin ist für die VST-Schnittstelle. Sonst noch Fragen?
    Viele Grüße
    Sören

    Ein völlig veralteter (wohl auch nicht optimierender) Compiler für eine Diplomarbeit? Warum bindest du dir diesen Klotz ans Bein. Ein moderner Compiler hätte vermutlich einen ähnlichen Performancevorteil (und zur Not muss man ja nicht das ganze Projekt mit dem gleichen Compiler übersetzen).
    Gegenüber optimiertem normalem SISD-Code kann die Geschwindigkeit in der Regel (es gibt ein paar Ausnahmen, insbesondere wenn die Geschwindigkeit des normalen Codes durch den beschränkten Registersatz begrenzt wird) maximal um den Faktor 4 steigern - ich wage allerdings nicht zu schätzen, wie viel Performance dein Compiler bereits jetzt verschenkt, vermutlich ist das mehr.
    Zu den SIMD-Instruktionen:
    MMX: verfügbar ab Pentium MMX bzw. Pentium II und K6 erlaubt gepackte Operationen auf 2 32-bit Integern - wegen des unvermeidbaren Overheads ist es oft nicht ganz leicht, das in eine Steigerung der Gesamtperformance zu übersetzen
    3dnow: ab K6-2 (nur AMD) für gepackte Operationen auf 2 floats
    SSE: verfügbar ab Pentium III und Athlon XP erlaubt gepackte Operationen auf 4 32-bit Gleitkommazahlen (also float)
    SSE2: ab Pentium IV und Athlon 64 erlaubt gepackte Operationen auf 4 32-bit Integern oder 2 64-Gleitkommazahlen (double) oder 2 64-bit Integern

    von der Methodik her empfehle ich, sich nicht durch die bestehende Schleifenstruktur (die wohl durchaus selbst noch verbessert werden könnte) zu beschränken. Ein sehr simple und oft mit geringem Overhead verbundene Methode ist zum Beispiel, die Schleife x-fach aufzurollen und dann Vektorinstruktionen auf einen solchen x-Vektor loszulassen, also sinngemäß:

    for(int x=2;x<m_nElements-2;x+=4)
        {
            m_y[tp1][x.x+1.x+2.x+3]=
                m_coeff_a1*m_y[t][x.x+1.x+2.x+3]
                +m_coeff_a2*m_y[tm1][x.x+1.x+2.x+3]
                +m_coeff_a3*(m_y[t][x+1.x+2.x+3.x+4]+m_y[t][x-1.x.x+1.x+2])
                +m_coeff_a4*(m_y[t][x+2.x+3.x+4.x+5]+m_y[t][x-2.x-1.x.x+1])
                +m_coeff_a5*(m_y[tm1][x+1.x+2.x+3.x+4]+m_y[tm1][x-1.x.x+1.x+2]+m_y[tm2][x.x+1.x+2.x+3])
            +m_forceBuffer[m_forceBufferPointer][x.x+1.x+2.x+3];
        }
    

    der Fantasie sind da kaum Grenzen gesetzt.



  • Vor allem solltest du bedenken dass Compiler wie z. B. der GCC ab Version 4 Schleifen automatisch in SSE-Varianten uebersetzen koennen. Besonders die von camper gezeigte aufgerollte Version schaut (fuer mich) so aus als koennte das evlt. sogar schon der Compiler alleine hinkriegen.



  • Ja, vielen Dank!
    Ich benutze den Compiler, weil ich ihn mir mal legal erworben habe und alles bislang ganz gut funktioniert hat und (bla, bla...) ich bis jetzt wohl etwas schlampig mit dem Thema optimierung umgegangen bin. Bin sonst eigentlich von Haus aus eher Gelegenheitsprogrammierer (ich studiere Medientechnik...) Gibt es denn gute Umsonst-Compiler, oder sollte ich ein bisschen was investieren? Und ausserdem habe ich es nicht geschafft, mit ner OpenSource Entwicklungsumgebung ein VST-Plugin zu kompilieren, da das VST-SDK damit nicht funktioniert (Compiler-Dialekt????)

    Achso, und nochwas: Kann ich mir mit unglücklichen Assembler Befehlen, die aber eher harmloser Natur waren (MOV, CPUID, etc) Sachen kaputt schießen?
    Visual C++ stürzt seit ich Beispiel Assembler aus einem Buch ausgeführt habe, auch während des Schreibvorgangs einfach mal ab und mein WinSCP-Icon ist komplett schwarz... (Wahrscheinlich ein weiterer Grund, einen neuen Compiler zu installieren...)

    Viele Grüße
    Sören



  • Hey!
    Nur dass ihr es wisst:
    Hab es mit Code::Blocks geschafft, ein VST-Plugin zu kompilieren. Ich würde behaupten, der GCC-Compiler hat einen Faktor 5 rausgeholt! Obwohl mich die Assembler Geschichte auch mal gereizt hätte, aber: Andermal!!!
    Vielen Dank Euch!
    Sören



  • Ich hab da noch ein bisschen was am Code verändert und es ist tatsächlich ein bisschen schneller:

    Angenommen m_coeff(1,2,3...),m_forceBuffer und **m_y sind float, ansonsten musst du float durch einen anderen Typ erstzen

    float *pm_y_tp1= m_y[tp1],
          *pm_y_tm1= m_y[tm1],
          *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*m_y[t][x]
                +m_coeff_a2*pm_y_t[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_tm1[x])
            +pm_forceBuffer_m_forceBufferPointer=m_forceBuffer[x];
        }
    

    Ist glaub ich fast wie Deferenzierung. Will mich aber nicht festlegen.



  • Wow!
    Ich hatte schon gar nicht mehr mit Antworten aus dem Thread gerechnet!
    Das lohnt sich total. Ca doppelt so schnell, wenn ich das gerade überschlage?
    Meint zumindest die Anzeige in meinem Cubase.
    Also, vielen Dank.
    Gibt es irgendwo Literatur, wo man erfahren kann, wieviel Prozessorleistung einzelne Befehle verbrauchen? Hätte nicht gedacht, dass man mit einem [] soviel verbrauchen kann...
    Subba!
    Sören



  • Ok, ganz soviel warens dann am ende doch nicht. aber immerhin etwas:
    Die Peaks liegen jetzt bei 50 anstatt bei 60% auslastung...


Anmelden zum Antworten