Alignment / pointer vs. array / SSE



  • Hallo, erstmal mein Code:

    #include <stdio.h>
        #include <iostream>
        #include <xmmintrin.h>
        #include <windows.h>
    
        #define dim 8
        #define DEBUG
    
        float x[dim] __attribute__((aligned(16)));
        float A[dim*dim] __attribute__((aligned(16)));
        float result[dim];
    
        __m128 c;  
    //einkommentieren....
    //    float* __attribute__((aligned(16))) x = new float[dim];
    //    float* __attribute__((aligned(16))) A = new float[dim*dim];    
        int main(void){
    
         //irgendwie füllen...
        for(int i = 0;i<dim;i++) {
            x[i] = i+4;
            for(int j = 0;j<dim;j++) {
                A[j+dim*i] = i+j;         
            }   
        }
    
         // CPU implementation (unwichtig...)
        _SYSTEMTIME hallo;
        std::cout << "CPU" << std::endl;
        GetSystemTime(&hallo);
        int milli = hallo.wSecond*1000+hallo.wMilliseconds;
        float temp2 = 0;
        int Aadder2 = 0;
          for(int i = 0;i<dim;i++) {
            temp2 = 0;
            for(int j = 0;j<dim;j++) {
                temp2 += A[j+Aadder2]*x[j]; 
            }
            Aadder2 += dim;
            result[i] = temp2;
        }
        GetSystemTime(&hallo);
        std::cout << hallo.wSecond*1000+hallo.wMilliseconds - milli << std::endl;
        #ifdef DEBUG
        for(int i = 0;i<dim;i++) {
            std::cout << result[i] << std::endl;
        }
        #endif
    
        std::cout << "SSE" << std::endl;
        //zeiterfassung, unwichtig....
        GetSystemTime(&hallo);
        milli = hallo.wSecond*1000+hallo.wMilliseconds;
         //float* xt = x;
        float* temp = new float[4]; 
        for(int i = 0;i<dim;i++) {    
            c = _mm_setzero_ps();
            for(int j = 0;j<dim;j+=4) {
                //das stürzt ab bei float*...
               c = _mm_add_ps(_mm_mul_ps(_mm_load_ps(x+j),_mm_load_ps(A+i*dim+j)),c);
            }       
            _mm_store_ps(temp,c);
            result[i] = temp[0] + temp[1] + temp[2] + temp[3];
        }
        GetSystemTime(&hallo);
        std::cout << hallo.wSecond*1000+hallo.wMilliseconds - milli << std::endl;
        #ifdef DEBUG
        for(int i = 0;i<dim;i++) {
            std::cout << result[i] << std::endl;
        }
        #endif
    
        system("Pause");
        return 0; 
    }
    

    nicht erschrenken, dass meiste ist da nur so vollständighalber gepostet...
    so wie es ist, compiliert es unter dev-c++ tadellos. aber ich will ja aus der SSE Geschichte ne funktion bauen (ist ne Matrix mal Vector Muliplikation)
    so wenn ich nun die Arrays als pointer zuweise (die 2 auskommentierten Zeile ersetzen das A und x) kommt ein Segfault..

    was mache ich falsch, bin da noch nicht der hellste, und weiß nicht genau, wofür diese alignment man braucht bei SSE, irgendwie funktionierts auch ohne(btw.), naja, vielleicht weiß jemand rat ? was ist der Unterschied zwischen den zwei Array addressierungen ?

    danke, Karlos

    ps: hallo Forum



  • Karlos schrieb:

    was mache ich falsch

    Das Alignment wirkt nicht auf dynamischen Speicher. Mach dir nichts draus, das ist mir auch schon auf die Füsse gefallen. 😉 Der Speichermanager selbst bestimmt, wie letztendlich ausgerichtet wird. Eine simple Lösung dafür gibt es nicht, da die stdlib keine entsprechenden Funktionen anbietet. (übrigens, new ist C++)
    Vor einiger Zeit wurden hier allerdings ein paar Sachen gepostet, um dynamischen Speicher aligned zu reservieren. Wenn die Forensuche funktionieren würde, könnte ich dir auch den Link geben. 🙂 Ansonsten bieten auch diverse Bibliotheken entsprechende Funktionen an.

    Karlos schrieb:

    bin da noch nicht der hellste, und weiß nicht genau, wofür diese alignment man braucht bei SSE, irgendwie funktionierts auch ohne(btw.)

    SSE arbeitet mit 128 Bit (16 Byte) Werten, dementsprechend wird auf den Speicher zugegriffen. Und da sind aligned Zugriffe halt schneller. Das ist bei anderen Werten (int, long, float, etc.) auch nicht anders. Die Ursachen dafür liegen schlichtweg in der Hardware begründet. Wenn es dich interessiert, dann würde ich dir entsprechende Lektüre dazu empfehlen.
    Ansonsten, wenn es ohne Ausrichtung funktioniert, dann ist das reiner Zufall. Dann hat der Compiler die Daten zufällig so angelegt, dass diese an einer gültigen Adresse liegen. Darauf verlassen kannst du dich aber nicht. Zumal jeder Compiler da seine eigenen Vorstellungen hat. Der MSC zB richtet per default an 8 Byte Grenzen aus.
    Es gibt die SSE Anweisungen übrigens auch in non-aligned Versionen. Dort brauchst du dich um die Ausrichtung nicht mehr zu kümmern, musst dann aber mit Performancenachteilen rechnen.



  • Ich hab mal schnell nach _mm_add_ps gegooglet.

    1. Treffer: http://www.x86.org/articles/sse_pt3/simd3.htm

    Da wird _mm_malloc erwähnt.



  • TactX schrieb:

    Ich hab mal schnell nach _mm_add_ps gegooglet.

    1. Treffer: http://www.x86.org/articles/sse_pt3/simd3.htm

    Da wird _mm_malloc erwähnt.

    hmm, ja, __mm_malloc wird aber bei GCC nicht unterstützt 😞 bzw. hab ich nicht gefunden !?

    echt komisch alles..

    groovemaster schrieb:

    Die Ursachen dafür liegen schlichtweg in der Hardware begründet. Wenn es dich interessiert, dann würde ich dir entsprechende Lektüre dazu empfehlen.

    ja, bitte !!

    danke schonmal für die Hilfe !



  • LOL! ich glaube das hast du falsch verstanden mit der Lektüre. 🤡



  • hihi schrieb:

    LOL! ich glaube das hast du falsch verstanden mit der Lektüre. 🤡

    LoL, ist aber wohl eindeutig zweideutig zu verstehen ! 😉



  • geht nicht sowas in der art?

    void *aligned_malloc (size_t size, unsigned int alignment)
    {
       unsigned long p = (unsigned long)malloc (size + alignment);
       if (!p)
         return 0;
       while (p % alignment)
         p++;
       return (void*)p;
    }
    

    (ungetestet)

    edit: ok, das 'free' wird schwierig 😉



  • Karlos schrieb:

    ja, bitte !!

    http://www.google.de/ 😃

    Aber um meinen Vorredner nochmal zu zitieren und sämtliche Missverständnisse auszuräumen:

    ich glaube das hast du falsch verstanden mit der Lektüre.

    So, ich habe auch den Thread zum Problem wiedergefunden. ➡ hier



  • @Karlos
    Ich weiß ich nerve die meisten damit wahrscheinlich schon, aber system("PAUSE") ist echt die blödeste Art und Weise eine Eingabe von einem Benutzer zu erzwingen (mal davon abgesehen, dass man Konsolenprogramme normalerweise auch in der Konsole ausführt ;)). Außerdem ist es nicht ANSI-C konform.

    Wie man es besser macht, findest du in der Konsolen-FAQ unter "Automatisches Schließen verhindern".



  • AJ schrieb:

    Außerdem ist es nicht ANSI-C konform.

    [pedantic]
    Naja, ISO C konform ist es schon. Nur wird sich halt nicht auf jedem System das gewünschte Verhalten einstellen, da nicht jeder Kommandozeileninterpreter etwas mit "PAUSE" anfangen kann.
    [/pedantic]
    🙂


Anmelden zum Antworten