Einzelnen Beitrag anzeigen

Horst_

Registriert seit: 22. Jul 2004
Ort: Münster Osnabrück
116 Beiträge
 
#54

AW: Hilfe: Schnellste möglichkeit ein 4-Byte Array zu Sortieren

  Alt 13. Feb 2012, 06:55
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.
  Mit Zitat antworten Zitat