unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls;

type
  TForm1 = class(TForm)
    Label1: TLabel;
    Button2: TButton;
    procedure Button2Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

function getRDTSC: Int64;
asm
  rdtsc
end;

function StrLen1(const Str: PChar): Cardinal;
begin
  Result := 0;
  while (Str[Result] <> #0) do
  begin
    Inc(Result);
  end;
end;

function StrLen2(const Str: PChar): Cardinal;
asm
  // Result := 0;
  xor edx, edx

  jmp @StrLen2_compare

//  while (Str[Result] <> #0) do
@StrLen2_increment:
  // Inc(Result);
  inc edx

@StrLen2_compare:
  cmp byte ptr[eax + edx], $0
  jnz @StrLen2_increment

  mov eax, edx
  // end;
end;

function StrLen3(const Str: PChar): Cardinal;
asm
  mov edx, eax

  jmp @StrLen3_compare

@StrLen3_increment:
  inc eax

@StrLen3_compare:
  cmp byte ptr[eax], $0
  jnz @StrLen3_increment

  sub eax, edx
end;

// mmx version
function StrLen4(const Str: PChar): Cardinal;
asm
  mov edx, eax

  // Clear mmx1
  pxor mm0, mm0

  jmp @StrLen4_mmx_compare

@StrLen4_mmx_increment:
  add eax, 8

@StrLen4_mmx_compare:
  // mmx2 = memory[eax]
  movq mm1, [eax]
  
  // mmx2 = [mmx2 equals mmx1]
  pcmpeqb mm1, mm0

  movd ECX, mm1
  test ECX, ECX
  jz @StrLen4_mmx_increment
  // empty mmx state
  emms

  // found 0 in following 8 bytes
  jmp @StrLen4_compare

@StrLen4_increment:
  inc eax

@StrLen4_compare:
  cmp byte ptr[eax], $0
  jnz @StrLen4_increment

  sub eax, edx
end;

procedure TForm1.Button2Click(Sender: TObject);
const
  myCount = 100000;
var
  iTime: Int64;
  iResult: Integer;
  iIndex: Integer;
  s: String;
  p: PChar;
begin
  s := StringOfChar('0', 100000);
  p := PChar(s);
  iTime := getRDTSC;

  for iIndex := 1 to myCount do
  begin
    iResult := StrLen4(p);
  end;

  iTime := getRDTSC - iTime;
  iTime := iTime div myCount;
  MessageDlg('Time spent ' + IntToStr(iTime) + ' cpu cycles', mtInformation, [mbOK], 0);
  Label1.Caption := IntToStr(iResult);
end;

end.
