Autor |
Beitrag |
Spaceguide
      
Beiträge: 552
(D3/D7/D8) Prof.
|
Verfasst: Do 11.05.06 10:44
Hi,
ich versuche gerade eine Routine zu optimieren, welche einen FloatPoint (x,y) in einen einen ganzzahligen Teil und die Nachkommastellen zerlegt.
Mein Problem ist die schlechte Performanz der SSE-Implementierung FracTruncXY_SSE(). Sie ist kaum schneller (manchmal auf langsamer) als der FPU-Murks FracTruncXY_FPU. Kann man da noch was herausholen?
Timings zum Vergleich auf Pentium-M:
FracTruncXY() : 4386ms
FracTruncXY_FPU() : 2043ms
FracTruncXY_SSE() : 2023ms
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: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35: 36: 37: 38: 39: 40: 41: 42: 43: 44: 45: 46: 47: 48: 49: 50: 51: 52: 53: 54: 55: 56: 57: 58: 59: 60: 61: 62: 63: 64: 65: 66: 67: 68: 69: 70: 71:
| type float = single; TPoint = packed record x,y : integer; end; TFloatPoint = packed record x,y : float; end;
procedure FracTruncXY(const aPoint : TFloatPoint; var aIntOut : TPoint; var aFraction : TFloatPoint); begin aIntOut.x := Round(aPoint.x-0.5); aFraction.x := aPoint.x-aIntOut.x; aIntOut.y := Round(aPoint.y-0.5); aFraction.y := aPoint.y-aIntOut.y; end;
procedure FracTruncXY_FPU(const aPoint : TFloatPoint; var aIntOut : TPoint; var aFraction : TFloatPoint);
const round_toward_m_i: float = -0.5; var i: integer; begin
asm fld dword ptr [eax] fadd round_toward_m_i fistp i end;
aIntOut.x := i; aFraction.x := aPoint.x - i;
asm fld dword ptr [eax+4] fadd round_toward_m_i fistp i end;
aIntOut.y := i; aFraction.y := aPoint.y - i; end;
procedure FracTruncXY_SSE(const aPoint : TFloatPoint; var aIntOut : TPoint; var aFraction : TFloatPoint); const RoundTowards : array [0..3] of float = (-0.5,-0.5,0,0); ASM MOVLPS xmm0,[aPoint] MOVUPS xmm1,[RoundTowards] MOVAPS xmm2,xmm0 ADDPS xmm0,xmm1 CVTPS2PI mm0, xmm0 MOVQ [aIntOut],mm0 CVTPI2PS xmm0,mm0 SUBPS xmm2,xmm0 MOVLPS [aFraction],xmm2 EMMS end; |
|
|
jasocul
      
Beiträge: 6395
Erhaltene Danke: 149
Windows 7 + Windows 10
Sydney Prof + CE
|
Verfasst: Do 11.05.06 10:57
Warum benutzt du Round? Delphi kennt auch die Funktion Trunc. Round dürfte theoretisch langsamer sein. Und die Funktion Frac gibts doch auch.
|
|
Spaceguide 
      
Beiträge: 552
(D3/D7/D8) Prof.
|
Verfasst: Do 11.05.06 11:04
Ich habe gewusst, dass das jemand fragt, der's nicht ausprobiert hat.
|
|
jasocul
      
Beiträge: 6395
Erhaltene Danke: 149
Windows 7 + Windows 10
Sydney Prof + CE
|
Verfasst: Do 11.05.06 11:15
Dann hätte auch ein einfache Hinweis in deinem ersten Beitrag genügt, dass du das schon getestet hast. Oder ist es unsere Aufgabe, deine Versuche zu wiederholen?
|
|
Spaceguide 
      
Beiträge: 552
(D3/D7/D8) Prof.
|
Verfasst: Do 11.05.06 11:19
Hae? Die erste Routine steht doch garnicht zur Diskussion, die ist nur dabei, damit man sofort sieht, was die unten stehenden Assembler-Routinen eigentlich machen sollen. Das Problem ist, wie im Beitrag steht, die SSE-Routine, die mir ziemlich langsam vorkommt.
|
|
jasocul
      
