ich hab noch ein paar performance fragen bezüglich C++.
Zur info, hier geht es mehr oder weniger um millisekunden, bzw noch weniger.. aber in meinem fall ist jede millisekunde wichtig!
1)
Ich habe eine funktion die eine Farbe (ein Struct aus 4 Floats) zurückliefern muß. Diese wird mehrere millionen mal aufgerufen, etwa so:
Code:
CColor doSomething() {
CColor result;
result = something();
retur result;
}
[....]
CColor c;
for (int i = 0; i < 10000000; i++)
c += doSomething();
Ist es da ein geschwindigkeits unterschied wenn ich das ganze so umstelle?
Code:
void doSomething(CColor &c) {
c = something();
}
[....]
CColor c, x;
for (int i = 0; i < 10000000; i++) {
doSomething(x);
c += x;
}
Sprich, macht es einen geschwindigkeits unterschied ob ich in jedem funktionsaufruf eine neue CColor erstelle oder eine übernehme die ich als reference-parameter bekomme? Oder optimiert der compiler das eh weg?
2) Macht es einen geschwindigkeitsunterschied ob ich einer funktion parameter als referenz oder als pointer übergebe?
Code:
void doSomething(CColor &c) {
c.bla();
}
oder:
Code:
void doSomething(CColor *c) {
c->bla();
}
3) Ähnlich wie erstens, ist hier ein unterschied?
Code:
CColor x;
for (int i = 0; i < 10000; i++) {
CColor c = bla();
x += c;
}
und:
Code:
CColor x, c;
for (int i = 0; i < 10000; i++) {
c = bla();
x += c;
}
Das ich hier nicht diret "x += bla()" mache liegt nur am beispiel, es geht nur um das erstellen eines neuen color-objekts in der for-schleife.. oder wird das sowieso wegoptimiert?
Registriert: Di Jul 01, 2003 18:59 Beiträge: 887 Wohnort: (The Netherlands)
Programmiersprache: fpc/delphi/java/c#
Could you benchmark it? And does not c++ (or at least the gnu version) have an option where you can set the optimisation level. Also i believe you are able to target i386 vs i686 even that could have impact.
zu 1) Die zweite Variante ist schneller. Speicher reservieren ist eine relative langsame Operation.
Noch schneller wäre es aber,, wenn du die Funktion doSomething() als inline definieren würdest. Sofern du die Funktion nirgendwo sonst (oder nur an wenigen Stellen) benutzt kann der Compiler den gesamten Funktionsaufruf weg optimieren.
Folgendes wäre vielleicht auch noch eine Alternative:
Code:
CColor doSomething() {
return something();
}
zu 2) Referenz dürfte schneller sein. Vermutlich optimiert der Compiler das sowieso.
zu 3) Wie bei erstens, Speicher reservieren dauert. Vermutlich optimiert der Compiler aber auch hier.
Allgemein: Viel wichtiger als solche Kleinigkeiten ist aber, dass du einen für deinen Zweck optimalen Algorithmus wählst! Also überlege ob du es irgendwie vermeiden kannst diese Operation millionenmal auszuführen. Klassisches Beispiel sind Sortieralgorithmen. Wenn du da naiv ran gehst wirst du entweder Insertion-Sort, Selection-Sort oder Bubble-Sort implementieren. Das sind die drei Algorithmen auf die man ohne viel nachdenken kommt. Diese Algortihmen haben eine Laufzeit von O(n*n), du brauchst also um 10.000 Zahlen zu sortieren 100 Mio. Operationen. Setzt man etwas mehr Grips ein implementiert man dann vielleicht den Quicksort-Algorithmus, Merge-Sort oder vielleicht auch Intro-Sort. Diese haben eine erwartete Laufzeit von O(n*log(n)). Bei 10.000 Zahlen brauchst du also nur etwa 130.000 Operationen.
Registriert: Do Sep 02, 2004 19:42 Beiträge: 4158
Programmiersprache: FreePascal, C++
Da es gerade bei C mehrere durchaus verschiedene Compiler gibt, würde ich mich nicht allein auf die optimierung verlassen, sondern erstmal versuchen, ohne irgendwelche Optimierungen das beste rauszuholen.
zu 1: Ich stimme mit Coolcat überein, ich würde da ein Inline versuchen.
zu 2: Ich kenne jetzt den Unterschied bei C zwischen Referenz und Pointer nicht... Müsste das nicht das gleich sein? Ein Pointer ist doch ein Verweis, eine Referenz, auf einen Speicherbereich?
zu 3: Im worst case muss er den Stack da bei jedem Schleifendurchlauf erhöhen und senken, sowie das Objekt reinlegen. Ich würde sagen, du solltest bei der Variante bleiben, wo du das außerhalb deklarierst.
Gruß Lord Horazont
_________________ If you find any deadlinks, please send me a notification – Wenn du tote Links findest, sende mir eine Benachrichtigung. current projects: ManiacLab; aioxmpp zombofant network • my photostream „Writing code is like writing poetry“ - source unknown
„Give a man a fish, and you feed him for a day. Teach a man to fish and you feed him for a lifetime. “ ~ A Chinese Proverb
zu 2: Ich kenne jetzt den Unterschied bei C zwischen Referenz und Pointer nicht... Müsste das nicht das gleich sein? Ein Pointer ist doch ein Verweis, eine Referenz, auf einen Speicherbereich?
Bei einer Referenz kann der Compiler optimieren. Eine Referenz ist einfach nur ein Aliasname. Er greift einfach direkt auf die referenzierte Speicherstelle zu ohne erst den Pointer zu lesen und die entsprechende Speicherstelle zu suchen.
bestätigt das was ich mir schon gedacht hatte Wollte nur sicher gehen.
Coolcat hat geschrieben:
Allgemein: Viel wichtiger als solche Kleinigkeiten ist aber, dass du einen für deinen Zweck optimalen Algorithmus wählst! Also überlege ob du es irgendwie vermeiden kannst diese Operation millionenmal auszuführen. Klassisches Beispiel sind Sortieralgorithmen. Wenn du da naiv ran gehst wirst du entweder Insertion-Sort, Selection-Sort oder Bubble-Sort implementieren. Das sind die drei Algorithmen auf die man ohne viel nachdenken kommt. Diese Algortihmen haben eine Laufzeit von O(n*n), du brauchst also um 10.000 Zahlen zu sortieren 100 Mio. Operationen. Setzt man etwas mehr Grips ein implementiert man dann vielleicht den Quicksort-Algorithmus, Merge-Sort oder vielleicht auch Intro-Sort. Diese haben eine erwartete Laufzeit von O(n*log(n)). Bei 10.000 Zahlen brauchst du also nur etwa 130.000 Operationen.
Das ist klar Bei mir geht's hier grad um einen Software Rasterizer, und im speziellen um die shader-fuktionen.
Es ging auch "nur" darum den code von 15ms pro frame auf noch weniger runter zu bekommen. Bin jetzt bei 8ms pro Frame (bei 800x600 mit ca. 20.000 Triangles die etwa 2/3tel des bildes füllen)
Registriert: Do Sep 02, 2004 19:42 Beiträge: 4158
Programmiersprache: FreePascal, C++
Dann solltest du auf jeden fall auch mal in die verschiedenen Assembleranweisungen für das gleichzeitige (wirklich gleichzeitig) bearbeiten von drei oder vier Floats mit einer Rechenoperation. Dürfte für Vektoren und Farben, speziell Blending, Gold beziehnungsweise Millisekunden wert sein.
Gruß Lord Horazont
_________________ If you find any deadlinks, please send me a notification – Wenn du tote Links findest, sende mir eine Benachrichtigung. current projects: ManiacLab; aioxmpp zombofant network • my photostream „Writing code is like writing poetry“ - source unknown
„Give a man a fish, and you feed him for a day. Teach a man to fish and you feed him for a lifetime. “ ~ A Chinese Proverb
Dann solltest du auf jeden fall auch mal in die verschiedenen Assembleranweisungen für das gleichzeitige (wirklich gleichzeitig) bearbeiten von drei oder vier Floats mit einer Rechenoperation. Dürfte für Vektoren und Farben, speziell Blending, Gold beziehnungsweise Millisekunden wert sein.
Gruß Lord Horazont
Huh? Davon hör ich zum ersten mal, magst du das kurz etwas genauer erklären?
das ganze mit SSE hat nochmal ordentlich was gebracht Man muß nur erstmal drauf kommen das man das nicht in einem union benutzen darf, da sonst wieder performance verloren geht :p
Hab jetzt allerdings erstmal nur meine Color4f-Klasse umgestellt, für die Vector3f-Klasse wäre es eigentlich auch perfekt, allerdings frage ich mich hier ob es lohnt..
Ich müßte bei jeder rechnung die ich mache dann ein neues objekt von __m128 (die 128bit variable von SSE) erstellen und da die ersten 3 floats auf meine werte setzen, dann wieder zurücklesen etc... die frage wäre ob das dann noch schneller ist als einfach die floats von hand zusammen zurechnen (geht ja nur um operationen wie +, -, * und /)..
Dem Vektor einfach nen vierten float wert (w) dazu zu geben geht aus vielen anderen gründen nicht
Color4f Klasse? Kannst du die mal zeigen? Am besten auch, was du jetzt genau mit SSE gemacht hast.
Umh, das ist bei mir die "chaotischte" klasse. Mein ziel war es beliebig viele farb-kanäle (auch mehr als nur RGBA) und verschiedene datentypen (float, double, unsigned char etc) zu unterstüzen.. Das ganze ist dadurch zu einem ziemlich komplexen template konstrukt geworden.
Im grundprinzip kann die Klasse aber auch nicht mehr als farb-daten halten (im normalfall RGB(A) in float) und bietet halt die standard rechenoperationen für farben (+, -, *, /, +=, -=, *=, /= etc) als überladene operatoren.
Durch das multi-channel prinzip mußte ich früher z.B. bei der Color4f bei der multiplikation soetwas schreiben:
Code:
CIColor4f r;
for (int i = 0; i < numChannels(); i++) // numChannels() wird bei Color4f durch einen Templateparameter festgelegt.
r[i] = channel[i] + otherColor[i];
return r;
Jetzt nach der umstellung auf SSE habe ich einfach für Color4f das template spezialisiert und als datentyp folgendes verwendet:
Code:
struct CIColorChannelsSSEFloatData {
__m128 sse;
float& operator[](unsigned int i) {
return ((float*)&sse)[i];
}
float* getPointer() {
return (float*)&sse;
}
};
durch den [] operator und getPointer() bleibe ich kompatibel zu meinen anderen Farb-Formaten. (z.B. um sie in OpenGL zu benutzen: glColor4fv(myColor.getPointer()); bzw wird das auch von meiner klasse gehandhabt -> myColor.bind(); (natürlich inline)
so, und um jetzt 2 Farben via SSE zu multiplizieren:
PS: Das ist übrigens wieder einer der Momente wo ich froh darüber bin auf C++ umgestiegen zu sein.
Ich programmiere den Rasterizer mehr oder weniger Parallel mit nem Freund (er in Java), sprich wir benutzen für den Rasterizer die gleichen algorithmen etc... wir haben es auch bei ihm schon bist zum geht nicht mehr optimiert, aber meine C++ lösung läuft etwa doppelt so schnell wie seins in Java (die reine renderzeit, ohne darstellung etc gemessen).
Registriert: Do Dez 05, 2002 10:35 Beiträge: 4234 Wohnort: Dortmund
Weißt du in welchem "Modus" SSE bei dir arbeitet? SSE hat 2 Funktionen zum Laden von Daten in ein XMM Register. Eine für 16 Byte Alligned Daten und eine für nicht Aligned Daten. Die für 16 Byte Aligned ist ein gutes Stück schneller als die Andere. Also wenn du da eine Möglichkeit hast so etwas irgendwie einzustellen, dann solltest du davon Gebrauch machen.
Mitglieder in diesem Forum: 0 Mitglieder und 4 Gäste
Du darfst keine neuen Themen in diesem Forum erstellen. Du darfst keine Antworten zu Themen in diesem Forum erstellen. Du darfst deine Beiträge in diesem Forum nicht ändern. Du darfst deine Beiträge in diesem Forum nicht löschen. Du darfst keine Dateianhänge in diesem Forum erstellen.