Willkommen ~Gast!
Registrieren || Einloggen || Hilfe/FAQ || Staff
Probleme mit der Registrierung im Forum? Melde dich unter registerEin Bild.
Autor Beitrag
000
07.01.2002, 22:19
Tron



ich hab mit eine einfache Image-klasse geschrieben, die BMPs (fuer texturen in OpenGL) laden kann

Quellcode:class
{
..public:
....Image();
....~Iamge();

....Load(const Char*);
..../* ... */
..private:
....eFormat mFormat;
....UInt mWidth;
....UInt mHeight;
....UByte* mData;
....UByte* mPalette;
};

Image::Image() :
..mFormat(NONE)
..mWidth(0);
..mHeight(0);
..mData(NULL);
..mPalette(NULL);
{}

jetzt habe ich mal den assemblercode des constructors angeschaut: (mit parameter -S kompiliert)
;
; mFormat (NONE),
;
mov edx,dword ptr [ebp+8]
xor ecx,ecx
mov dword ptr [edx],ecx
;
; mWidth (0),
;
mov eax,dword ptr [ebp+8]
xor edx,edx
mov dword ptr [eax+4],edx
;
; mHeight (0),
;
mov ecx,dword ptr [ebp+8]
xor eax,eax
mov dword ptr [ecx+8],eax
;
; mData (NULL),
;
mov edx,dword ptr [ebp+8]
xor ecx,ecx
mov dword ptr [edx+12],ecx
;
; mPalette(NULL)
;
mov eax,dword ptr [ebp+8]
xor edx,edx
mov dword ptr [eax+16],edx

vor allem DAS machte mich stutzig: mov edx,dword ptr [ebp+8]
d.h. es wird bei JEDER zuweisung this erneut in ein register geladen...

auch das aender des codes auf
Quellcode:
Image::Image()
{
..mFormat = NONE;
..mWidth = 0;
..mHeight = 0;
..mData = NULL;
..mPalette = NULL;
}

anederte nichts.

erst als ich den code auf
{
..Image* Self = this;
..Self->mFormat = NONE;
..Self->mWidth = 0;
..Self->mHeight = 0;
..Self->mData = NULL;
..Self->mPalette = NULL;
}
veraenderte wurde es 'normal', also this einmal ein ein register und fertig:
;
; Image* Self = this;
;
mov eax,dword ptr [ebp+8]
;
; Self->mFormat = NONE;
;
?live16385@48: ; EAX = Self
xor edx,edx
mov dword ptr [eax],edx
;
; Self->mWidth = 0;
;
xor ecx,ecx
mov dword ptr [eax+4],ecx
;
; Self->mHeight = 0;
;
xor edx,edx
mov dword ptr [eax+8],edx
;
; Self->mData = NULL;
;
xor ecx,ecx
mov dword ptr [eax+12],ecx
;
; Self->mPalette = NULL;
;
xor edx,edx
mov dword ptr [eax+16],edx

was ich auch recht seltsam finde ist, dass fuer jede variable die auf 0 gesetzt wird extra ein register geXORt wird...

ich hab' saemtliche optimierungsoptionen ausprobiert...
ich kann mir kaum vorstellen, dass die borland-compiler-entwickler dermasen doof sind, hat jemand dafuer eine erklaerung?!

--

'KEINE PANIK' - aus der Triologie in fuenf Baenden von Douglas Adams

'FÜR DEINN FERD' - aus 'Gevatter Tod' von Terry Pratchett

zum Seitenanfang zum Seitenende Profil || Suche
001
09.01.2002, 16:35
Prefect



Manche Compiler deaktivieren automatisch alle Optimierungen, wenn du Debuginformationen mit reinkompilierst (da ansonsten Code in der Gegend rumverschoben würde usw.). Vielleicht ist das dein Problem.

cu,
Prefect

--

Widelands - Gemütliche Aufbaustrategie, Free Software
Noch ein Blog - Lerne, wie die Welt wirklich ist, aber vergiss niemals, wie sie sein sollte.

zum Seitenanfang zum Seitenende Profil || Suche
002
10.01.2002, 22:59
CY4N1D3



*delete*

--

ob nun delphi, c oder java. kein programm lässt sich mit allen 3en gleichschnell entwickeln.


Dieser Beitrag wurde am 10.01.2002 um 22:59 von CY4N1D3 bearbeitet.
zum Seitenanfang zum Seitenende Profil || Suche
003
11.01.2002, 18:28
LePrau



Das mit dem XORen ist ganz einfach:
Um eine Variable auf 0 zu setzen ist MOV erforderlich,
MOV verbrät jedoch mindestens 8 Zyklen. (Es muss ja der feste Wert aus dem RAM geholt werden, was Zeit kostet)

Logisch ist auch das

