Datenstruktur für Matrizen
-
TomasRiker schrieb:
Inline all suitable, Full Optimization
...
wird nicht geinlined,dann machst du etwas bei deinen settings falsch
int main() { 00401930 sub esp,8 00401933 push esi float v1, v2; scanf("a %f\n",&v1); 00401934 mov esi,dword ptr [__imp__scanf (4020B0h)] 0040193A lea eax,[esp+4] 0040193E push eax 0040193F push offset type_info::`vftable'+2Ch (40212Ch) 00401944 call esi scanf("b %f\n",&v2); 00401946 lea ecx,[esp+10h] 0040194A push ecx 0040194B push offset type_info::`vftable'+34h (402134h) 00401950 call esi Adder<float> adder(v1, v2); printf("%f\n",adder.add()); 00401952 movss xmm0,dword ptr [esp+14h] 00401958 movss xmm1,dword ptr [esp+18h] 0040195E add esp,10h 00401961 movaps xmm3,xmm0 00401964 mov eax,2 00401969 pop esi 0040196A lea ebx,[ebx] 00401970 sub eax,1 00401973 movaps xmm2,xmm1 00401976 subss xmm2,xmm3 0040197A mulss xmm2,xmm0 0040197E addss xmm2,xmm3 00401982 movaps xmm3,xmm1 00401985 subss xmm3,xmm2 00401989 mulss xmm3,xmm0 0040198D addss xmm3,xmm2 00401991 movaps xmm2,xmm1 00401994 subss xmm2,xmm3 00401998 mulss xmm2,xmm0 0040199C addss xmm2,xmm3 004019A0 movaps xmm3,xmm1 004019A3 subss xmm3,xmm2 004019A7 mulss xmm3,xmm0 004019AB addss xmm3,xmm2 004019AF movaps xmm2,xmm1 004019B2 subss xmm2,xmm3 004019B6 mulss xmm2,xmm0 004019BA addss xmm2,xmm3 004019BE movaps xmm3,xmm1 004019C1 subss xmm3,xmm2 004019C5 mulss xmm3,xmm0 004019C9 addss xmm3,xmm2 004019CD movaps xmm2,xmm1 004019D0 subss xmm2,xmm3 004019D4 mulss xmm2,xmm0 004019D8 addss xmm2,xmm3 004019DC movaps xmm3,xmm1 004019DF subss xmm3,xmm2 004019E3 mulss xmm3,xmm0 004019E7 addss xmm3,xmm2 004019EB jne main+40h (401970h) 004019ED sub esp,8 004019F0 cvtss2sd xmm0,xmm3 004019F4 movsd mmword ptr [esp],xmm0 004019F9 push offset type_info::`vftable'+3Ch (40213Ch) 004019FE call dword ptr [__imp__printf (4020A8h)] return 0; 00401A04 xor eax,eax }template<typename T> T Adder<T>::add() const { return v1 + v2; }Warum sollte der Compiler auch einen Unterschied machen?
tja, wieso macht er das? steck doch mal deine templates in ein header in nutze sie testweise paar mal... geht... und mach das gleiche nun ohne templates... ploetzlich gibt es mehrere definitionen der selben funktion und es geht nicht mehr... templates werden lokal in jedes .o (oder .bin bei vc++) neu erstellt, das kannst du nicht verhindern, der code wird zwangsweise groesser und bei normalen optimierungsoptionen wird das auch immer in-place gemacht.
Ein Template ist doch einfach nur eine Vorlage. Daraus erzeugt er eine Klasse und die kompiliert er so wie eine normale Klasse auch.
nicht ganz, ein template ist quasi annonym (der linker muss nichts von dessen existenz wissen) und wird von vielen compilern einfach in den code gepatcht. selbst ewig lange funktionen stopft dir der compiler in-place rein und wenn du die 100 mal machst, dann packt er dir die auch so oft rein und manche compiler hoeren dann nie auf zu compilieren (woertlich) statt einfach nen call zu machen was in jeglicher hinsicht besser waere.
-
... und nun ersetz mal die Template-Klasse durch eine normale Klasse, wo float statt T drinsteht. Es kommt derselbe Code raus. Ebenfalls alles inline reingeklatscht.
Mit SSE inlined er, ohne SSE nicht.
Also zeig du mir doch bitte mal ein Beispiel, wo er die Methode einer Template-Klasse anders inlined als die Methode der äquivalenten normalen Klasse.
-
rapso schrieb:
geht um das resultierende binary. das liegt daran das alles unnuetzerweise immer geinlined wird. wenn du also etwas aufwendiges machst wie z.b. die inverse einer matrix44 (oder selbst ne multiplikation davon), dann wird das ueberall direkt in den code eingebracht, das macht die binary sehr viel groesser als noetig und kann am ende langsammere programme bedeuten. manche nutzen templates auch explizit um z.b. loop unrolling zu machen weil sie das mal irgendwo mitbekommen haben wie das geht, dann wird auch oft viel unperformanter code generiert z.b. wird die branch prediction eventuell viel effizienter genutzt falls man eine bedingung drinnen hat ohne unrolling.
das tykische ist ja leider das viele meinen durch templates irgendwas schneller/besser gemacht zu haben obwohl es richtig gebenchmarkt dann das gegenteil ist. doch leider ist das oft etwas was ohne benchmarks am anfang vorweg genommen wird und als tatsache eklaert wird. normalerweise lernt jeder juniorprogrammer dass erst der code stehen muss und dann die optimierungen kommen, doch hinsichtlich templates scheint diese philosophie oft zu versagen.
Und wie soll man das umgehen? Weil du schreibst ja oben was von "Anfänger-Gott ...".
Ist doch erstmal das Prinzip von Templates, dass in jeder o Datei eine entsprechende "Template-Instanz" erzeugt wird. Wie soll man das verhindern?
Ok inline kann man weglassen, in eurem Disput scheint das ja ne Compiler-Optimierung zu sein, dass er ohne inline Schlüsselwort trotzdem inlined.
Aber im Allgemeinen?
-
TomasRiker schrieb:
... und nun ersetz mal die Template-Klasse durch eine normale Klasse, wo float statt T drinsteht. Es kommt derselbe Code raus. Ebenfalls alles inline reingeklatscht.
ja genau das war mein beispiel im letzten absatz. wie gesagt, kann er das in zwei implementierungsdateien dann nicht mehr verwenden weil normale implementierungen nicht mehr annonym sind, es compiliert also nicht mal.
Mit SSE inlined er, ohne SSE nicht.
wie gesagt, mit den optimierungen die bei jedem spiel dabei sind.
Also zeig du mir doch bitte mal ein Beispiel, wo er die Methode einer Template-Klasse anders inlined als die Methode der äquivalenten normalen Klasse.
s.o.
-
Pellaeon schrieb:
Und wie soll man das umgehen? ...
indem man erst optimiert wenn der code steht und stabil ist.
-
@rapso:
Es ging doch darum: Du hast gesagt, Methoden von Template-Klassen würden immer inline aufgerufen. Soll dein Beispiel das jetzt widerlegen, oder wie?
Ich habe testweise die Adder<T> und eine FloatAdder (normale Klasse mit float) genommen. Egal, welche Einstellungen ich nehme: Beide werden gleich geinlined. Wenn er eine Methode bei Adder<T> inlined, dann tut er es auch bei FloatAdder und umgekehrt.
-
TomasRiker schrieb:
@rapso:
Es ging doch darum: Du hast gesagt, Methoden von Template-Klassen würden immer inline aufgerufen. Soll dein Beispiel das jetzt widerlegen, oder wie?das war der beweis um deine behauptung zu wiederlegen dass templateklassen genau wie normale klassen behandelt werden.
Ich habe testweise die Adder<T> und eine FloatAdder (normale Klasse mit float) genommen. Egal, welche Einstellungen ich nehme: Beide werden gleich geinlined. Wenn er eine Methode bei Adder<T> inlined, dann tut er es auch bei FloatAdder und umgekehrt.
ja, du hast vollkommen recht.
-
Dein Argument, dass die Template-Klassen pro Objektdatei instanziert werden, ist natürlich auch korrekt.
Das macht die Objektdateien größer.Angenommen wir haben zwei CPP-Dateien A.cpp und B.cpp, die beide jeweils die Template-Klasse Adder<float> benutzen. In A.obj und B.obj ist nach dem Kompilieren jeweils der ganze Code von Adder<float> drin. Natürlich, das ist nicht sonderlich schön.
Wenn jetzt der Linker kommt und A.obj und B.obj zu einer EXE zusammenlinkt, dann wird er aber doch nur die erste Instanzierung der Klasse nehmen und die andere verwerfen - oder nicht??
-
Wenn ich gewusst hätte was meine Frage für Folgen hat....

