PDA

View Full Version : C++-Optimierungen


MarianSchedenig
16-05-2004, 18:16
Macht es eigentlich Sinn, oft aufgerufene Methoden als inline zu deklarieren? Hätte mir da einen merklichen Geschwindigkeitsunterschied erwartet (hunderte Vektor-Methodenaufrufe pro Frame), aber wirklich gemerkt hab ich bisher nix.

Nachteilig wirkt sich allerdings aus, daß ich jetzt Unmengen von Code in den .h-Files drin hab, was erstens schirch und unübersichtlich ist und zweitens natürlich das Compilieren enorm verlangsamt.

(Zum Einsatz kommt g++ mit -O3)

Wolfibolfi
16-05-2004, 18:54
Naja, vielleicht wird der Code dadurch zu lang, wenn das Zeug an hundert verschiedenen Stellen vorkommt. Könnte sein, dass der Cache der CPU dann mehr Misses produziert. Eventuell bleibt der Code der nicht-inline-Funktion die ganze Zeit im Cache, und es gleicht sich wieder aus.
*imZuckerRauschSchweb*
Kann sein, dass ich nur Blödsinn faseln tu. :devil:

Peter
16-05-2004, 19:20
Wolfibolfi hat recht:
inline sollte man nur fuer kleine Methoden mit maximal 2 oder 3 Zeilen verwenden. Wenn man inline uebertrieben verwendet, wird der code zu grosz, was zu cache misses oder page faults fuehren kann. Auf einem PII/400 kostet ein hard page fault 10ms.
Richtig eingesetzt koennen inline-Methoden schon ordentlich optimieren.

MarianSchedenig
16-05-2004, 19:37
Hmm, auch wahr. Kommt davon, wenn man sich über solche Dinge das letzte mal zu C64-/Amiga-Zeiten den Kopf zerbrochen hat. ;)

Werd mir mal genauer anschauen, welche Methoden ich inline will. Thx!

tivolo
17-05-2004, 00:29
hmmm, hab auch mal geglaubt, dass inlinen soviel bringt, bei mir war's dann eher langsamer. und zwar aus den oben genannten gründen. außerdem gibt's neben dem "normalen" inline noch andere (ich glaub MSVC-spezifische) konstrukte, wie z.b. forceinline, da sich der compiler das inlinen manchmal anders überlegt - sprich, er macht eine funktion gar nicht inline, obwohl du's explizit angegeben hast.

wenn du wirklich optimieren willst, dann fang an bestimmte rechenintensive funktionen in assembler zu programmieren.
gutes beispiel: du würdest gar nicht glauben, was man mit einer wurzel- bzw. reziprok-wurzel-approximation alles rausholen kann, sofern sie richtig programmiert ist. da die wurzel-funktion grad im 3D-bereich oft gebraucht wird (länge eines vektors), bringt das meiner erfahrung nach schon einiges, sofern du die funktion auch wirklich oft verwendest.
andere dinge wie ein skalarprodukt z.b. lassen sich mit MMX, SSE und SSE2 auch ordentlich optimieren (ich liebe es, die taktzyklen meines assembler-codes zu zählen :) )

viel spass beim assembler-programmieren,
mfg,
tivolo

MaxAuthority
17-05-2004, 00:33
kann es nicht auch einfach sein, dass der compiler bei -O3 deine funktion teilweise eh schon automatisch inlined und du daher keinen speed-unterschied merkst?

Peter
17-05-2004, 00:47
bei -O3 fuehrt gcc Methoden mit weniger als 600 Instruktionen inline aus, wenn seine Heuristik das so will.

MarianSchedenig
17-05-2004, 03:41
Assembler spielt's nicht...erstens sind meine letzten wirklichen Erfahrungen damit (abgesehen von UBLU) auch noch aus der C64-Zeit, und bis zur letzten Abgabe kann ich das kaum auffrischen. ;) Aber vor allem sollte unser Spiel dank SDL & OpenGL auch auf nicht-Intels laufen... :)

kann es nicht auch einfach sein, dass der compiler bei -O3 deine funktion teilweise eh schon automatisch inlined und du daher keinen speed-unterschied merkst?