FF XOR FF = 0
16 XOR 16 = 0 usw. da sich die jeweiligen Bits gegenseitig auslöschen.

Da bei XOR ax zweimal auf ein Prozessorregister zugegriffen wird, muss man nicht auf das RAM zugreifen und somit kostet XOR (nach meinen Informationen) nur 2 Zyklen.

Man sieht also: Geschwindigkeitsverhältnis von 1:4 oder sogar noch besser.
Eine simple Oprimierung, die einen jedoch sehr verwirren kann.
Wie man die Optimierungen konkret deaktivieren kann, weiß ich nun leider nicht, bin aber überzeugt dass das über eine Compilerdirektive in {...-} / {...+} Manier zu regeln ist. Such einfach mal in der Hilfe nach der Beschreibung der Compilerdirektiven.

--

voice - Ruhe in Frieden

zum Seitenanfang zum Seitenende Profil || Suche
004
11.01.2002, 21:51
Tron



das mit dem xor ist mir schon klar, aber so sinnlose sachen wie:
mov edx,dword ptr [ebp+8]
xor ecx,ecx
mov dword ptr [edx],ecx
mov eax,dword ptr [ebp+8]
xor edx,edx
mov dword ptr [eax+4],edx

sowohl ecx als auch edx wird auf 0 gesetzt und so geht es grade weiter!
im konstruktor werden 5 variablen auf 0 gesetzt und es werden dafuer 5 mal register gexort, aber nur einmal ist noetig!
und ich habe jede optimierung angeschaltet, die der compiler bietet.
was mich ja auch noch stoert ist, dass im konstruktor vor dem zugriff auf einen member JEDESMAL der this-zeiger aus dem ram in ein register geladen wird. (in meinem beispiel ist das: mov edx,dword ptr [ebp+8])
was ich herausgefunden habe: wenn ich den konstruktor inline mache wird nur einmal der this-zeiger geladen und bei jeder normalen methode (ausser konstruktor) wird der this-zeiger auch nur einmal geladen, nur beim konstruktor bei jedem member-zugriff extra.

das raff' ich net warum?! wenn ich das von hand geschreiben haette, wuerde ich es so machen:
mov edx,dword ptr [ebp+8]
xor ecx,ecx
mov dword ptr [edx],ecx
mov dword ptr [edx+4],ecx

ok, bei nem konstruktor von einer klasse fuer bilder ist das nicht so dramatisch, aber z.b. bei einer klasse fuer nen vektor, da wird der konstruktor etlich tausendmal benutzt!

--

'KEINE PANIK' - aus der Triologie in fuenf Baenden von Douglas Adams

'FÜR DEINN FERD' - aus 'Gevatter Tod' von Terry Pratchett

zum Seitenanfang zum Seitenende Profil || Suche
005
12.01.2002, 13:48
Prefect



Hast du meinen Post gelesen (bzgl. Debug-Compiles)?

Übrigens verbraucht mov nicht unbedingt 8 Cycles. In diesem Fall wäre z.B. die Cacheline bei [ebp+8] im internen Prozessorcache (nicht L1, sondern der Cache direkt an der ALU). Trotzdem ist das natürlich behindertertstes Compilerverhalten.

cu,
Prefect

--

Widelands - Gemütliche Aufbaustrategie, Free Software
Noch ein Blog - Lerne, wie die Welt wirklich ist, aber vergiss niemals, wie sie sein sollte.

zum Seitenanfang zum Seitenende Profil || Suche
006
12.01.2002, 19:05
Tron



jo, habe ich gelesen, ich kompilier mal normal (mit allen optimierungen) und schau mir mal das produkt mit dem turbo debugger an; wenn das dann immernoch so ne katastrophe ist, dann gute nacht vater...aeh...borland

--

'KEINE PANIK' - aus der Triologie in fuenf Baenden von Douglas Adams

'FÜR DEINN FERD' - aus 'Gevatter Tod' von Terry Pratchett

zum Seitenanfang zum Seitenende Profil || Suche
007
16.01.2002, 16:33
Tron



ahhh... GANZ langsam bekomm ich plack!

ich habe folgende problemstellung:
meine kameraklasse hat eine funktion, die den forwaersvektor zurueckgibt, das tut sie, indem sie aus der transformationsmatrix die stellen 8, 9 und 10 (matrix nach opengl-konvention) ausliest und diese als einen vektor zurueckgibt:

inline Vector Camera::Forward() const
{
..return
....Vector
....(
......mTransformation[8],
......mTransformation[9],
......mTransformation[10],
....);
}

jetzt will ich diesen vektor in einen neuen reintun, also:
Camera Cam;
Vector Vec(Cam.Forward);

