Perfomance



  • @raspo
    Da hast du sicher recht, dass man das ins Endlose ziehen könnte

    @kane
    FPU-ASM??



  • Mit ASM die FPU programmieren


  • Mod

    wenn du es besser machst als ein compiler, dann ja!

    rapso->greets();



  • Tja, und woher weiß ich (bevor ich meine base_math.h in asm schreibe) das
    ich das besser kann?
    Ich habe gehört, das bestimmt Operationen in C++ nicht besonders so effizient
    implementiert sind wie möglich, da sie irgendeinem Standard erfüllen müssen.



  • AJ schrieb:

    @0x1
    Ist bei deinem Beispiel die zweite Schleife nicht langsamer??

    Sind wohl Messfehler... vielleicht hab ich ja die Maus bewegt oder Outlook hat den Posteingang geprüft. Ich würde sagen beides ist gleichschnell.

    @rapso:
    Der Tipp um das Vorzeichen eines floats festzustellen ist super. Hätte man eigentlich selbst drauf kommen können. Werd ich gleich mal überall einbauen....



  • um es nochmal zu sagen, man kann nicht wirklich generele Performance Tipps geben! Das hängt konkret von deiner Anwendung ab. Wenn du siehst, dass eine Funktion eben besonders oft aufgerufen wird, kannst du sie dir angucken und dort optimieren. zB. kannst du jenachdem dort SIMD Code einfügen oder ähnliches.

    Natürlich gibt es schon einige Dinge zu beachten, dass man eben je nachdem Call-by-value vermeidet, wenn man const Referenzen übergeben/zurückgeben kann. Obwohl das in einigen Fällen die Lage sogar verschlimmern kann!

    Das mit dem Postfix/Prefix ++/-- Operator war früher bei den Compilern wichtig. Bei C++ ist das bei Klassen wichtig, wo der Operator überladen ist, weil da der Compiler nicht mehr optimieren kann, weil er ja nicht weiss, was die Funktion intern macht (bei inline kann das aber natürlich wieder anders sein!). Deswegen ist es schon keine schlechte Taktik sich die Benutzung des Prefix-Opertors anzugewöhnen, genauso wie Lieber <lvalue> <op>= <rvalue> Anstelle <lvalue> = <lvalue> <op> <rvalue>

    Aber wie gesagt, wirklich optimieren kann man nur, wenn man einen konkreten Code hat und den schön mit dem Profiler analysieren kann.


  • Mod

    kingruedi schrieb:

    Bei C++ ist das bei Klassen wichtig, wo der Operator überladen ist, weil da der Compiler nicht mehr optimieren kann, weil er ja nicht weiss, was die Funktion intern macht

    außer bei virtuellen funktionen macht der compiler genau das, das ist eine optimierung die schon seit sehr langem im intel compiler ist und im .Net compiler von m$ und die gnu leute sind da sicherlich nicht hinten dran und haben das drinne.
    (damit will ich nicht klugscheissen sondern lediglich darauf hinweisen)

    rapso->greets();



  • sicher das die Compiler das machen? Ich meine der Compiler ahnt ja nicht, was der Prefix oder Postfix Operator macht. Es kann ja sein, dass der Prefix Operator irgend welche anderen Aktionen durchführt (natürlich idr. nicht zu empfehlen, weil es schlecht zu lesen ist :)). Darf der Compiler da einfach reinfummeln?



  • Nö, das darf er ganz sicher nicht. Denn beim Postfix ++ wird ja eine Kopie erzeugt, und mein Programm darf davon abhängen, daß genau diese Kopie auch erzeugt wird, ob sie jetzt gebraucht wird oder nicht...
    Deshalb muß er da die Finger rauslassen und daher ist es sinnvoll prefix ++ postifx++ vorzuziehen.


  • Mod

    also mein compiler optimiert das weg, wenn die kopie nichts macht... der optimiert auch alles unnötige weg, wenn man z.b. ein kreuzprodukt zweier vektoren macht und nur das erste element weiter verwendet, dann berechnet der die restlichen elemente nicht, obwohl das in der vektor-class gekapselt ist, und unabhängig davon wo es benutzt wird, berechnet werden sollte.

    ist aber auch länger her, dass ich die beiden ++ sachen verglich und es spricht ja garnichts gegen ++c;

    rapso->greets();



  • Welcher Compiler ist das?
    Welche Ausgabe erzeugt er bei folgendem Code?

    #include <iostream>
    #include <fstream>
    #include <sstream>
    #include <iomanip>
    #include "stdafx.h"
    
    class CountCopy
    {
    public:
      static int Copies() { return Copies_; }
      static void Clear() { Copies_ = 0; }
      CountCopy() { ++Copies_; }
      CountCopy(const CountCopy & c) { blub = c.blub; ++Copies_; }
    
      const CountCopy & operator++ ()    { ++blub; return *this; } 
      const CountCopy   operator++ (int) { CountCopy tmp(*this); ++*this; return tmp; }
    private:
      int blub;
      static int Copies_;
    };
    
    int CountCopy::Copies_;
    
    int main()
    {
      using namespace std;
      CountCopy c;
      ++c;
      cout << "Prefix: " <<CountCopy::Copies() << endl;
      CountCopy::Clear();
      c++;
      cout << "Postfix: " <<CountCopy::Copies() << endl;
      cin.get();
    }
    


  • Achja, und auch wenn ich die Konstruktoren auskommentiere und ein CopyCount anlege, einmal mit Prefix und eine Version mit Postfix inkrementiere gibts verschiedene Exe-Files.


  • Mod

    rapso schrieb:

    also mein compiler optimiert das weg, wenn die kopie nichts macht...

    dein beispiel wühlt im konstruktor auf statics rum, da kann man nichts wegoptimieren... jeder optimiert sachen weg, wenn man es darf, darauf sind auch compiler gebaut. wenn ein objeckt erstellt wird und nichts macht, dann darf es wegoptimiert werden und das machen manche kompiler. *doppelmoppel*

    wenn etwas "wegoptimiert" werden würde, was ein anderes verhalten hervorruft, ist es keine optimierung mehr sondern ein bug... darüber müssen wir uns erst garnicht unterhalten 😉

    aber in vielen fällen ist post und pre das gleiche, da muss man sich keinen kopf drüber machen beim optimieren und falls nicht, weil man etwas im konstruktor macht, wass auswirkungen auf das ganze programm hat (siehe dein beispiel), dann wird man ja wohl selbst bei jedem ++ nachdenken welches man verwenden möchte/muss, je nachdem was man bezweckt.

    rapso->greets();



  • Jo klar, aber sogar ohne selbstdefinierte Konstruktoren
    ist der generierte Code von

    class CopyCount
    {
    // wie eben, nur ohne eigenen CopyConstr., dafür mit GetBlub
    }

    int main()
    {
    CopyCount c;
    ++c;
    cout << "Blub: " << c.GetBlub();

    }

    nicht der gleiche, wie wenn ich c++ anstelle von ++c schreibe...

    welchen Compiler verwendest Du denn?


  • Mod

    nein, der code ist sicherlich nicht der gleiche, soll er ja auch nicht, er soll optimiert werden, dabei ist die regel, das optimalste ist das was man nicht machen muss wohl die erste die aufgestellt wurde :).

    wenn du sowas wie z.B. for(int a=0;a<pAutoPark->getCount();a++) benutzt und der compiler merkt, dass in der funcktion getCount(); immer der selbe wert zurückgegeben werden wird, wird er den aufruf eventuell wegoptimieren, VC6 hat da noch probleme und deswegen kann man dort Aliasing ein und ausschalten, denn manchmal ändert sich da doch ein kleiner wert aber die schelife bekommt das nicht mit... das zu debuggen sass ich mal fast nen tag... nur ne compiler option.

    ich benutze, wie weiter oben erwähnt, den intel und den m$.Net compiler, der intel hat als erstes global optimiert (also in andere cpp geschaut ob sich noch mehr optimieren oder inlinen lässt).
    wenn man normalerweise eine leere function in dem header deklariert bzw im cpp definiert, wird sie angesprungen, weil sich kompiler normalerweise nur die header anschauen. der intel hat dagegen auch in die cpp geschaut um constanten wegzuoptimieren oder dinge zu inlinen.

    das gibt's bei denen bestimmt auch in papern nachzusehen.

    rapso->greets();



  • Am meisten Performance holt man IMMER beim Algorithmus heraus. Deshalb bin ich jetzt grad auf der Suche nach einem Profiler für VS.Net *such*
    Ihr könnt mir gerne auch ein paar Tipps geben, wo ich suchen muss 😉

    Oder kosten die was?



  • CodeAnalyst von AMD ist 4free.
    Sonst schau dir mal VTune von Intel an.
    Du könntest aber auch mal die Gnu utilities hernehmen wie gprof usw. Nur ob die mit dem output von VC was anfangen können ist eine andere Frage


Anmelden zum Antworten