-
Tja, das musst du jetzt ausbaden

Ist doch egal, man lernt immer was ...
-
Raspo wenn deine Einwände berechtigt wären dürfte man in Template-Klasse keine statischen Variablen benutzen.
Gilt auch für Template-Funktionen (in Template-Klassen) mit statischen Variablen.
Der Linker kann (muss es in oben genanntem Fall sogar) Duplikate durchaus erkennen.
Edit:
Das Inlining-Problem ist dadurch natürlich nicht behoben. Dazu muss man wie von David gezeigt den Compiler schon zwingen es nicht immer zu inlinen (wobei ich auch schon Funktionen in Template-Klassen direkt reingeschrieben habe und diese nicht geinlined worden).Wie gut der VC Linker Strippen kann müsste man mal testen.
-
TomasRiker schrieb:
Wenn jetzt der Linker kommt und A.obj und B.obj zu einer EXE zusammenlinkt, dann wird er aber doch nur die erste Instanzierung der Klasse nehmen und die andere verwerfen - oder nicht??
der punkt ist (und mehr hab ich nicht behauptet) dass leute ohne es zu wissen trotzdem irgendwelche behauptungen aufstellen z.b. wird (nicht) geinlined... inlined ist schneller/langsammer und glauben ohne es je geprueft zu haben, was irgendjemand anders irgendwo irgendwie gehoert oder gelesen hat ueber templates.
das resultiert darin dass (im gegensatz zu normalen klassen) das binary aufblaeht und am ende langsammer ist.
du hast es hier den evolutionsschritt gut gezeigt