Beiträge: 6395
Erhaltene Danke: 149
Windows 7 + Windows 10
Sydney Prof + CE
|
Verfasst: Do 11.05.06 11:23
Spaceguide hat folgendes geschrieben: | Hae? Die erste Routine steht doch garnicht zur Diskussion, die ist nur dabei, damit man sofort sieht, was die unten stehenden Assembler-Routinen eigentlich machen sollen. |
Dann war ich wohl zu blöd, das so zu interpertieren.
|
|
Horst_H
      
Beiträge: 1654
Erhaltene Danke: 244
WIN10,PuppyLinux
FreePascal,Lazarus
|
Verfasst: Do 11.05.06 11:37
Hallo,
auf einem Athlon64 (1800 Mhz)sieht es so mit Delphi7 aus
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: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35: 36: 37: 38: 39: 40: 41: 42: 43: 44: 45: 46: 47: 48: 49: 50: 51: 52: 53: 54: 55: 56: 57: 58: 59: 60: 61: 62: 63: 64: 65: 66: 67: 68: 69: 70: 71: 72: 73: 74: 75: 76: 77: 78: 79: 80: 81: 82: 83: 84: 85: 86: 87: 88: 89: 90: 91: 92: 93: 94: 95: 96: 97: 98: 99: 100: 101: 102: 103: 104: 105: 106: 107:
| program Project2;
{$APPTYPE CONSOLE}
uses SysUtils,windows; type float = single; TPoint = packed record x,y : integer; end; TFloatPoint = packed record x,y : float; end;
var fPunkt,Fout :TFloatPoint; iPunkt: TPoint; i,max : integer; T1,T0,Tf,Td : int64;
procedure FracTruncXY(const aPoint : TFloatPoint; var aIntOut : TPoint; var aFraction : TFloatPoint); begin aIntOut.x := Round(aPoint.x-0.5); aFraction.x := aPoint.x-aIntOut.x; aIntOut.y := Round(aPoint.y-0.5); aFraction.y := aPoint.y-aIntOut.y; end;
procedure FracTruncXY_FPU(const aPoint : TFloatPoint; var aIntOut : TPoint; var aFraction : TFloatPoint);
const round_toward_m_i: float = -0.5; var i: integer; begin
asm fld dword ptr [eax] fadd round_toward_m_i fistp i end;
aIntOut.x := i; aFraction.x := aPoint.x - i;
asm fld dword ptr [eax+4] fadd round_toward_m_i fistp i end;
aIntOut.y := i; aFraction.y := aPoint.y - i; end;
procedure FracTruncXY_SSE(const aPoint : TFloatPoint; var aIntOut : TPoint; var aFraction : TFloatPoint); const RoundTowards : array [0..3] of float = (-0.5,-0.5,0,0); ASM MOVLPS xmm0,[aPoint] MOVUPS xmm1,[RoundTowards] MOVAPS xmm2,xmm0 ADDPS xmm0,xmm1 CVTPS2PI mm0, xmm0 MOVQ [aIntOut],mm0 CVTPI2PS xmm0,mm0 SUBPS xmm2,xmm0 MOVLPS [aFraction],xmm2 EMMS end;
begin queryperformancefrequency(Tf); fPunkt.x := pi; fPunkt.y := pi; max := 1000*1000*100; writeln(Format('Durchlaeufe %e',[max*1.0])); writeln; queryperformanceCounter(T0); for i := max downto 1 do; queryperformanceCounter(T1); writeln(Format('Nichts %10.5f ms',[(T1-T0)/Tf*1000])); Td := t1-t0;
queryperformanceCounter(T0); for i := max downto 1 do FracTruncXY(fPunkt,iPunkt,fOut); queryperformanceCounter(T1); writeln(Format('Normal %10.5f ms',[(T1-T0-Td)/Tf*1000]));
queryperformanceCounter(T0); for i := max downto 1 do FracTruncXY_FPU(fPunkt,iPunkt,fOut); queryperformanceCounter(T1); writeln(Format('FPU %10.5f ms',[(T1-T0-Td)/Tf*1000]));
queryperformanceCounter(T0); for i := max downto 1 do FracTruncXY_SSE(fPunkt,iPunkt,fOut); queryperformanceCounter(T1); writeln(Format('SSE %10.5f ms',[(T1-T0-Td)/Tf*1000]));
readln; end. |
mit dem Ergebnis
Quelltext 1: 2: 3: 4: 5: 6:
| Durchlaeufe 1,00000000000000E+008
Nichts 112,82160 ms Normal 3048,05080 ms FPU 1428,75058 ms SSE 729,30247 ms |
Also dort ist es schneller mit SSE
Gruss Horst
EDIT
Auf meine Notebook (Pentium M 1,7 Ghz)
sind es
Quelltext 1: 2: 3: 4: 5: 6:
| Durchlaeufe 1,00000000000000E+008
Nichts 197,01470 ms Normal 2614,99157 ms FPU 1286,62917 ms SSE 891,20740 ms |
Also auch dort ist es schneller mit SSE
Da ich immer den selben Speicherbereich anspreche, koennte es daran liegen, dass die Daten nur immer im 1.st level cache sind.
|
|
BenBE
      
