Autor Beitrag
Mathematiker
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 2622
Erhaltene Danke: 1447

Win 7, 8.1, 10
Delphi 5, 7, 10.1
BeitragVerfasst: 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

ausblenden 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:
    //Zufallszahl im Intervall [0, a-1]
    function randomx(a:integer):integer;
    asm
       xor edx, edx      
       imul edx, [randseed], $08088405
       inc edx
       mov [randseed], edx
       mul edx
       mov eax, edx       //in eax steht zufallswert
    end;

    //Zufallszahl im Intervall [-a, a]
    function randomy(a:integer):integer;
    asm
       push eax             //a sichern
       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       //in eax steht zufallswert
    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. :nixweiss: 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
ausblenden 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
ausblenden 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
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 1826
Erhaltene Danke: 11

Win 2000 & VMware
Delphi 3 Prof, Delphi 7 Prof
BeitragVerfasst: 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 Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 2622
Erhaltene Danke: 1447

Win 7, 8.1, 10
Delphi 5, 7, 10.1
BeitragVerfasst: So 16.09.12 19:46 
Hallo
user profile iconuall@ogc hat folgendes geschrieben Zum zitierten Posting springen:
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:
ausblenden 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       //in eax steht zufallswert [-a,a]
    end;

user profile iconuall@ogc hat folgendes geschrieben Zum zitierten Posting springen:
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
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 486
Erhaltene Danke: 99

Win7, Win81, Win10
Tokyo, VS2017
BeitragVerfasst: 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