Welche Abfrage ist schneller?


  • Mod

    TNA schrieb:

    Also meiner Erfahrung nach optimieren Compiler sehr viel komplexere Sachen insbesondere bei Logik ausdrücken. x < 2 sollte auch bei allen mir bekannten Architekturen mit einem Maschinenbefehl abbildbar sein. was soll man da noch besser machen können?

    Tatsache. Der GCC 4.8 macht beides zu einem Vergleich auf < 2. 👍

    edit: Bei genaueren Tests kommt es auch noch da drauf an, wie die Schleife genau abgerollt wird. Manchmal kommt dann < 2, manchmal > 1.



  • Mein SV11 macht daraus >=2 und >1 .

    000000013F91170C  cmp         eax,2  
    000000013F91170F  jae         main+36h (013F911716h)
    

    vs.

    000000013F91172D  cmp         eax,1  
    000000013F911730  ja          main+57h (013F911737h)
    


  • Hm. Wenn der Compiler aus beiden Abfragen das selbe optimiert, ist es egal. Fast. Natürlich ist x < 2 besser, da weniger komplex.

    Ich dachte eigentlich daran, ob die eine Abfrage mehr Taktzyklen beansprucht als die andere, ohne Optimierung des Compilers. Also so wie es da steht direkt als Assembler.


  • Mod

    kralo9 schrieb:

    Ich dachte eigentlich daran, ob die eine Abfrage mehr Taktzyklen beansprucht als die andere, ohne Optimierung des Compilers. Also so wie es da steht direkt als Assembler.

    Unwahrscheinlich dass das zweite schneller ist, aber theoretisch vorstellbar. Wird, wie schon gesagt, stark von den Eingabedaten abhängen.



  • kralo9 schrieb:

    Also so wie es da steht direkt als Assembler.

    Kommt natürlich auf die Architektur an. In der Regel sind alle Vergleisoperationen gleich schnell und die zweite Variante würde bei einer 1:1 Abbildung mindestens zwei statt einem benötigen, wovon der zweite aber je nach Fall ausgelassen werden könnte. Also je nach Eingabedaten bestenfalls gleichschnell.

    Die Lehre aus diesem Fall ist aber ohnehin: Schreib verständlichen, problemnahen Code und las den Compiler machen. Der weiß im Zweifelsfall besser als du (und ich), was schneller ist.



  • Weil wir grad dabei sind...

    Was ist schneller, ein "branch taken" oder ein "branch not taken"?
    Also sollte man bedingte Sprungbefehle so schreiben dass meistens gesprungen wird, oder so dass meistens nicht gesprungen wird?

    Wenn die Branch-Prediction richtig tippt würde ich annehmen dass "nicht gesprungen" schneller sein müsste -- weil die ganze Pipeline dabei ohne Änderung weitermachen kann. D.h. wenn es in dem Fall überhaupt einen Unterschied macht.

    Aber trifft das auch zu wenn die Branch-Prediction den Sprungbefehl noch nicht kennt?
    Gibt es da ne Richtwert der bei den meisten CPUs passt?



  • hustbaer schrieb:

    Aber trifft das auch zu wenn die Branch-Prediction den Sprungbefehl noch nicht kennt?

    Andererseits ist diese Mikro-Optimierung gerade an dieser Stelle dann mit großer Wahrscheinlichkeit auch irrelevant.



  • hustbaer schrieb:

    Weil wir grad dabei sind...

    Was ist schneller, ein "branch taken" oder ein "branch not taken"?
    Also sollte man bedingte Sprungbefehle so schreiben dass meistens gesprungen wird, oder so dass meistens nicht gesprungen wird?

    Wenn die Branch-Prediction richtig tippt würde ich annehmen dass "nicht gesprungen" schneller sein müsste -- weil die ganze Pipeline dabei ohne Änderung weitermachen kann. D.h. wenn es in dem Fall überhaupt einen Unterschied macht.

    Aber trifft das auch zu wenn die Branch-Prediction den Sprungbefehl noch nicht kennt?
    Gibt es da ne Richtwert der bei den meisten CPUs passt?

    Das ist ein komplexes Thema. Zuerst muss man hier zwischen "Branch taken" im C++ Code und im daraus generierten Maschienencode unterscheiden. Das muss nämlich nicht identisch sein. Der Compiler kann das in der Regel umdrehen, wenn er es für sinnvoll hält. Auf Maschienenebene ist es meistens so, dass beim ersten Durchlauf, also praktisch immer außerhalb von Schleifen, vom "Branch not taken" Fall ausgegangen wird. Es gibt aber Architekturen wie z.B. beim PowerPC bei dem man in den Branchinstruktionen angeben kann, welcher Fall warscheilicher ist. Dafür muss der Compiler natürlich entscheiden, welchen Fall er für warscheinlicher hält. Compiler haben aber darüber hinaus oft noch Möglichkeiten schon auf höherer, maschinenunabhängiger Ebene, Optimierung zu machen, die einen der beiden Pfade bevorzugen. Oft kann der Compiler schon recht gut aus dem Programm erkennen, Welcher Pfad wahrscheinlicher ist. Manchmal allerdings auch nicht. Bei GCC schein es tatsächlich so zu sein, das er zumindest bei if ohne Else, den if-Fall für unwarscheinlicher hält. Aber auch dem kann man das mit __builtin_expect vorschreiben, wenn man sich für schlauer als der Compiler hält.



  • Wenn ich mich recht erinnere, ist es egal.
    Der Prosessor macht seine Sprungvorhersage und lädt den laut Sprungvorherage nächsten Befehl in die Pipeline, egal ob der direkt dem JMP folgt oder woanders steht, fürs Woandersgucken hat er genug Zeit.

    Optimieren kann man in kleinen Schleifen nur fürs erste Auftauchen, wenn die Sprungvorhersagetabelle noch leer ist. Und natürlich für selten laufenden Code, da ist sie immer wieder leer.

    Wenn ich mich recht erinnere, ist die Defaultbelegung der Sprungvorhersage dann:
    Sprünge nach unten werden als unwahrscheinlich angenommen, also typischerweise der überspringbare if-zweig bevorzugt.
    Sprünge nach oben werden als Wahrscheinlich angenommen, also typischerweise die bedingte Schleifenwiederholung.



  • @TNA
    Ja, mir ist klar dass der "if" Zweig in C++ nicht unbedingt zum "branch taken" in Assembler wird. Und auch nicht umgekehrt. Sondern so wie der Compiler meint dass es schlau ist.

    Die Möglichkeit anzugeben was man für wahrscheinlicher hält ist natürlich Top. Das macht Sinn. Dumm nur dass die momentan interessanteste Architektur (=x64) es nicht kann.

    @all
    Mir ist auch klar dass die Unterschiede vermutlich nicht SO krass reinhauen werden. Mich interessiert das rein "akademisch" 🙂
    (Ich würde nie im Traum daran denken bei sowas von Hand zu optmieren anzufangen.)



  • hustbaer schrieb:

    Die Möglichkeit anzugeben was man für wahrscheinlicher hält ist natürlich Top. Das macht Sinn. Dumm nur dass die momentan interessanteste Architektur (=x64) es nicht kann.

    Quelle?


Anmelden zum Antworten