Funktion in ASM programmieren
-
Ich hoffe ihr könnt mir ein wenig behilflich sein.
ich habe diese Funktion:
inline void Identitiy(D3DMATRIX *mat) { mat->_11 = mat->_22 = mat->_33 = mat->_44 = 1.0f; mat->_12 = mat->_13 = mat->_14 = mat->_41 = 0.0f; mat->_21 = mat->_23 = mat->_24 = mat->_42 = 0.0f; mat->_31 = mat->_32 = mat->_34 = mat->_43 = 0.0f; } //Identitiy
Ich muss diese in ASM für den MSVC(Inline Assembler) umprogrammieren. Hab aber keine Ahnung wie oder wo ich anfangen soll. Ich will auch nicht das mir einer jetzt das alles macht. Es ist ja nicht nur eine Funktion. Könnt ihr mir da etwas behilflich sein? ASM Grundkenntnisse habe ich. So etwas habe ich aber nie gemacht.
-
hab mal was hinbekommen...
funktioniert, aber ich glaube, das koennte man noch schneller machen:p
Hier der code:
inline void Test2( D3DMATRIX *mat ) { _asm { mov eax,dword ptr [mat] fld1 fstp dword ptr [eax+3Ch] mov eax,dword ptr [mat] fld1 fstp dword ptr [eax+28h] mov eax,dword ptr [mat] fld1 fstp dword ptr [eax+14h] mov eax,dword ptr [mat] fld1 fstp dword ptr [eax] mov eax,dword ptr [mat] fldz fstp dword ptr [eax+30h] mov eax,dword ptr [mat] fldz fstp dword ptr [eax+0Ch] mov eax,dword ptr [mat] fldz fstp dword ptr [eax+8] mov eax,dword ptr [mat] fldz fstp dword ptr [eax+4] mov eax,dword ptr [mat] fldz fstp dword ptr [eax+34h] mov eax,dword ptr [mat] fldz fstp dword ptr [eax+1Ch] mov eax,dword ptr [mat] fldz fstp dword ptr [eax+18h] mov eax,dword ptr [mat] fldz fstp dword ptr [eax+10h] mov eax,dword ptr [mat] fldz fstp dword ptr [eax+38h] mov eax,dword ptr [mat] fldz fstp dword ptr [eax+2Ch] mov eax,dword ptr [mat] fldz fstp dword ptr [eax+24h] mov eax,dword ptr [mat] fldz fstp dword ptr [eax+20h] } }
Hat verdammt lange gedauert wehe du beschwerst dich jetzt dann
:p
-
und die in asm programmierte funktion soll schneller sein? ich glaube nicht dass es einen merkbaren unterschied macht...
-
So bins wieder.... (der echte GAST
:p )
@Copie von mir: die erste funktion war nich sonderlich schneller aber die die jetzt kommt lauft doppelt so schnell
hier der code:
inline void Test3( D3DMATRIX *mat ) { _asm { mov eax,dword ptr [mat] fld1 fst dword ptr [eax] fst dword ptr [eax+14h] fst dword ptr [eax+28h] fstp dword ptr [eax+3Ch] mov eax,dword ptr [mat] fldz fst dword ptr [eax+30h] fst dword ptr [eax+0Ch] fst dword ptr [eax+8] fst dword ptr [eax+4] fst dword ptr [eax+34h] fst dword ptr [eax+1Ch] fst dword ptr [eax+18h] fst dword ptr [eax+10h] fst dword ptr [eax+38h] fst dword ptr [eax+2Ch] fst dword ptr [eax+24h] fstp dword ptr [eax+20h] } }
Hab den ganzen unnuetzen kram rausgeschmissen und jetzt lauft sie viel schneller, schneller als jetzt wird man sie auch kaum bekommen!
CYA
-
Danke, das wird mir helfen. Ich beginne gleich den Code zu studieren. Ich muss noch ein paar andere Matrix Funktionen umschreiben. Ist ja erst 24:39 Uhr
-
Ich sehe das keinen Sinn, solche Dinge optimiert der Compiler wahrscheinlich genausogut oder noch besser (obwohl ich <GAST> nicht schlecht machen will ;), der Compiler kann einfach im Zusammenhang besser optimieren, da <GAST> ja nur die eine Funktion kennt). Wahrscheinlich behindert der Assembler Code eher den Compiler beim optimieren.
Du solltest am besten so vorgehen beim optimieren:
-Profiler benutzen und die schlimmen Code stellen finden
-C++ Code versuchen zu optimieren
-Assembler Code betrachten und ggf. optimieren, aber immer die Auswirkung testen, ob der Compiler nicht langsameren Code generiert.
-
Ich bins wieder
@kingruedi: Also die erste version der Funtion hat der compiler fuer mich erstellt, ich habe sie dann fast 100% vom debugger uebernommen als ich mir den asm code anzeigen haben lasse. Selbst der VC++ 6.0 in der Profi edition mit allen optimierungen an hat den code nich sonderlich optimiert.
Die zweite funktion ist zwar etwas schneller aber in der Praxis machen sich die 2-5% auch nich bemerkbar ausser man ruft die Funktion 300000 mal in der sekunde auf. In einem Punkt gebe ich dir aber recht, wozu ueberhaupt den ganzen kram in asm umschreiben das kann der Compiler genauso gut.
Richtig merken tut man asm optimierungen erst, wenn man SIMD befehle wie MMX,SSE oder 3DNow! benutzt da kann man zum teil bis zu 35% an extra Speed rauskitzeln wenn man gut ueberlegt rangeht. Oder was meint ihr dazu ????
BYE BYE
PS: Ich glaube, ich sollte mich mal registrieren lassen.
-
Wieso wird hier eigentlich der FPU benutzt um 1,0 und 0 in den Speicher zu schreiben? Das dauert doch nur unnoetig lange... MMX und SIMD hin oder her, aber IMHO waere hier ein einfaches mov auf jeden Fall schneller als dieses Gewusel mit dem Coprozessor.
-
Gaehn muede sein....
Tha die FPU muss in diesem fall benutzt werden, da in der matrix floating point werte abgespeichert werden. Es wuerde zwar alles mit mov funktionieren nur wuerden die werte verfaelscht herauskommen wenn man :
mov dword ptr [eax],1
schreiben wuerde. Durch die unterschiedliche codierung wuerde es nich hinhauen
oder sagst du etwa ich soll ein integer ohne umrechnung in einer Fließkommazahl speichern ?? ( Sorry bin schon ein wenig muede )
-
AHHHRRG was rede ich denn da, naklar dein ansatz geht und is sogar etwas schneller nach ersten messungen. Wenn man zwei konstanten benutzt und deren werte in register verschiebt, dann geht es auch ohne die FPU zu beanspruchen.
Hier der code (war in 2 sec zusammengehackt):
__forceinline void Test4( D3DMATRIX *mat ) { const float A = 1.0f; const float B = 0.0f; _asm { mov eax,[mat] mov ebx, A mov ecx, B mov [eax],ebx mov [eax+14h],ebx mov [eax+28h],ebx mov [eax+3Ch],ebx mov [eax+30h],ecx mov [eax+0Ch],ecx mov [eax+8],ecx mov [eax+4],ecx mov [eax+34h],ecx mov [eax+1Ch],ecx mov [eax+18h],ecx mov [eax+10h],ecx mov [eax+38h],ecx mov [eax+2Ch],ecx mov [eax+24h],ecx mov [eax+20h],ecx } }
Ohne die zwei Konstanten hab ich nich hinbekommen! Oder wie wuerdest du das machen Nobu ???
-
Jo, ungefaehr so hatte ich mir das gedacht.
Auch noch ein Vorschlag:
mov edi,[mat] mov esi,offset Pattern0 mov ecx,15 rep movsd ... Pattern0 dd 1.0, 0.0, 0.0, 0.0, 0.0 dd 1.0, 0.0, 0.0, 0.0, 0.0 dd 1.0, 0.0, 0.0, 0.0, 0.0
-
__forceinline void Test4( D3DMATRIX *mat ) { const float A = 1.0f; const float B = 0.0f; _asm { mov eax,[mat] mov ebx, A mov ecx, B mov [eax],ebx mov [eax+14h],ebx mov [eax+28h],ebx mov [eax+3Ch],ebx . . .
mov eax,[mat] Adresse von mat in den eax Register mov ebx, A ebx und ecx werden mit den Werte in A und B gefüllt mov ecx, B mov [eax],ebx eax hat jetzt den Wert 1.0f mov [eax+14h],ebx Adresse+14h(Dezimal 20) bekommen Wert 1.0f
ist das richtig? Die eckigen Klammer. Ist es so etwas wie *variable in C? Und was hat es mit dem Wert 14h auf sich. Wie kommt man darauf?
-
Die eckigen Klammern stehen fuer einen Speicherzugriff. Kann man also in sofern nicht unbedingt mit *Variable in c vergleichen...
mov eax,[mat] Adresse von mat in den eax Register
hier wird nicht die Addresse von mat in eax geladen, sondern der Wert, der an der Adresse von mat im Speicher steht.
mov [eax],ebx eax hat jetzt den Wert 1.0f
nicht ganz: 1.0 wird an die Speicheraddresse geschrieben, auf die eax zeigt.
-
Ok,
mov [eax],ebx eax hat jetzt den Wert 1.0f
**
nicht ganz: 1.0 wird an die Speicheraddresse geschrieben, auf die eax zeigt.
**mov eax,ebx hätte auch funktioniert, oder?
Noch etwas.
mov [eax],1 Über einen "Speicherzugriff" schreibe ich den Wert 1 in das Register eax. mov [eax+14h],2 Adresse+14h wird der Wert 2 geschrieben.
Wie groß ist den so ein Register? Ich meine das ich da +14h machen kann.
-
Wie groß ist den so ein Register?
Kommt auf den Prozessor drauf an. Beim x86er 32-bit
-
Original erstellt von <Gombolo>**
mov eax,ebx hätte auch funktioniert, oder?
**Eben nicht!
mov eax,ebx != mov [eax],ebxIm 1. Fall wird ebx in eax geschrieben. => eax wird veraendert. Im Speicher wird nichts veraendert. => kein Speicherzugriff => keine eckigen Klammern
Im 2. Fall wird eax als Pointer in den Speicher benutzt. Dabei aendert sich der Wert von eax nicht! Lediglich ein 4Byte grosser bereich im Speicher wird hier veraendert. (ebx=32Bit=4Byte) Irgendwelche anderen Register werden auch nicht veraendert. => Speicherzugriff => eckige Klammern
Original erstellt von <Gombolo>**
mov [eax],1 Über einen "Speicherzugriff" schreibe ich den Wert 1
in das Register eax.
**Die Register sind die einzigen "Variablen", die nicht im Speicher liegen. Wie soll dann ueber einen "Speicherzugriff" ein Register veraendert werden?
Also nochmal: Hier wird ein ???byte (nicht angegeben) grosser Speicherbereich veraendert, auf den eax zeigt und nicht das Register selbst.
So wuerde das uebrigens kein vernuenftiger Compiler akzeptieren, da wie oben erwaehnt nicht angegeben ist, wie gross der Speicherbereich ist, der veraendert werden soll. Es waere hier moeglich einen 1byte/1word(2byte)/1dword(4byte) grossen Speicherbereich mit dieser 1 zu fuellen.
So wuerde ein dword grosser Speicherbereich (auf den eax zeigt) mit dieser 1 belegt werden:mov [dword ptr eax],1
Original erstellt von <Gombolo>**
mov [eax+14h],2 Adresse+14h wird der Wert 2 geschrieben.Wie groß ist den so ein Register? Ich meine das ich da +14h machen kann.
**Ich hoffe doch, dass sich diese Frage nach meinen Ausfuehrungen erledigt hat?
[ Dieser Beitrag wurde am 30.12.2002 um 14:58 Uhr von Nobuo T editiert. ]
-
So, hab mir die letzten Beiträge nich so genau angeschaut (ging eh "nur" um den Speicherzugriff via []). Aber Ich habe da Oben ding im Code gesehen, die meiner Ansicht nach falsch sind. Ich sage gleich ich benutze NASM-Syntax für den ASM-Code.
const A 0.0f asm{ mov eax, A mov [Addr], eax } // ist NICHT äquivalent zu asm{ fldz fstp Addr }
Ein float Wert ist 80 Bit (!!!) gross, der passt nicht in eax!!!
ich würde vorschlagen den ersten float jeweils von der FPU zu holen, und dann mit "normalen" instruktionen fortfahren. Entscheidend ist auch ob die Werte der Matrix direkt nebeneinanderliegen oder nicht.Code könnt dann so aussehen:
//ich nehme der einfaheit halber an, das die Werte an die Adressen // Mat_1, Mat2, Mat_3, .., kopiert werden sollen asm{ fldz fstp Mat_1 mov esi, Mat_1 mov edi, Mat_2 movsd ;kopiere die 1. 32 bit movsd ;kopiere die 2. 32 bit movsw ;kopiere die letzten 16 bit mov esi, Mat_1 mov edi, Mat_3 movsd ;kopiere die 1. 32 bit movsd ;kopiere die 2. 32 bit movsw ;kopiere die letzten 16 bit mov esi, Mat_1 mov edi, Mat_4 movsd ;kopiere die 1. 32 bit movsd ;kopiere die 2. 32 bit movsw ;kopiere die letzten 16 bit }
habe allerdings gerade nochmal nachgeschaut, der fst(p) mem32 braucht nur 2 Takte ab dem Pentium, daher währe es u.U. doch sinvoll einfach
asm{ fldz fst Mat_1 fst Mat_2 fst Mat_3 fstp Mat_4 }
zu machen.
mfg
-bg-und ein frohes neues, falls ich vorher nicht mehr dazu komme
-
Original erstellt von -bg-
Ein float Wert ist 80 Bit (!!!) gross, der passt nicht in eax!!!hm?? Seit wann denn das? Da musst Du mir mal deine Quelle(n) offenlegen
Meine kannst Du hier haben (aus dem c++-Lehrgang fuer MSVC++ 6.0):
If you don't need 15 digits precision, and you don't need the massive range of values provided by double variables, you can opt to use the keyword float to declare floating point variables occupying 4 bytes.
-
z.B.
http://www.nuvisionmiami.com/books/asm/files/chapt_17.pdf Seite 17 mitte "Data Registers"auch in meinen ganzen FPU tuts und der Intel Doku sind die Register der FPU 80bit groß.
Muss allerdings zugeben, dass sizeof(float)==4 true ist, und sizeof(double)==8.
Das ganze scheint ein wenig blöd zu sein, der Hilfe nach ist deim bcc sizeof(long double)==10, beim mingw (gcc) ist sizeof(long double)==12.Die FPU kann nur mit 80bit Werten rechnen, kann jedoch andere Werte laden und speichern.
also wohl ein Fehler meinerseits.
mfg
-bg-
-
-sorry ich hatte den letzten post nicht richtig gelesen,da hat sich ja schon alles geklärt-
[ Dieser Beitrag wurde am 02.01.2003 um 01:53 Uhr von Bigor editiert. ]