Hallo,
@bjoerk:
In
Post 44 ist das doch in der Unit1.zip eingebaut.
Wie dano schrieb, wie er seine Ergebnisse bekam, habe ich ein eine Form1 mit einem Button1 und einem memo1 zusammengeklickt und dann die entstehende unit1 durch diese ersetzt.Dort sind doch die
asm Varianten schon drin.
@dano:
Wie ich schon vorher bemerkt habe kann man ab und an durch cmovc Sprünge einsparen.
Wie BUG auch schrieb, kann ein miss"ge"ratener Sprung die ganzen vorgearbeiten Anweisungen (Befehls-pipeline) über den Haufen werfen, dass bedeutet die CPU muss nach dem Sprung von vorne mit der Arbeit beginnen und schon sind 20 Takte weg.
Der Ersatz durch cmov macht aber nur Sinn, wenn der Sprung nicht vorhersagbar, also ohne kurzes Muster, ist.
Ausserdem können die 80586 und später CPUs auf mehrere parallelen Arbeitssträngen arbeiten, wenn man sie lässt.
Beispielsweise:
Delphi-Quellcode:
MOV BX,AX
Xchg BH,BL
//1 tauscht CL,CH
MOV CX,AX;
SHR EAX,16;
MOV DX,AX
Xchg AH,AL
//2 tauscht DL,DH
cmp CH,CL;
cmovc cx,bx
Der Befehl
MOV BX,AX
Xchg BH,BL //1 tauscht CL,CH
hat bis
cmovc cx,bx
Zeit, ausgeführt zu werden, da sind noch 5 andere Befehle dazwischen.
Die Anordnung der Befehle ist dann von großem Einfluss.
Wenn der Sprung vorhersagbar ist, wenn man zum Beispiel immer den selben Wert verarbeitet, saust die Verarbeitung den richtigen Weg lang, dann ist bei mir asmdown die schnellste Variante, trotz dreier Sprünge.
Mein Bruder hat jetzt einen i5-2500 mit 3,4 Ghz, der hat bei konstanten Wert fast identische Werte wie der Core2 3,33 Ghz von Dir ( Ok skype lief nebenbei, aber das sollten 4 Kernen doch locker schaffen )
Was mich aber wundert, dass die Laufzeit auf Intel und AMD so unterschiedlich sind.
Meist ist doch AMD langsamer.
Bei Dir: 1351 e-3 / 1e8 = 1.351e-8 s pro Aufruf = 1.351e-8 [s]*3,33e9 [Hz] = 45 Cpu Takte.
Ich brauche Anzahl: 2147483646 ms: 14825,648.3 => 14825,64/2147483646*3,2e9 =22 Takte.
Vielleicht hat ja jemand anderer noch eine AMD CPU.
Es kann natürlich sein, dass eine Umstellung der Befehle für die Intel CPU von Vorteil ist.
Zudem könnte man denn letzten Sprung auch noch durch cmovc ersetzen, da die "Strafe" für einen falschen Sprung 20 Takte ist.Bei einer 50/50 Chance der Sprungvorhersage, kann man ruhig noch 8 Takte verbraten
Ich hatte Dir aber schon geschrieben das es mit 6 Vergleichen und der Auswertung des Carry Flags durch eine Sprungtabelle noch schneller sein müsste:
Delphi-Quellcode:
procedure Testvariante(
var A: ByteArray);
assembler;
{ I D C B A ECX
0 4 3 2 1 63 00111111 ..
6 4 3 1 2 55 00110111 tausche BA
2 4 2 3 1 59 00111011 tausche CB
14 4 1 2 3 35 00100011 tausche CA
12 4 2 1 3 39 00100111 tausche CA ,BA
8 4 1 3 2 43 00101011 tausche CB ,BA
1 3 4 2 1 62 00111110 tausche DC
4 3 2 4 1 57 00111001 tausche DC ,CB
7 3 4 1 2 54 00110110 tausche DC ,BA
10 3 1 4 2 41 00101001 tausche DC ,BA, DA
18 3 2 1 4 7 00000111 tausche DC ,BA, DB
20 3 1 2 4 3 00000011 tausche DC ,BA, DA
5 2 3 4 1 56 00111000
3 2 4 3 1 60 00111100
13 2 4 1 3 22 00010110
16 2 1 4 3 9 00001001
19 2 3 1 4 6 00000110
22 2 1 3 4 1 00000001 BSWAP tausche BA
17 1 2 4 3 8 00001000 BSWAP tausche DC
21 1 3 2 4 4 00000100 BSWAP tausche CB
23 1 2 3 4 0 00000000 BSWAP
9 1 4 3 2 28 00011100
11 1 3 4 2 24 00011000
15 1 4 2 3 20 00010100}
ASM
PUSH EAX;
MOV EAX,Dword PTR [EAX];
// A,B,C,D
MOV EDX,EAX;
//EDX A,B ,C,D DL = A; DH = B
BSWAP EAX;
//EAX D,C ,B,A AL = D; AH = C
XOR ECX,ECX;
CMP
DL,AL;
//A<D
RCL CL,1;
CMP
DL,AH;
//A<C
RCL CL,1;
CMP
DL,DH;
//A<B
RCL CL,1;
CMP DH,AH;
//B<C
RCL CL,1;
CMP DH,AL;
//B<D
RCL CL,1;
CMP AH,AL;
//C<D
RCL CL,1;
XOR ECX,ECX;
// Test
// Berechneter Sprung
JMP DWORD PTR [@SprungTabelle+4*ECX]
@L0:
POP EAX;
MOV Dword Ptr[EAX],EDX;
Ret;
@L1:;
//
@L3:;
//
//.....
@L63:;
//....
@Sprungtabelle:
DD @L0,@L1,0,@L3
.....
end;
Gruß Horst.