Beiträge: 8721
Erhaltene Danke: 191
Win95, Win98SE, Win2K, WinXP
D1S, D3S, D4S, D5E, D6E, D7E, D9PE, D10E, D12P, DXEP, L0.9\FPC2.0
|
Verfasst: Do 11.05.06 14:29
Wenn ich mich nicht vertan hab (ACHTUNG: UNGETESTET), sollte es so noch etwas optimaler sein.
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: 26: 27: 28: 29: 30:
| type float = single; TPoint = packed record x,y : integer; end; TFloatPoint = packed record x,y : float; end;
procedure FracTruncXY_FPU( var aPoint : TFloatPoint; var aIntOut : TPoint; var aFraction : TFloatPoint); const round_toward_m_i: float = -0.5; var i: integer; asm fld DWORD PTR [eax].TFloatPoint.x fld st(0) fadd round_toward_m_i fld st(0) fistp DWORD PTR [edi].TPoint.X fsubrp fstp DWORD PTR [ECX].TFloatPoint.x
fld DWORD PTR [eax].TFloatPoint.y fld st(0) fadd round_toward_m_i fld st(0) fistp DWORD PTR [edi].TPoint.y fsubrp fstp DWORD PTR [ECX].TFloatPoint.y end; |
Wenn's Vorzeichenfehler gibt, bei fsubrp das R entfernen 
_________________ Anyone who is capable of being elected president should on no account be allowed to do the job.
Ich code EdgeMonkey - In dubio pro Setting.
|
|
Spaceguide 
      
Beiträge: 552
(D3/D7/D8) Prof.
|
Verfasst: Do 11.05.06 15:05
Wenn ich jetzt mal EDI durch EDX ersetze funktioniert es noch nicht. Die Fraction ist konstant 0.5,0.5
|
|
BenBE
      
Beiträge: 8721
Erhaltene Danke: 191
Win95, Win98SE, Win2K, WinXP
D1S, D3S, D4S, D5E, D6E, D7E, D9PE, D10E, D12P, DXEP, L0.9\FPC2.0
|
Verfasst: Do 11.05.06 15:23
Hi, hatte noch nen kleinen Fehler bei der Rundung drin. Jetzt funzt's ... Hab keine Zeitmessung gemacht, sollte aber zumindest den Algo von Delphi um Längen schlagen ...
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: 26: 27: 28: 29: 30:
| type float = single; TPoint = packed record x,y : integer; end; TFloatPoint = packed record x,y : float; end;
procedure FracTruncXY_FPU( var aPoint : TFloatPoint; var aIntOut : TPoint; var aFraction : TFloatPoint); const round_toward_m_i: float = -0.5; var i: integer; asm fld DWORD PTR [eax].TFloatPoint.x fld st(0) fadd round_toward_m_i fistp DWORD PTR [edx].TPoint.X fild DWORD PTR [edx].TPoint.X fsubrp fstp DWORD PTR [ECX].TFloatPoint.x
fld DWORD PTR [eax].TFloatPoint.y fld st(0) fadd round_toward_m_i fistp DWORD PTR [edx].TPoint.y fild DWORD PTR [edx].TPoint.y fsubp fstp DWORD PTR [ECX].TFloatPoint.y end; |
//Edit: F*CK ... Delphi hat das Kopieren nicht mitbekommen. Hab vor der Sub-Anweisung die beiden Befehle getauscht ...
_________________ Anyone who is capable of being elected president should on no account be allowed to do the job.
Ich code EdgeMonkey - In dubio pro Setting.
Zuletzt bearbeitet von BenBE am Do 11.05.06 15:59, insgesamt 1-mal bearbeitet
|
|
Spaceguide 
      
