Autor |
Beitrag |
Mathematiker
Beiträge: 2622
Erhaltene Danke: 1447
Win 7, 8.1, 10
Delphi 5, 7, 10.1
|
Verfasst: So 16.09.12 09:59
Hallo,
nachdem ich bei der Darstellung eines Plasmas ( www.entwickler-ecke.de/topic_110170.html) mit Assembler experimentiert habe, wollte ich das etwas besser verstehen.
Aus diesem Grund habe ich die zwei Assembler-Routinen
Delphi-Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25:
| function randomx(a:integer):integer; asm xor edx, edx imul edx, [randseed], $08088405 inc edx mov [randseed], edx mul edx mov eax, edx end;
function randomy(a:integer):integer; asm push eax shl eax, 1 add eax, 1 xor edx, edx imul edx, [randseed], $08088405 inc edx mov [randseed], edx mul edx pop eax sub eax, edx end; |
mit den normalen Delphi-Aufrufen random(a) bzw. random(2*a+1)-a verglichen. Dabei ist die Grundidee des ASM-Textes nicht von mir, sondern aus www.entwickler-ecke....highlight=random+asm entnommen.
Nun geschieht etwas, meiner Meinung nach, sehr Merkwürdiges.
Während die erste Funktion sehr oft schneller ist als random(a), aber nicht immer(?), ist die zweite nur selten besser als random(2*a+1)-a, mitunter sogar langsamer.
Das verstehe ich nicht. Durch das Übernehmen der Multiplikation mit 2, der Additon mit 1 und am Ende der Subtraktion mit a direkt(!) im Assembler-Code müsste es doch gerade hier einen Geschwindigkeitszuwachs geben.
Bei mehreren Tests ergab sich im Mittel
Quelltext 1: 2: 3: 4: 5: 6: 7: 8:
| Zufallsintervall [0, a-1] Delphi 0,198 s ASM 0,121 s Gewinn 38,8 % Zufallsintervall [-a, a] Delphi 0,127 s ASM 0,128 s Gewinn -0,35 % |
Als ich meinen Prozessor Genuine Intel(R) T2250 1,73 GHz mit nur 50 %-Leistung (Energiesparplan) genutzt habe, wurde
Quelltext 1: 2: 3: 4: 5: 6: 7: 8:
| Zufallsintervall [0, a-1] Delphi 0,271 s ASM 0,264 s Gewinn 2,4 % Zufallsintervall [-a, a] Delphi 0,278 s ASM 0,279 s Gewinn -0,56 % |
Und das verstehe ich nun gar nicht mehr. Wieso ist Assembler bei 100% CPU-Auslastung auf einmal so viel schneller im Vergleich zu Delphi?
Vielleicht kann mir jemand von Euch helfen.
Beste Grüße
Mathematiker
_________________ Töten im Krieg ist nach meiner Auffassung um nichts besser als gewöhnlicher Mord. Albert Einstein
Zuletzt bearbeitet von Mathematiker am Mo 24.09.12 22:07, insgesamt 1-mal bearbeitet
|
|
uall@ogc
Beiträge: 1826
Erhaltene Danke: 11
Win 2000 & VMware
Delphi 3 Prof, Delphi 7 Prof
|
Verfasst: So 16.09.12 19:31
Du kannst das Push eax / Pop Eax auch noch weglassen, im Grunde ist dies aber nichts anderes als die Random-Funktion von Delphi (wenn ich mich nicht irre), von daher sollte es keinen Unterschied machen, eine Zeitmessung ueber 0.2 ist da nicht aussagekraeftig.
Verwende einfach mal das Delphi-Random mach nen Breakpoint drauf und schau dir den code an (glaub strg+shift+c).
_________________ wer andern eine grube gräbt hat ein grubengrabgerät
- oder einfach zu viel zeit
Für diesen Beitrag haben gedankt: Mathematiker
|
|
Mathematiker
Beiträge: 2622
Erhaltene Danke: 1447
Win 7, 8.1, 10
Delphi 5, 7, 10.1
|
Verfasst: So 16.09.12 19:46
Hallo
uall@ogc hat folgendes geschrieben : | Du kannst das Push eax / Pop Eax auch noch weglassen, im Grunde ist dies aber nichts anderes als die Random-Funktion von Delphi (wenn ich mich nicht irre) |
Es ist die Random-Funktion von Delphi. Push und Pop kann ich leider nicht weglassen, da ich einen Fehler im Text hatte. Richtig ist:
Delphi-Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14:
| function randomy(a:integer):integer; asm push eax shl eax, 1 add eax, 1 xor edx, edx imul edx, [randseed], $08088405 inc edx mov [randseed], edx mul edx mov eax, edx pop edx sub eax, edx end; |
uall@ogc hat folgendes geschrieben : | von daher sollte es keinen Unterschied machen, eine Zeitmessung ueber 0.2 ist da nicht aussagekraeftig. |
Danke für den Hinweis. Ich habe die Schleifendurchläufe immer mehr erhöht, wobei der Unterschied zwischen Delphi und Assembler immer kleiner wurde. Die Delphi-Lösung ist wohl schon optimal.
Beste Grüße
Mathematiker
_________________ Töten im Krieg ist nach meiner Auffassung um nichts besser als gewöhnlicher Mord. Albert Einstein
|
|
OlafSt
Beiträge: 486
Erhaltene Danke: 99
Win7, Win81, Win10
Tokyo, VS2017
|
Verfasst: Mo 17.09.12 00:21
Ich habe spaßenshalber mal den Code von random(x) auf Assembler-Ebene betrachtet. Die oben vorgeschlagene Routine ist eine 1:1-Kopie davon
Das Laufzeitverhalten kann durchaus unterschiedlich sein. Die Befehle IMUL und MUL haben in den Opcode-Tabellen von Intel stets eine Laufzeit von "xx-yy Takte" angegeben, bis Intel keine Taktangaben mehr ausgab (siehe weiter unten, warum). So ist es dann möglich, das hunderte IMULs xx Takte brauchen, und ein dutzend weitere plötzlich yy Takte. MUL hat sogar dreistellige Taktzahlen IIRC. Daher die unterschiedlichen Laufzeiten. Um herauszufinden, wann genau MUL/IMUL wieviel Takte benötigt, ist ein Blick in die Opcode-Tabelle von Intel hilfreich - ich hab mir das nicht so genau angesehen
Die Tatsache, das im Stromsparmodus die Laufzeiten in die Höhe schnellen, ist einfach erklärt. Um Strom zu sparen, werden Teile der CPU deaktiviert bzw. mit sehr niedrigen Taktraten betrieben - die FPU ist z.B. so ein Kandidat, aber auch Teile der ALU werden abgeschaltet, so das nur mehr 5 oder 6 ALUs laufen, und das restliche dutzend schläft. So müssen sich nun die Mnemonics durch 6 ALUs quetschen, statt bequem und verzögerungsfrei superskalar abgearbeitet werden zu können. Und schwups dauert die Berechnung 80% länger - dafür läuft der Notebook aber 10 Minuten länger.
Heutige CPUs haben mit den simplen Prozessoren, auf denen wir mal gelernt haben (ich hab auf nem 6510, dann Z80 und dann 8085 angefangen ) nur noch den Namen gemein. Tatsächlich ist es heute praktisch unmöglich, die exakte Laufzeit einer Routine konkret zu berechnen, weshalb bei Intel auch kaum noch Taktangaben zu finden sind - superskalar sei Dank. Da ist es möglich, das Befehle auch Null Takte Laufzeit benötigen...
_________________ Lies, was da steht. Denk dann drüber nach. Dann erst fragen.
Für diesen Beitrag haben gedankt: Mathematiker
|
|
|