so... dann schauen wir mal was der gute compiler daraus macht...
mov edx,dword ptr [esp+116]
mov dword ptr [esp],edx
mov ecx,dword ptr [esp+112]
mov dword ptr [esp+4],ecx
mov eax,dword ptr [esp+108]
mov dword ptr [esp+8],eax
mov edx,dword ptr [esp+8]
mov dword ptr [esp+200],edx
mov ecx,dword ptr [esp+4]
mov dword ptr [esp+204],ecx
mov eax,dword ptr [esp]
mov dword ptr [esp+208],eax
mov edx,dword ptr [esp+200]
mov dword ptr [esp+188],edx
mov ecx,dword ptr [esp+204]
mov dword ptr [esp+192],ecx
mov eax,dword ptr [esp+208]
mov dword ptr [esp+196],eax

AAAAHHHHHH!!! der schiebt das durch 2 (!!!) temporaere objekte durch! das ist ja totaler stumpfsinn!

ich hab auch eine methode gefunden, mit der er es direkt geht, ohne ein einziges temporaeres objekt, das sieht in asm dann so aus:

mov edx,dword ptr [ebp-80]
mov dword ptr [ebp-188],edx
mov ecx,dword ptr [ebp-76]
mov dword ptr [ebp-184],ecx
mov eax,dword ptr [ebp-72]
mov dword ptr [ebp-180],eax

und so sieht der code dazu aus:

inline const Vector& Camera::Forward() const
{
return *((const Vector*)(&mTransformation[8]));
}

tja, es funktionert, blos ist diese methode UEBELSTER hack! reinterpret_cast halt... grrrrrr
und das funktionert auch nur, wenn ich nen vektor will, der senkrecht in der matrix drinsteht, einer der quer drin ist (braucht man fuer billboarding) bekommt man damit nicht, da hier die elemente nicht hintereinander im speicher liegen. (also elemente 0, 4, 8 z.b.)

ich hab' mal etwas rumprobiert und dieses problem ergibt sich generell fuer folgende konstellation:

klasse f()
{
return klasse(parameter);
}

obj = f();

im detail:
erzeugen eines anonymen objektes: ein sinnloses temporaeres objekt
dieses zurueckgeben als wert (als referenz geht ja auch schlecht...) : ein weiteres sinnloses temporaeres objekt

die daten werden folglich von den parametern in das erste objekt kopiert, dann in das zweite und schlieslich in das zielobjekt.
egal ob ich den automtischen copy-konstruktor verwende oder einen eigenen schreibe.

hat jemand ne idee wie man das eleganter hinbekommt?

ps: ich hab's auch mit kompilieren direkt zu 'ner exe und dann mit turbodebugger angucken probiert, anstatt mit in assembler kompilieren: das ergebnis ist genau das gleiche

--

'KEINE PANIK' - aus der Triologie in fuenf Baenden von Douglas Adams

'FÜR DEINN FERD' - aus 'Gevatter Tod' von Terry Pratchett

zum Seitenanfang zum Seitenende Profil || Suche
008
22.01.2002, 16:59
Tron



so, ich habe mein matrix-vektor-kopier-problem (post 007) geloest: anderer compiler! MinGW rult!

statt diesem stuss: (borland)
mov edx,dword ptr [esp+116]
mov dword ptr [esp],edx
mov ecx,dword ptr [esp+112]
mov dword ptr [esp+4],ecx
mov eax,dword ptr [esp+108]
mov dword ptr [esp+8],eax
mov edx,dword ptr [esp+8]
mov dword ptr [esp+200],edx
mov ecx,dword ptr [esp+4]
mov dword ptr [esp+204],ecx
mov eax,dword ptr [esp]
mov dword ptr [esp+208],eax
mov edx,dword ptr [esp+200]
mov dword ptr [esp+188],edx
mov ecx,dword ptr [esp+204]
mov dword ptr [esp+192],ecx
mov eax,dword ptr [esp+208]
mov dword ptr [esp+196],eax

erzeugt es diese krass optimierte sequenz: (MinGW)
flds -80(%ebp)
flds -76(%ebp)
flds -72(%ebp)
fxch %st(2)
fstps -208(%ebp)
fstps -204(%ebp)
fstps -200(%ebp)

oder in 'normalem' assembler:
fld [ebp-80]
fld [ebp-76]
fld [ebp-72]
fxch st2
fstp [ebp-208]
fstp [ebp-204]
fstp [ebp-200]

das ist wohl die optimalloesung, da hier sequentielles lesen und schreiben von RAM voll ausgenuetzt wird.

--

'KEINE PANIK' - aus der Triologie in fuenf Baenden von Douglas Adams

'FÜR DEINN FERD' - aus 'Gevatter Tod' von Terry Pratchett

zum Seitenanfang zum Seitenende Profil || Suche