ByteOrder umkehren



  • Rock Lobster schrieb:

    EDIT: Ich habe gerade mal mit Digital Mars kompiliert, und da sieht das Ergebnis völlig anders aus. Hier braucht die erste Variante 984 ms und die zweite 1625 ms. Sehr seltsam, ich werd mir mal den Output genauer anschauen... das erste mal habe ich mit Visual C++ 2005 kompiliert.

    Im Release-Mode?

    Heutzutage ist es oftmals naiv anzunehmen, man könne manuell besser optimieren als der Compiler es im Releasemode sowieso tut, deshalb überrascht mich das Ergebnis (Digital Mars) zunächst nicht. Falls Du mit VC++ auch im Releasemode gemessen hast, wundert mich eher, dass der da nicht besser optimiert.


  • Mod

    Traurig, das sowas kein Einzelfall ist.
    Falls du unbedingt ein "schnelles swap" brauchst, solltest du dich erst einmal auf die Suche nach entsprechenden Primitiven des Compilers machen - inline assembler ist hier alles andere als optimal - und das nicht wegen der fehlenden Portabilität.
    Visual C++ etwa bietet die _byteswap_* Funktionen an, die auch eine intrinsische Form haben.



  • camper schrieb:

    Visual C++ etwa bietet die _byteswap_* Funktionen an, die auch eine intrinsische Form haben.

    bswap_* in byteswap.h bei der GNU libc.



  • push eax und pop eax kannste dir sparen. der compiler schert sich bei der funktion eh ned drum. und a landet bei funktionsende sowieso in eax.

    int swap2(int i)
    {
        __asm
        {
            mov eax, i
            bswap eax
            mov i, eax
        }
    
        return i;
    }
    

    für maximale performance schreib dir noch passende pro- und epilog und mach die funktion 'naked' mit

    __declspec(naked) int swap2(int i)
    

    thread sollte vielleicht nach rudp verschoben werden?


  • Mod

    cpt. obvious schrieb:

    push eax und pop eax kannste dir sparen. der compiler schert sich bei der funktion eh ned drum. und a landet bei funktionsende sowieso in eax.

    int swap2(int i)
    {
        __asm
        {
            mov eax, i
            bswap eax
            mov i, eax
        }
       
        return i;
    }
    

    dann gleich richtig

    inline unsigned swap2(unsigned i)
    {
        __asm mov eax, i
        __asm bswap eax
    }
    

    cpt. obvious schrieb:

    für maximale performance schreib dir noch passende pro- und epilog und mach die funktion 'naked' mit

    __declspec(naked) int swap2(int i)
    

    Was in der Praxis den gegenteiligen Effekt haben dürfte, weil der Compiler nicht mehr inline-Expandieren kann. Schließlich ruft man so ein Funktion in der Regel nicht indirekt über einen Pointer auf.



  • camper schrieb:

    dann gleich richtig

    inline unsigned swap2(unsigned i)
    {
        __asm mov eax, i
        __asm bswap eax
    }
    

    ok, ich dachte das return wäre unbedingt notwendig. als ich das letzte mal inline-asm geschrieben hab ging das so noch nicht, afair.

    Was in der Praxis den gegenteiligen Effekt haben dürfte, weil der Compiler nicht mehr inline-Expandieren kann. Schließlich ruft man so ein Funktion in der Regel nicht indirekt über einen Pointer auf.

    hm, könnte was dran sein. einen versuch wärs trotzdem mal wert, insbesondere wenn er mit komischen compilern hantiert.



  • Naja rein vom Aufruf waren beide Versionen ja gleichberechtigt, und nur was intern ablief, war anders. Der Output sieht bei VC und bei DC ebenfalls recht ähnlich aus, also erstmal vom Umfang her, aber auch die eigentlichen Befehle unterscheiden sich kaum. Ich kann nachher aber gerne mal den tatsächlichen Assembler-Output posten. Eigentlich hab ich beides auch im Release-Modus kompiliert, da ich von Hand über die Console kompiliert habe, ohne /DEBUG oder so etwas zu setzen.

    Werde aber nachher nochmal ein wenig rumfrickeln.

    Das mit "naked" kapier ich nicht so ganz (bin auch kein C++-Guru), was genau bewirkt das? Und noch eine schnelle Frage, geht "inline" nur in Klassen oder auch in normalen C-Funktionen? Ich habe neulich den Fall gehabt, daß ich eine Funktion nicht inlinen konnte, aber das bisher nicht näher verfolgt. Es war eine normale C-Funktion in einem extern ("C")-Block.

    EDIT: Das push/pop hatte ich drin, weil ich zunächst davon ausging, daß vielleicht vor dem Call etwas wichtiges im eax stehen könnte - beim Call müßte aber sowieso vorher alles gepusht werden, kann das sein?



  • Rock Lobster schrieb:

    Und noch eine schnelle Frage, geht "inline" nur in Klassen oder auch in normalen C-Funktionen? Ich habe neulich den Fall gehabt, daß ich eine Funktion nicht inlinen konnte, aber das bisher nicht näher verfolgt. Es war eine normale C-Funktion in einem extern ("C")-Block.

    Jede Funktion kann (sowohl auf Anforderung als auch aus eigener Kraft) inline gesetzt werden, solange einige Randbedingungen an die Komplexität (Schleifen und Rekursionen sind ungünstig) erfüllt werden - und der Compiler den Quellcode der Funktion sehen kann.

    (d.h. wenn du eine Funktion im CPP inline definierst, ist sie außerhalb dieser Übersetzungseinheit nicht erreichbar)



  • Ahh gut dann weiß ich woran es lag. Ich hatte eine tools.cpp und eine tools.h, und in der .h wurden die Funktionen einfach nur in einem extern ("C")-Block definiert, und dann in der .cpp implementiert. In dem Fall wird mir wohl nichts anderes übrig bleiben, als die Funktionen direkt in der .h zu implementieren, liege ich da richtig (kann's grad hier nicht testen)?



  • Rock Lobster schrieb:

    Das mit "naked" kapier ich nicht so ganz (bin auch kein C++-Guru), was genau bewirkt das?

    der compiler generiert keinen ein- und austrittscode für diese funktion, sondern verlässt sich darauf das du das tust. du bist also selbst dafür verantwortlich, argumente vom stack zu holen und was sonst noch so zu tun ist.
    http://msdn2.microsoft.com/en-us/library/5f7adz6y(VS.80).aspx
    das ist auch der grund, warum der compiler dann nicht mehr inlinen kann - er hat keine kontrolle mehr über den ein- und austrittscode (der beim inlinen entfallen muss)

    EDIT: Das push/pop hatte ich drin, weil ich zunächst davon ausging, daß vielleicht vor dem Call etwas wichtiges im eax stehen könnte - beim Call müßte aber sowieso vorher alles gepusht werden, kann das sein?

    siehe oben. in deinem fall steht halt nix wichtiges in eax, die funktion tut ja quasi nix. du solltest die registerbelegungsregeln deines compiler mal nachschlagen, wenn es die gibt und es dich interessiert.


Anmelden zum Antworten