Kann ich mir aus folgendem Grund nicht wirklich vorstellen: Wenn die Klassendefinitionen im .h- und die Methoden selbst im .cpp-File sind und ich daraus die .a Library generiere, wird das doch schon übersetzt. Beim Linken mit dem eigentlichen Spielecode sollte es dann doch zu spät sein, da noch was davon inline zu zaubern?

MaxAuthority
17-05-2004, 04:36
<quote>Wenn die Klassendefinitionen im .h- und die Methoden selbst im .cpp-File sind und ich daraus die .a Library generiere, wird das doch schon übersetzt. Beim Linken mit dem eigentlichen Spielecode sollte es dann doch zu spät sein, da noch was davon inline zu zaubern?</quote>

richtig, aber mit was (ausser gcc) generierst du die .a Library? und so gesehen werden eben beim uebersetzen der .cpp files in .a code deine funktionen vom gcc inlined.
Aber ich hab kein Computergrafik2, daher weiss ich leider auch nicht wirklcih, was ihr da genau machen muessts.

MarianSchedenig
17-05-2004, 05:04
richtig, aber mit was (ausser gcc) generierst du die .a Library? und so gesehen werden eben beim uebersetzen der .cpp files in .a code deine funktionen vom gcc inlined.

Ok, innerhalb der Library natürlich schon. Aber die Aufrufe aus dem Programmcode heraus dann halt nicht mehr (die kennen den C-Code der Lib ja nicht mehr)...wobei die meisten relevanten Aufrufe in unserem Fall aber wirklich innerhalb der Lib sind, stimmt schon.

Aber ich hab kein Computergrafik2, daher weiss ich leider auch nicht wirklcih, was ihr da genau machen muessts.

Das mit der Library war unsere eigene Entscheidung...das mit der Forderung einer akzeptablen Geschwindigkeit ist leider Vorgabe. ;)

Wolfibolfi
17-05-2004, 09:14
MMX und SSE Optimieren wär zwar keine schlechte Idee, aber oft findet man im Code noch viel mehr einfacheres Einsparpotential. Zumindest wenn der Code so ein Haufen ist, wie bei mir, da kann man oft Ergebnisse von früher weiterverwenden, erspart sich dadurch Berechnungen. Sinus-Funktionen, die nicht so genau sein müssen, lassen sich mit einer Tabelle auch realisieren, Verwendung von Triangle-Strips statt Triangle-Lists bringt auch was. Aber die Bahn werdet ihr bei Skydoo wohl eh mit Strips modelliert haben, oder?

Chuck
17-05-2004, 11:30
nur ne kleine anmerkung zu strips vs lists... wenn man gewöhnliche triangles in ner caching freundlichen reihenfolge schickt, dann gibts bis auf die größe des index arrays sogut wie keinen nachteil gegenüber strips... (hatte bei unserer terrain engine mal auf strips gewechselt und hatte null geschwindigkeits gewinn).
btw unterstützt der übungsrechner eigentlich sse? hatte mir nämlich auch schon überlegt das gesamte matrix multiplikations zeugs in sse zu schreiben weil das mit ziemlicher sicherheit um einiges schneller sein müsste.

MarianSchedenig
17-05-2004, 14:20
Strips kommen bei uns leider bisher nur in automatisch generierten Datenstrukturen vor, d.h. so gut wie nirgends...die Streckestücke sind transformierte (verzerrte) Milkshape-Models. Würde dort gerne auch auf Strips wechseln, aber mir ist noch schleierhaft, wie ich das anstellen muß. :)

Wollte diesbezüglich aber anders optimieren: Seit gestern Abend (bzw. Nacht, stundenlang einen sehr dummen Fehler gesucht) verwenden alle Models Vertex Arrays bzw. Vertex Buffer Objects. Hatte mir einen Geschwindigkeitsgewinn erhofft, aber das Gegenteil ist der Fall: Mit Display Lists ist die neue Variante bis zu 20 FPS langsamer als das alte Dreieck-für-Dreieck-von-Hand. Ohne Display Lists ist beides mittlerweile absolut unbrauchbar.

Kann mir bisher nur zwei Erklärungen zusammenreimen: 1.) meine Geforce 2 Go hat miserable VBO-Unterstützung (aber zumindest Vertex Arrays sollten dann doch schneller sein) oder 2.) ich hab schon die gesamtem 32 MB Grafikspeicher gefüllt? Jetzt schon?

