Einzelnen Beitrag anzeigen

Kas Ob.

Registriert seit: 3. Sep 2023
346 Beiträge
 
#29

AW: Floyd-Steinberg Dithering

  Alt 7. Nov 2023, 17:05
Der Benchmark ist Blödsinn, denn in TestMov wird der erste jle immer genommen, also ist der Branchpredictor ziemlich happy.
Branchy Code, bei dem ein conditional branch immer genommen wird oder nie genommen wird, ist für einen solchen Test Unfug.

Generell gilt: Conditional branches sind ok, wenn sie sehr predictable sind - d.h. es wird meist der eine Branch und selten der andere genommen. Sie funktionieren auch, wenn es immer abwechselnd ist, die Branchpredictors auf modernen CPUs sind ziemlich schlau. Schlimm wird es allerdings, wenn sie nicht vorhersehbar sind - selbst wenn es im Schnitt 50/50 ist aber ob der Sprung genommen wird oder nicht, ist z.B nicht immer abwechselnd, dann wirds schlimm und man ist mit einem cmov besser aufgehoben.

Übrigens schreibt man dec ecx und nicht sub ecx, 1 - dec ist 1 byte instruction, sub benötigt 3 byte

FWIW: https://codereview.stackexchange.com...he-range-0-255
Thank you very much, i have no idea what i was thinking missing all that.

here revised version of that benchmark with some semi-real data simulation over 1kb repeated million time.
Code:
uses
  System.SysUtils,
  Windows;

const
  Count = 1000000;
  DATA_LEN = 1024;

var
  Data: array[0..DATA_LEN - 1] of Integer;
  CData: array[0..DATA_LEN - 1] of Byte;

procedure TestMov;
asm
        mov    esi, 255
        mov    ecx, Count

@1:    mov    edi, 0

@2:    mov    edx, dword[Data + edi * 4]
        mov    eax, edx
        cmp    eax, 0
        jle    @Z
        cmp    eax, 255
        jbe    @S
        mov    Byte[CData + edi], 255
        jmp    @N

@Z:    xor    eax, eax

@S:    mov    Byte[CData + edi], al

@N:    inc    edi
        cmp    edi, DATA_LEN
        jle    @2
        dec    ecx
        jne    @1
end;

procedure TestCMovShort;
asm
        mov    esi, 255          // High Limit
        mov    ecx, Count

@1:    mov    edi, 0

@2:    mov    edx, dword[Data + edi * 4]
        XOR    eax, eax    // eax is destination value filled with the lowest value
        cmp    edx, esi    // comapare v (edx) with high value
        cmovg  eax, esi    // if bigger then take the highest esi
        cmovbe eax, edx    // if below or equal we fill value v (edx)
        mov    Byte[CData + edi], al
        inc    edi
        cmp    edi, DATA_LEN
        jl     @2
        dec    ecx
        jne    @1
end;

procedure Test;
var
  T: Cardinal;
  i: Integer;
begin
  Randomize;
  for i := Low(Data) to High(Data) do
    Data[i] := Random(256 * 3) - 256;

  T := GetTickCount;
  TestMov;
  T := GetTickCount - T;
  Writeln('TestMov ' + IntToStr(T));

  T := GetTickCount;
  TestCMovShort;
  T := GetTickCount - T;
  Writeln('TestCMovShort ' + IntToStr(T));

end;

begin
  Test;
  Readln;
end.
and the result
Code:
TestMov 1703
TestCMovShort 969
CMOV is almost twice faster.
Kas
  Mit Zitat antworten Zitat