Beiträge: 552
(D3/D7/D8) Prof.
|
Verfasst: Do 11.05.06 15:48
Hmm, mal ne dumme Frage: Was hast du grad geändert? Die Quellcodes sind eigentlich identisch.
|
|
Horst_H
      
Beiträge: 1654
Erhaltene Danke: 244
WIN10,PuppyLinux
FreePascal,Lazarus
|
Verfasst: Do 11.05.06 19:23
Hallo,
bei Deiner Variante werden drei Register auf den Stack geschoben, bei den anderen nicht.
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: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35: 36: 37: 38: 39: 40: 41: 42: 43: 44: 45: 46: 47: 48: 49: 50: 51: 52: 53: 54: 55: 56: 57: 58: 59: 60: 61: 62: 63: 64: 65: 66: 67: 68: 69: 70: 71: 72: 73: 74: 75: 76: 77: 78: 79: 80: 81: 82: 83: 84: 85: 86: 87: 88: 89: 90: 91: 92: 93: 94: 95: 96: 97: 98: 99: 100: 101: 102: 103: 104: 105: 106: 107: 108: 109: 110: 111: 112: 113: 114: 115: 116: 117: 118: 119: 120: 121: 122: 123: 124: 125: 126: 127: 128: 129: 130: 131: 132: 133: 134: 135: 136: 137: 138: 139: 140: 141: 142: 143: 144: 145: 146: 147: 148: 149: 150: 151: 152: 153: 154: 155: 156: 157: 158: 159: 160: 161: 162: 163: 164: 165: 166: 167: 168: 169: 170: 171: 172: 173: 174: 175: 176: 177: 178: 179: 180: 181: 182: 183: 184: 185: 186: 187: 188: 189: 190: 191: 192: 193: 194: 195: 196: 197: 198: 199: 200: 201: 202: 203: 204: 205: 206: 207: 208: 209: 210: 211: 212: 213: 214: 215: 216: 217: 218: 219: 220: 221: 222:
| program Project2;
{$APPTYPE CONSOLE}
uses SysUtils, windows;
type float = single; TPoint = packed record x,y : integer; end; TFloatPoint = packed record x,y : float; end;
var T1,T0,Tf,Td : int64; fPunkt,Fout :TFloatPoint; iPunkt: TPoint; i,max : integer;
procedure FracTruncXY(const aPoint : TFloatPoint; var aIntOut : TPoint; var aFraction : TFloatPoint); begin aIntOut.x := Round(aPoint.x-0.5); aFraction.x := aPoint.x-aIntOut.x; aIntOut.y := Round(aPoint.y-0.5); aFraction.y := aPoint.y-aIntOut.y; end;
procedure FracTruncXY_FPU(const aPoint : TFloatPoint; var aIntOut : TPoint; var aFraction : TFloatPoint);
const round_toward_m_i: float = -0.5; var i: integer; begin
asm fld dword ptr [eax] fadd round_toward_m_i fistp i end;
aIntOut.x := i; aFraction.x := aPoint.x - i;
asm fld dword ptr [eax+4] fadd round_toward_m_i fistp i end;
aIntOut.y := i; aFraction.y := aPoint.y - i; end;
procedure FracTruncXY_FPU2( var aPoint : TFloatPoint; var aIntOut : TPoint; var aFraction : TFloatPoint); const round_toward_m_i: float = -0.5; asm fld DWORD PTR [eax].TFloatPoint.x fld st(0) fadd round_toward_m_i fistp DWORD PTR [edx].TPoint.X fild DWORD PTR [edx].TPoint.X fsubp fstp DWORD PTR [ECX].TFloatPoint.x
fld DWORD PTR [eax].TFloatPoint.y fld st(0) fadd round_toward_m_i fistp DWORD PTR [edx].TPoint.y fild DWORD PTR [edx].TPoint.y fsubp fstp DWORD PTR [ECX].TFloatPoint.y end;
procedure FracTruncXY_FPU3( var aPoint : TFloatPoint; var aIntOut : TPoint; var aFraction : TFloatPoint); const round_toward_m_i: float = -0.5; asm fld round_toward_m_i fld DWORD PTR [EAX].TFloatPoint.x fld st(0) fadd st(0),st(2)
fld DWORD PTR [EAX].TFloatPoint.y fld st(0) fadd st(0),st(4) fFree st(4) fistp DWORD PTR [EDX].TPoint.y fild DWORD PTR [EDX].TPoint.y fsubp fstp DWORD PTR [ECX].TFloatPoint.y
fistp DWORD PTR [EDX].TPoint.x fild DWORD PTR [EDX].TPoint.x fsubp fstp DWORD PTR [ECX].TFloatPoint.x
end;
procedure FracTruncXY_FPU4( var aPoint : TFloatPoint; var aIntOut : TPoint; var aFraction : TFloatPoint); asm fld DWORD PTR [eax].TFloatPoint.X FRNDINT fld DWORD PTR [eax].TFloatPoint.Y FRNDINT fld DWORD PTR [eax].TFloatPoint.X fld DWORD PTR [eax].TFloatPoint.Y FXCH ST(3) fist DWORD PTR [edx].TPoint.X fsub fstp DWORD PTR [ECX].TFloatPoint.X
fist DWORD PTR [edx].TPoint.Y fsub fstp DWORD PTR [ECX].TFloatPoint.Y end;
procedure FracTruncXY_SSE(const aPoint : TFloatPoint; var aIntOut : TPoint; var aFraction : TFloatPoint); const RoundTowards : array [0..3] of float = (-0.5,-0.5,0,0); ASM MOVLPS xmm0,[aPoint] MOVUPS xmm1,[RoundTowards] MOVAPS xmm2,xmm0 ADDPS xmm0,xmm1 CVTPS2PI mm0, xmm0 MOVQ [aIntOut],mm0 CVTPI2PS xmm0,mm0 SUBPS xmm2,xmm0 MOVLPS [aFraction],xmm2 FEMMS end;
begin queryperformancefrequency(Tf); fPunkt.x := pi; fPunkt.y := sqrt(2); max := 1000*1000*100; writeln(Format('Durchlaeufe %e',[max*1.0])); writeln(''); queryperformanceCounter(T0); for i := max downto 1 do; queryperformanceCounter(T1); writeln(Format('Nichts %10.5f ms',[(T1-T0)/Tf*1000])); Td := t1-t0;
fPunkt.x := fPunkt.x+1; fPunkt.y := fPunkt.y+1; queryperformanceCounter(T0); for i := max downto 1 do FracTruncXY_FPU(fPunkt,iPunkt,fOut); queryperformanceCounter(T1); writeln(Format('FPU 1 %10.5f ms',[(T1-T0-Td)/Tf*1000])); writeln(Format('%10d %10d %10.8f %10.8f',[iPunkt.x,ipunkt.y,fout.x,fout.y]));
fPunkt.x := fPunkt.x+1; fPunkt.y := fPunkt.y+1; queryperformanceCounter(T0); for i := max downto 1 do FracTruncXY_FPU2(fPunkt,iPunkt,fOut); queryperformanceCounter(T1); writeln(Format('FPU 2 %10.5f ms',[(T1-T0-Td)/Tf*1000])); writeln(Format('%10d %10d %10.8f %10.8f',[iPunkt.x,ipunkt.y,fout.x,fout.y]));
fPunkt.x := fPunkt.x+1; fPunkt.y := fPunkt.y+1; queryperformanceCounter(T0); for i := max downto 1 do FracTruncXY_FPU3(fPunkt,iPunkt,fOut); queryperformanceCounter(T1); writeln(Format('FPU 3 %10.5f ms',[(T1-T0-Td)/Tf*1000])); writeln(Format('%10d %10d %10.8f %10.8f',[iPunkt.x,ipunkt.y,fout.x,fout.y]));
fPunkt.x := fPunkt.x+1; fPunkt.y := fPunkt.y+1; queryperformanceCounter(T0); for i := max downto 1 do FracTruncXY_FPU4(fPunkt,iPunkt,fOut); queryperformanceCounter(T1); writeln(Format('FPU 4 %10.5f ms',[(T1-T0-Td)/Tf*1000])); writeln(Format('%10d %10d %10.8f %10.8f',[iPunkt.x,ipunkt.y,fout.x,fout.y]));
fPunkt.x := fPunkt.x+1; fPunkt.y := fPunkt.y+1; queryperformanceCounter(T0); for i := max downto 1 do FracTruncXY_SSE(fPunkt,iPunkt,fOut); queryperformanceCounter(T1); writeln(Format('SSE %10.5f ms',[(T1-T0-Td)/Tf*1000])); writeln(Format('%10d %10d %10.8f %10.8f',[iPunkt.x,ipunkt.y,fout.x,fout.y])); readln; end. |
Als Ergebnis Ahtlon64 1.8 Ghz auf dem Pentium M funktioniert FPU4 nicht
Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13:
| Durchlaeufe 1,00000000000000E+008
Nichts 113,89017 ms FPU 1 1349,49833 ms 4 2 0,14159298 0,41421366 FPU 2 679,08296 ms 5 3 0,14159298 0,41421366 FPU 3 646,48719 ms 6 4 0,14159298 0,41421366 FPU 4 649,59820 ms 7 5 0,14159298 0,41421366 SSE 674,67821 ms 8 6 0,14159298 0,41421366 |
Falls man diese Proceduren mit einer Form verwendet, dann braucht SSE plotzlich ueber 18 Sekunden bei nur 10e8 Durchlaeufen??
Wieso ist dort der Rest soviel schneller? Das liegt wohl daran, dass die leere Schleife so merkwuerdig langsam ist.
Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14:
| Memo1 Durchlaeufe 1,00000000000000E+008
Nichts 336,66430 ms FPU 1 1202,33354 ms 4 2 0,14159298 0,41421366 FPU 2 572,52388 ms 5 3 0,14159298 0,41421366 FPU 3 549,07816 ms 6 4 0,14159298 0,41421366 FPU 4 471,83259 ms 7 5 0,14159298 0,41421366 SSE 18756,69952 ms 8 6 0,14159298 0,41421366 |
Gruss Horst
P.S.
Das sind also ca. 12 CPU-Takte pro Rechnung
|
|
Spaceguide 
      