nur leider die meisten anderen nicht. Ich behaupte nicht dass templates zu verteufeln sind, ich nutze sie selber seit vielen jahren und sage lediglich dass anfaenger damit mehr schlechtes als gutes anstellen.
-
Warst du denn nicht auch einer derjenigen, der ohne es zu wissen eine Behauptung aufgestellt hat?

Ansonsten denke ich, können wir es dabei belassen und haben alle was gelernt ...
-
TomasRiker schrieb:
Warst du denn nicht auch einer derjenigen, der ohne es zu wissen eine Behauptung aufgestellt hat?

dio mio, No.
-
Äh, sagtest du denn nicht, dass Methoden von Template-Klassen immer inline aufgerufen würden?
Das könnte man ja denken, wenn man davon ausgeht, dass man Template-Klassen immer direkt an einem Stück mit allen Methoden angeben muss. Muss man aber nicht. Und dann macht es bei der Frage "inline oder nicht?" keinen Unterschied, ob es sich um eine Template-Methode handelt oder um eine normale.
-
Hier gibt's auch ne interessante Diskussion über Templates, Inlining und Code-Bloating:
Klick
-
TomasRiker schrieb:
Äh, sagtest du denn nicht, dass Methoden von Template-Klassen immer inline aufgerufen würden?
nein, ich sprach von templates und wie du oben am unterschied von klasse/template gesehen hast, wird das auch so gemacht. da ich deswegen schon 70MB binaries gesehen habe spreche ich auch nicht aufgrund von glauben/vermutung, sondern erfahrung.
-
Bin auch Befürworter von Vector<T, N> und Matrix<T, N, M>.
Btw.:
Darf man mal fragen ob ihr auch Color<N> oder sogar Color<T, N> habt ?
Vielleicht braucht man ja mal irgendwann eine Farbwert mit 5 oder 6 Channels ^^Könnte man nicht sogar die VertexFormate schön mit MPL hinbiegen? Um OnTheFly mit Typedefs sein eigenes VertexFormat definieren zu können.
-
Pyr0kar schrieb:
Darf man mal fragen ob ihr auch Color<N> oder sogar Color<T, N> habt ?

wieso nicht vector<T> dafuer nehmen?
-
Ja, ich habe für Farben ebenfalls das Vektor-Template genommen. Das war mitunter auch der Grund, warum ich das Template überhaupt erstellt habe - 2D-Vektoren für Texturkoordinaten, 3D für 3D halt
und 4D u.a. für RGBA.