Inline Assembly jmp verlangsamt Programm

Programmiersprachen, APIs, Bibliotheken, Open Source Engines, Debugging, Quellcode Fehler und alles was mit praktischer Programmierung zu tun hat.
Antworten
tZee
Beiträge: 8
Registriert: 04.11.2009, 17:11
Alter Benutzername: norebo

Inline Assembly jmp verlangsamt Programm

Beitrag von tZee »

Ich bin gerade dabei eine Integer-Klasse für Integer grösser als 32bit zu schreiben. Erstens weil mich das schon immer mal machen wollte und zweitens weil ich mich damit endlich mal in Assembler einarbeiten kann. :)

Als erstes habe ich eine Referenz-Klasse geschrieben, in der ich alle Operationen in C++ umgesetzt habe. Damit wollte ich überprüfen ob mein Assembler Code schneller ist .. :D
Nun beim schreiben der eigentlichen Klasse mit den Operationen in inline assembler bin ich auf ein Problem gestossen, mit dem ich nichts anfangen kann.

Ich messe die Zeit, die die einzelnen Operatoren brauchen um 10.000.000 iterationen durchzuführen. (10 mio additions, bit-shifts etc.)
Der Code dazu sieht so aus:

Code: Alles auswählen

#define ITERATIONS 10000000

DWORD start, end;

LargeAsmInt	asm1, asm2;

asm1 = "0x53ab9803ac56c76fd43ac45364bc898b76fd43ac";
asm2 = "0x0a5bc76fd43ac564bc87efd5453ab980998bcdea";

LargeInt<128> int1, int2;

int1 = "0x53ab9803ac56c76fd43ac45364bc898b76fd43ac";
int2 = "0x0a5bc76fd43ac564bc87efd5453ab980998bcdea";

start = GetTickCount();
for (long i = 0; i < ITERATIONS; ++i)
	asm1 + asm2;
end = GetTickCount();
printf("Addition LargeAsmInt: %d\n", end - start);

start = GetTickCount();
for (long i = 0; i < ITERATIONS; ++i)
	int1 + int2;
end = GetTickCount();
printf("Addition LargeInt: %d\n", end - start);
Bisher habe ich nur + und << in solchen Loops.