Beiträge: 552
(D3/D7/D8) Prof.
|
Verfasst: Do 11.05.06 20:35
Also deine Routine scheint jetzt wirklich recht flott zu sein, BenBE. Jetzt bleibt nur die Frage offen, warum die SSE Routine so jämmerlich abschneidet.
|
|
BenBE
      
Beiträge: 8721
Erhaltene Danke: 191
Win95, Win98SE, Win2K, WinXP
D1S, D3S, D4S, D5E, D6E, D7E, D9PE, D10E, D12P, DXEP, L0.9\FPC2.0
|
Verfasst: Do 11.05.06 21:08
@Horst: Teste bitte mal FPU3 mit FADDP in Zeile 100. Evtl. kann es sein, dass Du die Register-Reihenfolge manuell festlegen musst (zwecks Entfernen von ST(4)). Damit sollten dort nochmal ein paar Takte möglich sein.
@Form + SSE: Sollte man nicht FEMMS vor+nach Nutzung von SSE aufrufen???
_________________ Anyone who is capable of being elected president should on no account be allowed to do the job.
Ich code EdgeMonkey - In dubio pro Setting.
|
|
Spaceguide 
      
Beiträge: 552
(D3/D7/D8) Prof.
|
Verfasst: Do 11.05.06 21:19
Das mit FEMMS macht keinen Unterschied. Die SSE-Routine ist fast viermal langsamer als mit der FPU (AthlonXP), dabei werden hier zwei Floats gleichzeitig bearbeitet, was die FPU sequentiell machen muss. Ich verstehe die Welt nicht mehr 
|
|
Horst_H
      
