Einzelnen Beitrag anzeigen

Edlmann

Registriert seit: 19. Nov 2010
212 Beiträge
 
#1

[ASM / SSE] Vektoroperationen

  Alt 13. Jun 2012, 18:37
Nachmittag DPLer,

ich habe mich heute mal daran Gesetz, die SIMD-Extensions ein wenig genauer unter die Lupe zu nehmen,
speziell wie man diese zur Berechnung von Vektoren einsetzen kann. Ich hab dafür ein paar kleine Testroutinen gebastelt,
und hätte 2 Fragen:
1. Wo liegt noch Optimierungspotential?
2. Warum ist die normale Addition gegenüber der SSE-Single-Vector Addition nur minimal schneller?

(Messwerte für 2 Millionen Verticies operationen, einmal addieren je 2er Vektoren, 1x Multiplizieren:
Ganz normaler Delphi-Code: im Schnitt 109.000 Zykel
SSE-Single-Vector: im Schnitt 102.000 Zykel
Addieren ganzer Arrays: 62.736).

Zum Quelltext dahinter:
Die Vektoren sind als einfache Records spezifiziert

Delphi-Quellcode:
const
  ALENGTH = 2000000;

type
  TTestVec = packed record
    x, y, z, w: Single;
  end;

...

  Vecs1: array[0..ALENGTH] of TTestVec;
  Vecs2: array[0..ALENGTH] of TTestVec;
  ResVecs: array[0..ALENGTH] of TTestVec;

Und die Methoden(hier mal nur die zum Addieren, die zum Multiplizieren dementsprechend statt + / ADDPS mit * / MULPS)

Standard Delphi:
Delphi-Quellcode:
function AddVecs(const av1, av2: TTestVec): TTestVec;
begin
  Result.x := av1.x + av2.x;
  Result.y := av1.y + av2.y;
  Result.z := av1.z + av2.z;
  Result.w := av1.w + av2.w;
end;
Single-Vector-SSE:
Delphi-Quellcode:
function AddVecsSSE(const av1, av2: TTestVec): TTestVec;
var p1, p2: Pointer;
begin
  p1 := @av1.x;
  p2 := @av2.x;
  asm
    MOV ECX, p1
    MOV EDX, p2

    MOVUPS XMM0, [ECX]
    MOVUPS XMM1, [EDX]

    ADDPS XMM0, XMM1
    MOV ECX, @Result.x
    MOVUPS [ECX], XMM0
  end;
end;
und schließlich Array-SSE-Addieren:
Delphi-Quellcode:
procedure AddVecsArraySSE(const av1, av2: Pointer; const outarray: Pointer; const Length: Integer; const Strafing: Integer);
begin
  asm
    //ECX = 1st Array
    //EDX = 2nd Array
    //EBX = Length of the Array
    //EAX = Pointer to the outarray
    MOV ECX, av1
    MOV EDX, av2
    MOV EBX, Length
    MOV EAX, outarray

    @@LoopLabel:
    MOVUPS XMM0, [ECX]
    MOVUPS XMM1, [EDX]

    ADDPS XMM0, XMM1
    MOVUPS [EAX], XMM0
    //Die Pointer um Strafing verschieben
    ADD ECX, Strafing
    ADD EDX, Strafing
    ADD EAX, Strafing
    DEC EBX
    //Sind wir mit der Länbe bei -1, haben wir unser Array durch
    CMP EBX, -1
    JNE @@LoopLabel
  end;
end;


Und Aufgerufen wird der Spass mit:

Delphi-Quellcode:
for x := 0 to ALENGTH do
begin
  ResVecs[x] := AddVecs(Vecs1[x], Vecs2[x]);
end;

for x := 0 to ALENGTH do
begin
  ResVecs[x] := AddVecsSSE(Vecs1[x], Vecs2[x]);
end;

AddVecsArraySSE(@Vecs1[0].x, @Vecs2[0].x, @ResVecs[0].x, ALENGTH, 16);
Vielen Dank schonmal,
Edlmann

P.S. Ist nur ne Testimplementation, um zu schauen wie groß der Performancegewinn ist.

Geändert von Edlmann (13. Jun 2012 um 18:45 Uhr)
  Mit Zitat antworten Zitat