64-Bit-Integers auf 32-Bit-Windows



  • Das fragst du gerade mich, den MSVC+Windows Hasser schlechthin? Ja, seit Ewigkeiten schon...



  • Nur so fürs Protokoll: long long ist kein 64-bit Integer in C++. std::int64_t ist einer. Deswegen hat der nämlich die 64 im Namen.



  • TyRoXx schrieb:

    Nur so fürs Protokoll: long long ist kein 64-bit Integer in C++.

    Er ist nur garantiert mindestens 64 Bit breit. 😉



  • TyRoXx schrieb:

    Deswegen hat der nämlich die 64 im Namen.

    Hätt' ich nie gedacht. 😃

    Edit: Ist int64_t nicht eh ein typedef auf long long ?


  • Mod

    Hacker schrieb:

    Edit: Ist int64_t nicht eh ein typedef auf long long ?

    Der Standard sagt dazu ganz klar: Möglicherweise. :p



  • Es ist ein Unterschied, ob du int64_t oder __int64 verwendest. Denn __int64 ist ein Compiler-Builtin von MSVC, genauso wie zb float oder int. int64_t dagegen ist ein typedef.



  • Heißt das jetzt, ich kann 64-bit Integers verwenden, allerdings werden diese bei 32-bit Betriebssystemen vom Prozessor als 2 32-bit Integers behandelt?
    Somit werden 64-bit Integers auf 64-bit Betriebssytemen schneller verarbeitet als auf 32-bit Betriebssystemen, egal ob die Hardware 64-bit unterstützt?

    Falls ich das falsch interpretiert habe, erübrigt sich die Frage, ob man auf 64-bit Hardware mit 32-bit Betriebssystem nicht doch irgendwie direkt mit 64-bit Integers arbeiten kann (mit irgendwelchen Extensions, wie bei OpenGL Hardwarefeatures genutzt werden können).

    Noch eine Frage: Können übliche Prozessoren mehr Funktionen, als in C++ vorhanden sind? Wenn ja, wie kann ich diese verwenden (z.B. würde ich mir eine hardwareunterstützte Suche nach dem niederwertigsten Bit, das 1 ist, wünschen)?


  • Mod

    Senfti schrieb:

    Heißt das jetzt, ich kann 64-bit Integers verwenden, allerdings werden diese bei 32-bit Betriebssystemen vom Prozessor als 2 32-bit Integers behandelt?
    Somit werden 64-bit Integers auf 64-bit Betriebssytemen schneller verarbeitet als auf 32-bit Betriebssystemen, egal ob die Hardware 64-bit unterstützt?

    Ja, natürlich, wie sollte das sonst gehen? Wenn das Programm so geschrieben ist, dass es seine 64-Bit Zahlen in 2-32-Bit Rechenschritten verarbeitet, dann ist es egal, was die Hardware könnte. Das Programm sagt der Hardware, was wie getan wird, nicht umgekehrt. Und wenn das Programm davon ausgeht, dass die Hardware nur 32 Bit gleichzeitig kann, dann werden eben nur 32 Bit gleichzeitig benutzt.

    Falls ich das falsch interpretiert habe, erübrigt sich die Frage, ob man auf 64-bit Hardware mit 32-bit Betriebssystem nicht doch irgendwie direkt mit 64-bit Integers arbeiten kann (mit irgendwelchen Extensions, wie bei OpenGL Hardwarefeatures genutzt werden können).

    Nein, kann man nicht.

    Noch eine Frage: Können übliche Prozessoren mehr Funktionen, als in C++ vorhanden sind? Wenn ja, wie kann ich diese verwenden (z.B. würde ich mir eine hardwareunterstützte Suche nach dem niederwertigsten Bit, das 1 ist, wünschen)?

    C++ kennt gar keine Prozessorfunktionen. Die kennt der Compiler. Und der kennt in der Regel alle, die du ihn kennen lässt. Wenn du ein Programm so compilierst, dass es auch auf einem 386er laufen könnte (was bei 32-Bit Programmen die Regel ist), dann wird eben nur Code erzeugt, der die Funktionen eines 386ers nutzt. Wenn du sagst, dass er auch SSE4.2-Funktionen benutzen darf, dann wird ein Compiler, der aktuell genug ist diese zu kennen, sie auch nutzen, wo es etwas bringt*. Dann läuft das Programm eben nur auf den allerneuesten Intelprozessoren.

    Falls du meinst, es besser zu können als dein Compiler (was durchaus sein kann, falls man als Programmierer den vollen Durchblick hat) oder falls dein Compiler zu alt ist, dann gibt es auch die Möglichkeit, selber in Assembler Code vorzugeben oder besser: Spezielle Bibliotheken zu nutzen, die diese CPU-Features gezielt anbieten (zu erhalten bei den Prozessorherstellern, z.B. die Intels Math Kernel Library). Die sind in der Regel nichts für Anfänger (siehe obiger Kommentar über den Durchblick).

    Erwarte auch nicht zu viel von solchen Funktionen. Die Anwendungsszenarien sind recht speziell, es bringt sehr viel wenn man sehr oft die gleichen einfachen Operationen unabhängig auf eine riesige Menge gleichartiger Daten anwendet. Die meisten Programme tun dies nicht! Dann wird das Programm sogar langsamer, wenn man sich in den Kopf gesetzt hat, unbedingt diese Features nutzen zu wollen.

    *: Genauer: Wo der Compiler denkst, dass es was bringt. Siehe auch die Erklärungen in den letzten beiden Absätzen über den Durchblick und darüber, was passiert, wenn man keinen Durchblick hat. Ich habe schon oft erlebt, dass der Compiler langsameren Code baut, wenn man ihm SSE&Co. erlaubt.



  • SeppJ schrieb:

    Senfti schrieb:

    Heißt das jetzt, ich kann 64-bit Integers verwenden, allerdings werden diese bei 32-bit Betriebssystemen vom Prozessor als 2 32-bit Integers behandelt?
    Somit werden 64-bit Integers auf 64-bit Betriebssytemen schneller verarbeitet als auf 32-bit Betriebssystemen, egal ob die Hardware 64-bit unterstützt?

    Ja, natürlich, wie sollte das sonst gehen? Wenn das Programm so geschrieben ist, dass es seine 64-Bit Zahlen in 2-32-Bit Rechenschritten verarbeitet, dann ist es egal, was die Hardware könnte. Das Programm sagt der Hardware, was wie getan wird, nicht umgekehrt. Und wenn das Programm davon ausgeht, dass die Hardware nur 32 Bit gleichzeitig kann, dann werden eben nur 32 Bit gleichzeitig benutzt.

    Man könnte vermutlich SSE oder SSE2 oder sowas verwenden - da gibt's ja ausreichend grosse Register.
    Tun die Compiler aber glaube ich nicht, nichtmal wenn man SSE/SSE2 Support explizit aufdreht.


  • Mod

    hustbaer schrieb:

    Man könnte vermutlich SSE oder SSE2 oder sowas verwenden - da gibt's ja ausreichend grosse Register.
    Tun die Compiler aber glaube ich nicht, nichtmal wenn man SSE/SSE2 Support explizit aufdreht.

    SSE1, was es auch in reinen 32-Bit Prozessoren gibt, kann nur mit 32-Bit Zahlen rechnen. Kann man von 32-Bit Code aus SSE2 und höher benutzen?



  • SeppJ schrieb:

    hustbaer schrieb:

    Man könnte vermutlich SSE oder SSE2 oder sowas verwenden - da gibt's ja ausreichend grosse Register.
    Tun die Compiler aber glaube ich nicht, nichtmal wenn man SSE/SSE2 Support explizit aufdreht.

    SSE1, was es auch in reinen 32-Bit Prozessoren gibt, kann nur mit 32-Bit Zahlen rechnen. Kann man von 32-Bit Code aus SSE2 und höher benutzen?

    Nein, laut

    http://en.wikipedia.org/wiki/SSE2 schrieb:

    AMD's implementation of SSE2 on the AMD64 (x86-64) platform includes an additional eight registers, doubling the total number to 16 (XMM0 through XMM15). These additional registers are only visible when running in 64-bit mode.



  • Die zusätzlichen acht Register sind im 32-Bit-Modus nicht nutzbar. Die acht ursprünglichen m.W. durchaus.



  • Caligulaminus schrieb:

    Die zusätzlichen acht Register sind im 32-Bit-Modus nicht nutzbar. Die acht ursprünglichen m.W. durchaus.

    Heute ist nicht mein Tag, geh auf Tauchstation *blubblub*



  • @SeppJ:
    Naja... nachdem der 32 Bit Compiler vom MSVC nen /arch:SSE2 Switch hat, gehe ich mal davon aus dass es auch auf 32 Bit CPUs funktioniert.

    Und 64 Bit Integer Befehle gibt's bei SSE2 laut MSDN wohl auch.
    Müsste man fast doch mal ausprobieren was MSVC mit /arch:SSE2 für Code ausspuckt...

    EDIT: OK, erster schneller Test negativ: MSVC 2008/2010 verwenden trotz /arch:SSE2 Switch statt SSE2 lieber 32 Bit Registerpaare und die dadurch nötigen mit-der-Kirche-ums-Kreuz Multiplikationen und Divisionen.



  • Hab ein wenig rumgebastelt und eine Schleife mit SSE-Funktion und eine normale verwendet:

    for(int i=0;i<20000000;i++){
    	f[i] = _mm_andnot_si128(d[i],e);	
    }
    for(int i=0;i<20000000;i++){
    	c[i] = a[i] & (!b);
    	c2[i] = a2[i] & (!b2);
    }
    

    Eigentlich sollte die obere Schleife deutlich schneller sein, aber mit aktivierter Codeoptimierung ist sogar die untere schneller.
    Auch ändert sich nichts, wenn ich SSE2 aktiviere/deaktiviere



  • Müsste das nicht eher so heissen?

    for(int i=0;i<20000000;i++){
        c[i] = (~a[i]) & b;
        c2[i] = (~a2[i]) & b2;
    }
    


  • Danke hustbaer, so ist´s besser. Muss mich wieder an die Bitoperatoren gewöhnen 😉

    Am Ergebnis hat das aber nicht wahnsinnig viel geändert, statt ~10% langsamer ist die SSE-Version jetzt ~10% schneller. Das ist immer noch nicht das, was ich mir erwartet habe.


  • Mod

    Deswegen sag ich ja: Erwarte nicht zu viel. Die Compiler sind in der Regel schon ziemlich gut. Falls du z.B. das obige Programm für 64-Bit compiliert hast, dann werden möglicherweise auch automatisch SSE2-Befehle erzeugt (hier dürfte der Compiler erkennen, dass sich das lohnen könnte), da alle 64-Bit Prozessoren SSE2 können.



  • Heißt das jetzt, die SSE2-Befehle sind nicht viele schneller oder sie werden vom Compiler einfach nicht erzeugt?
    Falls zweiteres, wieso kann ich dann in Visual C++ SSE2 aktivieren, wenn es nicht verwendet wird?
    Von SSE2-Unterstützung kann ich bei meinem Programm sowieso ausgehen, da ich auch das wesentlich jüngere OpenGL 3 benötige.



  • Senfti schrieb:

    Heißt das jetzt, die SSE2-Befehle sind nicht viele schneller oder sie werden vom Compiler einfach nicht erzeugt?

    Die sind je nach Anwendungsfall ordentlich schneller, und werden auch erzeugt. Nur dass MSVC eben nicht perfekt ist, und viele Fälle wo man SSE2 (sinnvoll) anwenden könnte nicht "kann".

    Von SSE2-Unterstützung kann ich bei meinem Programm sowieso ausgehen, da ich auch das wesentlich jüngere OpenGL 3 benötige.

    Naja... OGL 3 Support ist abhängig von der Grafikkarte und deren Treiber, SSE2 ist abhängig von der CPU.
    Das eine hängt also nicht (direkt) mit dem anderen zusammen.

    Wobei die Chance einen z.B. Pentium III (letzter Pentium ohne SSE2) in Kombination mit einer OGL 3 fähigen Grafikkarte anzutreffen wohl relativ kein sein wird.


Anmelden zum Antworten