Beiträge: 1654
Erhaltene Danke: 244
WIN10,PuppyLinux
FreePascal,Lazarus
|
Verfasst: Do 11.05.06 22:18
Hallo,
Ahtlon benutzt intern nur einen 64-Bit Bus fuer SSE-Daten und nicht mit 128 wie Pentium, die erheblich(Faktor 2 und mehr) schneller mit SSE arbeiten.
So, nach dem Neustart funktioniert auch SSE unter VCL bei mir wieder( genau 2-mal mit 403 ms und wieder 14032 ms, dann wieder 405 ms,396 ms grummmelgrummelmaeusemelk ??? ).
Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14:
| Memo1 Durchlaeufe 1,00000000000000E+008
Nichts 345,38552 ms FPU 1 1187,13943 ms 4 2 0,14159298 0,41421366 FPU 2 543,49617 ms 5 3 0,14159298 0,41421366 FPU 3 521,06203 ms 6 4 0,14159298 0,41421366 FPU 4 441,06723 ms 7 5 0,14159298 0,41421366 SSE 396,97448 ms 8 6 0,14159298 0,41421366 |
Wenn man die Leere Schleife mit 112 ms ansetzt wie beim console Programm sind die Zeiten um 233 ms zu erhoehen, also statt 396 ms eben 629 ms, also fast wieder die gleichen Zeiten.
Zum Pentium M 1.7 Ghz (Femms kennt nur AMD , also EMMS...)
Aber die Laufzeiten...
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:
| Nichts 493,19453 ms FPU 1 1334,78808 ms 4 2 0,14159298 0,41421366 FPU 2 915,60855 ms 5 3 0,14159298 0,41421366 FPU 3 1027,68760 ms 6 4 0,14159298 0,41421366 FPU 4 1808,26837 ms 7 5 0,14159298 0,41421366 SSE 850,41339 ms 8 6 0,14159298 0,41421366 Durchlaeufe 1,00000000000000E+008
Nichts 415,32150 ms FPU 1 1068,82830 ms 4 2 0,14159298 0,41421366 FPU 2 764,51476 ms 5 3 0,14159298 0,41421366 FPU 3 774,06263 ms 6 4 0,14159298 0,41421366 FPU 4 1498,81256 ms 7 5 0,14159298 0,41421366 SSE 16538,15499 ms<<<<<<<<<<<<<<<<<<<<<<<< 8 6 0,14159298 0,41421366 |
Ich glaube es liegt an dem Grafikartentreiber fuer die ATI 9600 (bei beiden Rechnern).
Vielleicht auch nur dann, wenn es eine solange Zeit am Stueck ist.
Man sieht deutlich, dass AMD auch verschiedene Arten schnell erledigt, aber BenBe's Version ist eindeutig die effektivste.
Gruss Horst
P.S.
3dnow funktioniert doch auch gut.
|
|
Horst_H
      