Nun zu meinem Problem: Wenn ich jetzt den Operator += hinzunehme verlangsamt sich die Ausführungszeit der anderen Operatoren um ca 2 Sekunden. Ich habe keine Ahnung woran das liegt und versucht das Problem ausfindig zu machen indem ich im += Operator alles auskommentiert habe und dann Zeile für Zeile wieder eingefügt habe.
Das Problem tritt erst auf wenn ich ein Jump im inline assembler zu einem Label mache. (Laut meinen Messungen macht es keinen unterschied ob ich jnz oder jmp benutze. Hier der Code von meinem += Operator:

Code: Alles auswählen

LargeAsmInt& LargeAsmInt::operator+= (LargeAsmInt& inOther)
{
	uint32_t	*thisData = this->data,
				*otherData = inOther.data;

	__asm
	{
		mov	ecx, 0						// loop counter
		mov edi, thisData					// this pointer
		mov esi, otherData					// inOther reference
		mov ebx, _LARGEASMINT_LENGTH_
		
		mov eax, [esi+ecx*4]
		add [edi+ecx*4], eax

		inc ecx
		dec ebx
		jz after_loop

/*before_loop:
		mov eax, [esi+ecx*4]
		adc [edi+ecx*4], eax

		inc ecx
		dec ebx
		jnz before_loop*/
after_loop:
	}
Hier die Zeiten (in ms) die ich für jeweils 10.000.000 Iterationen bekomme:

Code: Alles auswählen

Addition LargeAsmInt: 2890
Addition LargeInt: 4282
+= LargeInt: 6203
Shift << LargeAsmInt: 2906
Shift << LargeInt: 5812

Code: Alles auswählen

Addition LargeAsmInt: 4875
Addition LargeInt: 6078
+= LargeAsmInt: 3843
+= LargeInt: 7938
Shift << LargeAsmInt: 4734
Shift << LargeInt: 5782
LargeInt is die C++ Klasse, LargeAsmInt verwendet inline assembler. Interssanterweise beeinflusst es alle Funktionen, ausser dem << Operator der C++ Klasse.

Weiss zufällig jemand woran das liegen kann? Ich habe versucht bei MSDN und in Google was dazu zu finden - leider erfolglos. Da ich erst vor kurzem in Assembler eingestiegen bin fehlt mir noch die Erfahrung/das Wissen.
Btw. Ich arbeite mit Visual C++ 2008 Express Edition.
kkrahl
Beiträge: 56
Registriert: 20.10.2008, 13:41

Re: Inline Assembly jmp verlangsamt Programm

Beitrag von kkrahl »

Das Phänomen das ich hier vermuten würde ist das du mit wachsenden code andere Adressräume nutzt, von vormals NEAR oder SHORT hast du nun einen FAR Sprung, das hat zur Auswirkung das ein anderes Code-Segment geladen werden muss um deinen ASM-Code aus zu führen.

Hoffe das konnte helfen.

Karl
tZee
Beiträge: 8
Registriert: 04.11.2009, 17:11
Alter Benutzername: norebo

Re: Inline Assembly jmp verlangsamt Programm

Beitrag von tZee »

Danke für die Antwort.

Wie kann ich feststellen, dass das passiert? Ich habe folgende 2 Dinge probiert:

Ich habe mir die Disassemblies vom operator+ jeweils mit und ohne dem Jump Befehl im operator+=. Die Adressen ändern sich nicht, die Jumps sollten immernoch near/short sein. (Der operator+ befindet sich sowieso vor dem operator+= im Code.)
Dann habe ich mir das Disassembly vom operator+= angeschaut. Anstatt des Jump Befehls habe ich dann 2 inc/dec Befehle eingefügt damit das Label after_loop wieder an der selben Adresse steht. Die Ausführungszeit war wieder gut, d.h. ich gehe davon aus, dass die Verlangsamung nicht daran liegt, dass das Label in einen neuen Adressraum geschoben wird.
Benutzeravatar
TGGC
Establishment
Beiträge: 569
Registriert: 15.05.2009, 18:14
Benutzertext: Ich _bin_ es.
Alter Benutzername: TGGC
Echter Name: Ich _bin_ es.
Wohnort: Mainz
Kontaktdaten:

Re: Inline Assembly jmp verlangsamt Programm

Beitrag von TGGC »

Irgendwie verstehe ich dein Problem nicht. Du hast eine Schleife in deinem Programm. Und wenn du jetzt das jmp/jnz am Ende der Schleife entfernst - dann wird dein Programm schneller? Ist das deine Frage? Dein Programm ist jetzt schneller weil es weniger ausfuehrt. Ansonsten werde ich aus deinen Ausfuehrungen nicht schlau. f'`8k

[ ] Autocogito


Gruß, TGGC (Was Gamestar sagt...)
tZee
Beiträge: 8
Registriert: 04.11.2009, 17:11
Alter Benutzername: norebo

Re: Inline Assembly jmp verlangsamt Programm

Beitrag von tZee »

TGGC hat geschrieben:Irgendwie verstehe ich dein Problem nicht. Du hast eine Schleife in deinem Programm. Und wenn du jetzt das jmp/jnz am Ende der Schleife entfernst - dann wird dein Programm schneller? Ist das deine Frage? Dein Programm ist jetzt schneller weil es weniger ausfuehrt. Ansonsten werde ich aus deinen Ausfuehrungen nicht schlau. f'`8k

[ ] Autocogito


Gruß, TGGC (Was Gamestar sagt...)
Wenn ich den Jump vor der Schleife in dieser Funktion entferne werden alle anderen Funktionen des Programms schneller. Sowohl die der C++ Klasse (außer dem << Operator) als auch die der Klasse die inline assembler verwendet. Es geht auch nicht um die Gesamtausführungszeit von meinem Programm, sondern um die Ausführungszeiten der einzelnen Operatoren - die, soweit ich bisher dachte, eigentlich nicht davon beeinflußt werden sollten.
Benutzeravatar
TGGC
Establishment
Beiträge: 569
Registriert: 15.05.2009, 18:14
Benutzertext: Ich _bin_ es.
Alter Benutzername: TGGC
Echter Name: Ich _bin_ es.
Wohnort: Mainz
Kontaktdaten:

Re: Inline Assembly jmp verlangsamt Programm

Beitrag von TGGC »

Ahh ok. Angenommen Du hast nichts falsches gemessen:

Wird denn fuer den Rest der gleiche Code generiert, unabhaengig wie der += Operator implementiert?
Ist der Rest auch langsamer/schneller, wenn der += Operator nie aufgerufen wurde?
Hast du das mal auf verschiedenen Prozessoren gemessen? f'`8k


Gruß, TGGC (Was Gamestar sagt...)
tZee
Beiträge: 8
Registriert: 04.11.2009, 17:11
Alter Benutzername: norebo

Re: Inline Assembly jmp verlangsamt Programm

Beitrag von tZee »

Ich habe mir den Assemblercode des + Operators angeschaut, einmal in der schnellen und einmal in der langsameren Ausführung und er sah genau gleich aus. (Auch die Adressen waren dieselben.)
Der Rest ist schneller wenn der += Operator nicht aufgerufen wird. Ob es auch mit einem anderen zusätzlichen Operator langsamer wird weiss ich nicht. Ich habe dann nur, durch Auskommentieren, geschaut, an welchem Befehl es im += Operator liegt. Dadurch bin ich auf den Jump gekommen.

Bisher habe ich es nur auf einem Notebook getestet, ich kann es aber auch noch auf einem anderen Testen. Bin aber erstmal im Urlaub für eine Woche. Melde mich danach wieder. :)
Benutzeravatar
TGGC
Establishment
Beiträge: 569
Registriert: 15.05.2009, 18:14
Benutzertext: Ich _bin_ es.
Alter Benutzername: TGGC
Echter Name: Ich _bin_ es.
Wohnort: Mainz
Kontaktdaten:

Re: Inline Assembly jmp verlangsamt Programm

Beitrag von TGGC »

D.h. die Ausfuehrung des gleichen Codes (des + Operators) ist bei dir abhaengig davon was fuer Daten (der Code des += Operators) in einem anderen Bereich des RAMs liegen, auf den waehrend der gesamten Laufzeit des Programms nicht zugegriffen wird. Entweder ist dein PC sehr komisch, oder deine Beobachtung ist falsch, z.b. falsche Zeitmessung oder doch Codeunterschiede, die du nicht bemerkt hast. f'`8k

[ ] Autocogito


Gruß, TGGC (Was Gamestar sagt...)
kkrahl
Beiträge: 56
Registriert: 20.10.2008, 13:41

Re: Inline Assembly jmp verlangsamt Programm

Beitrag von kkrahl »

Ich würde trotzdem sagen das das was mit den Code-segmenten zu tun hat, und zwar hat bei deiner ersten Implementierung vermutlich besagter Code-teil in der selben Memory-page platz und in der 2ten muss ein teil über Pageing(page-fault) nach geladen werden.

Wenn du dem genauer nach gehen willst würde ich dir einen CPU-Debuger von Intel empfehlen.

mfg

Karl
Benutzeravatar
TGGC
Establishment
Beiträge: 569
Registriert: 15.05.2009, 18:14
Benutzertext: Ich _bin_ es.
Alter Benutzername: TGGC
Echter Name: Ich _bin_ es.
Wohnort: Mainz
Kontaktdaten:

Re: Inline Assembly jmp verlangsamt Programm

Beitrag von TGGC »

Sollte nicht passieren. Er hat den gleichen Code an der gleichen Adresse. Ausserdem ist er so klein, das er in den Cache passt. f'`8k


Gruß, TGGC (Was Gamestar sagt...)
Jörg
Establishment
Beiträge: 296
Registriert: 03.12.2005, 13:06
Wohnort: Trondheim
Kontaktdaten:

Re: Inline Assembly jmp verlangsamt Programm

Beitrag von Jörg »

Poste doch einfach mal alles, was notwendig ist, damit man dieses Problem nachvollziehen kann. Idealerweise ein VS-Projekt mit etwas Source. Dann sollte es nicht lange dauern, bis jemand das Problem identifisziert hat. Rumraten hilft hier nicht wirklich, aber mehr ist nach den bisherigen Beschreibungen auch kaum moeglich.
tZee
Beiträge: 8
Registriert: 04.11.2009, 17:11
Alter Benutzername: norebo

Re: Inline Assembly jmp verlangsamt Programm

Beitrag von tZee »

Ok, ich habe das VC Projekt hochgeladen. Die wichtigen Funktionen sind oben erwähnt. Später, Zuhause, werde ich auf einem anderen PC messen ob ich das selbe verhalten auf einer anderen CPU bekomme.
Dateianhänge
LargeInt.zip
(11.34 KiB) 212-mal heruntergeladen
Jörg
Establishment
Beiträge: 296
Registriert: 03.12.2005, 13:06
Wohnort: Trondheim
Kontaktdaten:

Re: Inline Assembly jmp verlangsamt Programm

Beitrag von Jörg »

Danke! Bei mir macht's keinen Unterschied auf die schnelle.
Morgen schau ich mal naeher rein.
tZee
Beiträge: 8
Registriert: 04.11.2009, 17:11
Alter Benutzername: norebo

Re: Inline Assembly jmp verlangsamt Programm

Beitrag von tZee »

Habs gerade mal auf meinem privaten Laptop getestet, allerdings unter Windows 7 Ultimate und den Code compiliert mit VSTS 2010 Beta2:

Jump Auskommentiert:

Code: Alles auswählen

Addition LargeAsmInt: 2512
Addition LargeInt: 0
+= LargeAsmInt: 31
+= LargeInt: 4056
Shift << LargeAsmInt: 2028
Shift << LargeInt: 3807
Mit Jump:

Code: Alles auswählen

Addition LargeAsmInt: 2371
Addition LargeInt: 0
+= LargeAsmInt: 31
+= LargeInt: 4134
Shift << LargeAsmInt: 1950
Shift << LargeInt: 3744
Ziemlich gleich also. Ich werde morgen die 2 Versionen auf dem anderen Rechner kompilieren und hier nochmal testen. Wenns dann immernoch gleich ist.. liegts wohl am anderen Notebook. :D
Benutzeravatar
Lord Delvin
Establishment
Beiträge: 597
Registriert: 05.07.2003, 11:17

Re: Inline Assembly jmp verlangsamt Programm

Beitrag von Lord Delvin »

(Kann sein dass ich unsinn rede, hab das Thema nur halb verfolgt, weils imo ne ziemlich schlechte Idee ist, kann also sein dass ein Teil des angesprochenen nutzlos ist)

Warum nimmst du nicht einfach smmintrin.h?
Dann läufst du auch nicht gefahr Labels doppelt zu vergeben. Hast du eigentlich mal die Korrektheit deines Codes getestet? Und kanns sein, dass einfach aus einem if eine Sprungtabelle für den Operator geworden ist, die du jetzt andauernd anschaust? Willst du das gleiche vielleicht mal in C oder mit einem richtigen Compiler (gcc -O3, icc -O2) testen?

Ich kann mir im Übrigen nicht vorstellen, dass du so, wie dus momentan angehst den C Compiler schlägst. Wäre eventuell einfacher schneller und lesbarer, wenn du die Funktionen einfach im cpp file mit extern"C" vornedran schreibst und dann aufrufst. Das sollte mit O3 schnelleren Code geben als C++ und erzeugt keinen Overhead, da es sowieso implizit inline wird. Wobei ich den operator sowieso als inline const definieren würde, aber egal.

EDIT: Ich versteh auch garnicht, warum es Leute gibt, die asm Code für ne Intelarchitektur schreiben und dann kein SSE für die Rechnungen verwenden. Das kann eigentlich garnicht schneller sein als der Compiler.

Gruß
XML/JSON/EMF in schnell: OGSS
Keine Lust mehr auf C++? Versuche Tyr: Get & Get started
Jörg
Establishment
Beiträge: 296
Registriert: 03.12.2005, 13:06
Wohnort: Trondheim
Kontaktdaten:

Re: Inline Assembly jmp verlangsamt Programm

Beitrag von Jörg »

An der Messung liegt es nicht, aber das Einfuegen des jump-Befehls veranlasst den Compiler, ein anderes Stack-Layout anzulegen und auch die Art der Stack-Adressierung wird geaendert (habs mal mit VS2008 SP1 unter XP versucht). Warum, dass kann ich dir nicht sagen, aber es ist wirklich ..sehr seltsam. Muss mit dem inlining zusammen haengen, welches der Compiler fuer diesen fraglichen Funktionsstumpf vornimmt. Ob das Programm in beiden Varianten korrekt ist, mag ich jetzt nicht mehr pruefen, aber das waere der naechste (eigentlich der erste) Schritt, es koennte sich um ein Compiler-Problem handeln...
tZee
Beiträge: 8
Registriert: 04.11.2009, 17:11
Alter Benutzername: norebo

Re: Inline Assembly jmp verlangsamt Programm

Beitrag von tZee »

Hmm.. die Korrektheit der + und << Operatoren habe ich überprüft, allerdings unabhängig von dem Problem. D.h. ich weiss nicht ob das Problem auch das Ergebnis verfälscht. Werde ich mal untersuchen. Danke für den Hinweis. :)
Lord Delvin hat geschrieben:Warum nimmst du nicht einfach smmintrin.h?
Ich habe bis zu deinem Posting noch nicht davon gehört.. Ich habe mich auch mit SSE noch nicht auseinandergesetzt.
tZee
Beiträge: 8
Registriert: 04.11.2009, 17:11
Alter Benutzername: norebo

Re: Inline Assembly jmp verlangsamt Programm

Beitrag von tZee »

So, gerade mal hier getestet, was ich mit dem anderen PC kompiliert hab. Die Zeiten sind ziemlich gleich, mit und ohne dem Jump... Hier hab ich nen Core2 Duo T7300, auf dem anderen PC nen Core Duo T2400.

@Jörg: Inwiefern ist das Stack-Layout denn anders? Mir war nicht bewusst, dass sich eine Anwendung aussuchen kann, wie der Stack addressiert wird.
Jörg
Establishment
Beiträge: 296
Registriert: 03.12.2005, 13:06
Wohnort: Trondheim
Kontaktdaten:

Re: Inline Assembly jmp verlangsamt Programm

Beitrag von Jörg »

Das ist ja das Interessante....der Compiler macht das nach dem Einfuegen des jumps. Und ich habe hier einen PC, auf dem dann die beiden Varianten reproduzierbar anders timen. Schau dir einfach mal den kompletten dissassembly von main() an (VS2008 SP1)....
Antworten