Perfomance
-
Ups stimmt ja, bei Referenzen muss man trotzdem noch die Adresse angeben.
@Junky
Dass int und double Klassen sind, ist mir neu
Was für Methoden haben die denn so zu bieten? Oder haben sie nur Eigenschaften?
-
Ja, streng genommen ist das so. Definiert ist das ganze in den C++ Standard-Libs. Das ist nunmal das Prinzip von C++.
Methoden ? Naja Operatoren gibts natürlich :p +,-,/,* usw.
-
Naja mir solls recht sein
-
kann mal jemand ein konkretes beispiel zeigen?
-
Thema in/dekrementieren:
ob man jetzt ++i oder i++ schreibt ist bei einem guten Compiler egal. Der Msvc++6 zB macht anscheinend automatisch aus einem i++ ein ++i wenn er merkt dass es geht.
Ich habe grade folgenden Test gemacht:
int main(int argc, char* argv[]) { Sleep( 2000 ); unsigned int i; char out[333]; DWORD zeit1, zeit2; zeit1 = GetTickCount( ); for( i=0 ; i<0xffffffff ; i-- ) { i++; f( i ); // Das muss sein, sonst wird die Schleife komplett wegoptimiert i++; } zeit1 = GetTickCount() - zeit1; zeit2 = GetTickCount(); for( i=0 ; i<0xffffffff ; --i ) { ++i; f( i ); ++i; } zeit2 = GetTickCount() - zeit2; itoa( zeit1, out, 10 ); printf( out ); printf( "\n" ); itoa( zeit2, out, 10 ); printf( out ); printf( "\n" ); }
Ausgabe:
55119 55740 Press any key to continue
Der compiler denkt also mit. Ich schreibe aber auch immer ++i, das habe ich mir wegen diesem Gerücht angewöhnt
-
@0x1
Ist bei deinem Beispiel die zweite Schleife nicht langsamer??@bobba
Mir ist noch was eingefallen zum Optimieren der Performance. Du kannst beim Teilen von Zahlen noch einen kleinen Trick anwenden. Wenn du z. B. durch 2 teilst, dann kannst du auch die bits der Zahl einfach um 1 nach rechts verschieben. Das funktioniert natürlich auch beim Multiplizieren mit 2. Das kannst du natürlich auch mit anderen Zahlen machen. Alle potenzierten Zahlen mit der Basis 2. Also 2, 4, 8, 16, 32, ...
Ist hald die Frage, ob das der Compiler nicht eh schon von selber macht, aber ein Versuch ists wert ;).
-
wenn ihr hier alles auflisten wollt, dann werdet ihr nie fertig
fehlt ja noch das casten von float nach int, vergleich von floats als int um das vorzeichen zu prüfen, rechnen mit reciproxen, mehrere variablem in eine stecken um SIMD zu simulieren,fixpoint artihmetik,selbst modifizierender code,die fpu in andere modie umstellen,memory pooling,allignment von klassen...
am wichtigsten könnte sein, dass man seinen compiler in und auswendig kennt, damit man weiß was der am ende auskotzt, dazu sollte man ein wenig assembler können und sich das resultat anschauen, nicht selten dass da etwas total unperformantes rauskommt...
http://www.flipcode.com/tutorials/tut_fastmath.shtml
da kann man sich ein beispiel anschauen.
rapso->greets();
-
Was haltet ihr allgemein von FPU-ASM?
Lohnt sich der Aufwand überhaupt?
-
@raspo
Da hast du sicher recht, dass man das ins Endlose ziehen könnte@kane
FPU-ASM??
-
Mit ASM die FPU programmieren
-
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.
-
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.
-
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.