Beiträge: 1654
Erhaltene Danke: 244
WIN10,PuppyLinux
FreePascal,Lazarus
|
Verfasst: Do 11.05.06 23:21
Hallo,
FPU4 rundet und macht kein trunc-> ist also nur fuer positive Zahlen.
Fuer positive Zahlen und AMD 3dnow:
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: 26: 27: 28:
| procedure FracTruncXY_3dnow(const aPoint : TFloatPoint; var aIntOut : TPoint; var aFraction : TFloatPoint); ASM MOVQ MM0,[aPoint]; PF2ID MM1, MM0 MOVQ [aIntOut],MM1; PI2FD MM1, MM1 PFSUB MM0,MM1 MOVQ [aFraction],MM0 FEMMS end; Athlon64 Durchlaeufe 1,00000000000000E+008
Nichts 169,73275 ms FPU 1 1263,30106 ms 4 2 0,14159298 0,41421366 FPU 2 631,82416 ms 5 3 0,14159298 0,41421366 FPU 3 588,71700 ms 6 4 0,14159298 0,41421366 FPU 4 595,05635 ms 7 5 0,14159298 0,41421366 SSE 674,68268 ms 8 6 0,14159298 0,41421366 3dnow 505,10107 ms 9 7 0,14159298 0,41421366 |
Echtes trunc laut AMD ergibt dies, was aber viel langasamer ist.
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: 26: 27: 28: 29:
| procedure FracTruncXY_3dnow(const aPoint : TFloatPoint; var aIntOut : TPoint; var aFraction : TFloatPoint); const MABS : array [0..1] of cardinal = ($7FFFFFFF,$7FFFFFFF); TTTF : array [0..1] of cardinal = ($4B800000,$4B800000); ASM MOVQ MM0,[aPoint]; MOVQ MM3, [MABS] PF2ID MM1, MM0 MOVQ MM4, [TTTF] PAND MM3, MM0 PI2FD MM2, MM1 PCMPGTD MM3, MM4 MOVQ MM4, MM0 PFCMPGT MM2, MM4 MOVQ MM5,[aPoint] PAND MM0, MM3 PADDD MM1, MM2 PI2FD MM4, MM1 PANDN MM3, MM4 POR MM0, MM3 PFSUB MM5,MM0 MOVQ [aFraction],MM5 PF2ID MM0, MM0 MOVQ [aIntOut],MM0 FEMMS end; |
Gruss Horst
|
|
Spaceguide 
      