-> Kann mir wer sagen, wie ich in OpenGL (oder von mir aus auch SDL, in beiden hab ich bisher keine passende Funktion gefunden) das verbleibende Video-RAM ermitteln kann?

Chuck
17-05-2004, 15:27
es gibt in opengl absolut keine möglichkeit den verbleibenden video ram zu erfragen... ist im design nicht vorgesehen (und an und für sich sollte das auch nicht notwendig sein... im endeffekt sollte ohnehin der treiber wissen wo er jetzt seine daten hinkopiert.)

Wolfibolfi
17-05-2004, 17:50
Zu den Strips:
Ist nicht euer Spiel eher Graka-limitiert? Da wärs verständlich, wenns keinen Unterschied macht, ob du Strips oder Lists verwendest. Wenn das Spiel mehr CPU-limitiert ist, könnts schon einen Unterschied machen.
Naja, bei unserer Terrain-Datenstruktur wärs eh nur unnötiger Zusatzaufwand, Lists zu nehmen, auch vom Programmieraufwand her.

Chuck
17-05-2004, 19:42
naja die triangle version war wohl geometrie limitiert (noch bevor irgendwelche füllratenintensive spassetln eingebaut waren)... deshalb hätten strips theoretisch geschwindigkeit bringen müssen, da ja im endeffekt jeder vertex index nur 1 mal geschickt wird und dieser dann auch nur einmal transformiert wird. da heutige grafikkarten allerdings caches für die transformationsergebnisse haben (denke mal so ca 8-16 vertices sind da bereits transformiert gecached) ist es dann genauso schnell, wenn man zwar jeden vertex eines dreieckes einzeln schickt, allerdings bei der reihenfolge darauf achtet, dass möglichst 1 oder 2 punkte des dreiecks bereits im vorigen dreieck verwendet wurden, wodurch die schon im cache liegen und somit nicht neu transformiert werden müssen.

ChrisChiu
18-05-2004, 00:12
<quote>Wenn die Klassendefinitionen im .h- und die Methoden selbst im .cpp-File sind und ich daraus die .a Library generiere, wird das doch schon übersetzt. Beim Linken mit dem eigentlichen Spielecode sollte es dann doch zu spät sein, da noch was davon inline zu zaubern?</quote>

richtig, aber mit was (ausser gcc) generierst du die .a Library? und so gesehen werden eben beim uebersetzen der .cpp files in .a code deine funktionen vom gcc inlined.
Aber ich hab kein Computergrafik2, daher weiss ich leider auch nicht wirklcih, was ihr da genau machen muessts.

Optimieren in diesem Ausmaß "müssen" die Studenten bei CG23 sowieso nicht.

In meiner Erfahrung ist das Assembler-optimieren oder was auch immer meistens nur ein Tropfen auf einem heißen Stein, effektiver wären meistens tatsächliche algorithmische Optimierungen (Visibility Culling und ähnliches) oder Techniken wie Display Lists, Vertex Buffer Objects.

Uebungsleitung
19-05-2004, 12:04
Genau, beschäftigt euch lieber mal mit dem Spiel, Optimierungen nur insofern in der Angabe gefordert (verschiedene Geometrie-Modi) oder es ein Performance-Problem gibt.

Der Vertex-Cache ist in OpenGL allerdings nur in bestimmten Modi aktiv, zum Beispiel wenn man VBO verwendet oder die gldrawrangeelements, da sonst der Treiber ja nicht weiß, woher die vertices kommen...

Michael Wimmer

MarianSchedenig
19-05-2004, 13:54
Techniken wie Display Lists, Vertex Buffer Objects.

Genau das ist das Problem bei uns...Display Lists sind schon lange drin, machen auch einen enormen Unterschied, aber jetzt wird's wieder merklich langsam. Vertex Arrays bringen zur Zeit leider weniger als genau nix, ich verliere dadurch 10-20 FPS (warum versteh ich immer noch nicht)....und die VBOs bringen auf meiner GeForce nix und auf der Radeon schmieren sie ab. *g* Irgendwas muß ich da wieder mal ordentlich übersehen haben. :)