Beiträge: 552
(D3/D7/D8) Prof.
|
Verfasst: Fr 12.05.06 12:27
Hmm, also wenn ich mal in einer Konsolenapplikation teste, ist die SSE-Routine auf einmal reproduzierbar die schnellste:
AthlonXP:
Leer: 411ms
FPU/Pascal: 5535ms
BenBE_FPU: 3323ms
SSE: 2782ms
Du meinst das liegt an einem Grafikkartentreiber (hab auch eine ATI drin)? Wie kann das sein?
|
|
Horst_H
      
Beiträge: 1654
Erhaltene Danke: 244
WIN10,PuppyLinux
FreePascal,Lazarus
|
Verfasst: Fr 12.05.06 14:44
Hallo,
was kann das nur sein, heute habe ich keine Abweichung festgestellt, auch mit VCL nicht
Ein paar globale Variablen wie weiter oben.
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:
| queryperformancefrequency(Tf); fPunkt.x := pi; fPunkt.y := sqrt(2); max := 1000*1000*10; mittel := 0.0; For k := 0 to 99 do begin queryperformanceCounter(T0); for i := max downto 1 do FracTruncXY_SSE(fPunkt,iPunkt,fOut); queryperformanceCounter(T1); absZeit :=(T1-T0-Td)/Tf; mittel := (mittel*k+absZeit)/(k+1); If abs(absZeit/mittel-1.0) > 0.025then begin memo1.lines.add(Format('k:%4d %10.5f ms',[k,absZeit*1000.0])); memo1.lines.add(Format('%10.5f ms %10.5f ms',[absZeit*1000.0,mittel*1000.0])); end; end; memo1.lines.add(Format(' %10.5f ms',[absZeit*1000.0])); memo1.lines.add(Format('%10.5f ms %10.5f ms',[absZeit*1000.0,mittel*1000.0])); end; |
Ich dachte mir das nur bei Grafik SSE,MMX zum Zuge kommt, und welcher Treiber sollte dies sonst einsetzen.Zumal es eine der wenigen Gemeisamkeiten der beiden Rechner ist.
Oder macht dies WinXp mittlerweile auch?
Gruss Horst
P.S.:
Als Opera die E-mail's abholte, verdreifachte sich die Zeit, aber nicht der Faktor ~200 ,14 s statt 0.75 s
|
|
|