Delphi-PRAXiS
Seite 1 von 2  1 2      

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Programmieren allgemein (https://www.delphipraxis.net/40-programmieren-allgemein/)
-   -   Bitte Assembler-Routine verbessern (https://www.delphipraxis.net/105528-bitte-assembler-routine-verbessern.html)

alzaimar 23. Dez 2007 18:44


Bitte Assembler-Routine verbessern
 
Hier habe ich eine Routine vom FastCode-Project, das nach einem einzelnen Zeichen in einem String sucht. Nix besonderes, nur eben sauschnell. Leider fängt die Routine immer vorne an. Ich hätte gerne einen dritten Parameter (wie bei PosEx), bei dem die Funktion dann anfängt zu suchen. Leider kann ich kein Asm. Kann mir jemand helfen?

Hier die Routine:
Delphi-Quellcode:
function CharPos_JOH_SSE2_1_b(Ch : Char; const Str : AnsiString) : Integer;
asm
  test     edx, edx
  jz       @@NullString
  mov      ecx, [edx-4]
  push     ebx
  mov      ebx, eax
  cmp      ecx, 16
  jl       @@Small
@@NotSmall:
  mov      ah, al          {Fill each Byte of XMM1 with AL}
  movd     xmm1, eax
  pshuflw  xmm1, xmm1, 0
  pshufd   xmm1, xmm1, 0
@@First16:
  movups   xmm0, [edx]     {Unaligned}
  pcmpeqb  xmm0, xmm1       {Compare First 16 Characters}
  pmovmskb eax, xmm0
  test     eax, eax
  jnz      @@FoundStart    {Exit on any Match}
  cmp      ecx, 32
  jl       @@Medium        {If Length(Str) < 32, Check Remainder}
@@Align:
  sub      ecx, 16          {Align Block Reads}
  push     ecx
  mov      eax, edx
  neg      eax
  and      eax, 15
  add      edx, ecx
  neg      ecx
  add      ecx, eax
@@Loop:
  movaps   xmm0, [edx+ecx] {Aligned}
  pcmpeqb  xmm0, xmm1       {Compare Next 16 Characters}
  pmovmskb eax, xmm0
  test     eax, eax
  jnz      @@Found         {Exit on any Match}
  add      ecx, 16
  jle      @@Loop
  pop      eax             {Check Remaining Characters}
  add      edx, 16
  add      eax, ecx        {Count from Last Loop End Position}
  jmp      dword ptr [@@JumpTable2-ecx*4]
  nop
  nop
@@NullString:
  xor      eax, eax        {Result = 0}
  ret
  nop
@@FoundStart:
  bsf      eax, eax        {Get Set Bit}
  pop      ebx
  inc      eax             {Set Result}
  ret
  nop
  nop
@@Found:
  pop      edx
  bsf      eax, eax        {Get Set Bit}
  add      edx, ecx
  pop      ebx
  lea      eax, [eax+edx+1] {Set Result}
  ret
@@Medium:
  add      edx, ecx        {End of String}
  mov      eax, 16          {Count from 16}
  jmp      dword ptr [@@JumpTable1-64-ecx*4]
  nop
  nop
@@Small:
  add      edx, ecx        {End of String}
  xor      eax, eax        {Count from 0}
  jmp      dword ptr [@@JumpTable1-ecx*4]
  nop
@@JumpTable1:
  dd       @@NotFound, @@01, @@02, @@03, @@04, @@05, @@06, @@07
  dd       @@08, @@09, @@10, @@11, @@12, @@13, @@14, @@15, @@16
@@JumpTable2:
  dd       @@16, @@15, @@14, @@13, @@12, @@11, @@10, @@09, @@08
  dd       @@07, @@06, @@05, @@04, @@03, @@02, @@01, @@NotFound
@@16:
  add      eax, 1
  cmp      bl, [edx-16]
  je       @@Done
@@15:
  add      eax, 1
  cmp      bl, [edx-15]
  je       @@Done
@@14:
  add      eax, 1
  cmp      bl, [edx-14]
  je       @@Done
@@13:
  add      eax, 1
  cmp      bl, [edx-13]
  je       @@Done
@@12:
  add      eax, 1
  cmp      bl, [edx-12]
  je       @@Done
@@11:
  add      eax, 1
  cmp      bl, [edx-11]
  je       @@Done
@@10:
  add      eax, 1
  cmp      bl, [edx-10]
  je       @@Done
@@09:
  add      eax, 1
  cmp      bl, [edx-9]
  je       @@Done
@@08:
  add      eax, 1
  cmp      bl, [edx-8]
  je       @@Done
@@07:
  add      eax, 1
  cmp      bl, [edx-7]
  je       @@Done
@@06:
  add      eax, 1
  cmp      bl, [edx-6]
  je       @@Done
@@05:
  add      eax, 1
  cmp      bl, [edx-5]
  je       @@Done
@@04:
  add      eax, 1
  cmp      bl, [edx-4]
  je       @@Done
@@03:
  add      eax, 1
  cmp      bl, [edx-3]
  je       @@Done
@@02:
  add      eax, 1
  cmp      bl, [edx-2]
  je       @@Done
@@01:
  add      eax, 1
  cmp      bl, [edx-1]
  je       @@Done
@@NotFound:
  xor      eax, eax
  pop      ebx
  ret
@@Done:
  pop      ebx
end;
Und hier meine gewünschte Funktionsdeklaration
Delphi-Quellcode:
function CharPos_JOH_SSE2_1_b(Ch : Char; const Str : AnsiString; aStart : Integer = 1) : Integer;
Ich glaube, ich müsste nur zu der Adresse von 'Str' den Wert (aStart-1) hinzuaddieren und am Ende den Stack besser aufräumen, aber wie das geht weiss ich nicht.

Na? Erweicht sich ein Asm-Guru, mir die Routine anzupassen?

Frohes Fest an alle!

Dax 23. Dez 2007 19:30

Re: Bitte Assembler-Routine verbessern
 
Delphi-Quellcode:
function CharPos_JOH_SSE2_1_b(Ch : Char; const Str : AnsiString; aStart : Integer = 1) : Integer;
asm
  test     edx, edx
  jz       @@NullString
  mov      esi, ecx
  dec      esi
  mov      ecx, [edx-4]
  cmp      esi, ecx
  jle @@Continue
  xor      eax, eax
  ret
 
@@Continue:
  add      ecx, esi
  add      edx, esi
  push     ebx
  mov      ebx, eax
  cmp      ecx, 16
  jl       @@Small
@@NotSmall:
  mov      ah, al          {Fill each Byte of XMM1 with AL}
  movd     xmm1, eax
  pshuflw  xmm1, xmm1, 0
  pshufd   xmm1, xmm1, 0
@@First16:
  movups   xmm0, [edx]     {Unaligned}
  pcmpeqb  xmm0, xmm1       {Compare First 16 Characters}
  pmovmskb eax, xmm0
  test     eax, eax
  jnz      @@FoundStart    {Exit on any Match}
  cmp      ecx, 32
  jl       @@Medium        {If Length(Str) < 32, Check Remainder}
@@Align:
  sub      ecx, 16          {Align Block Reads}
  push     ecx
  mov      eax, edx
  neg      eax
  and      eax, 15
  add      edx, ecx
  neg      ecx
  add      ecx, eax
@@Loop:
  movaps   xmm0, [edx+ecx] {Aligned}
  pcmpeqb  xmm0, xmm1       {Compare Next 16 Characters}
  pmovmskb eax, xmm0
  test     eax, eax
  jnz      @@Found         {Exit on any Match}
  add      ecx, 16
  jle      @@Loop
  pop      eax             {Check Remaining Characters}
  add      edx, 16
  add      eax, ecx        {Count from Last Loop End Position}
  jmp      dword ptr [@@JumpTable2-ecx*4]
  nop
  nop
@@NullString:
  xor      eax, eax        {Result = 0}
  ret
  nop
@@FoundStart:
  bsf      eax, eax        {Get Set Bit}
  pop      ebx
  inc      eax             {Set Result}
  ret
  nop
  nop
@@Found:
  pop      edx
  bsf      eax, eax        {Get Set Bit}
  add      edx, ecx
  pop      ebx
  lea      eax, [eax+edx+1] {Set Result}
  ret
@@Medium:
  add      edx, ecx        {End of String}
  mov      eax, 16          {Count from 16}
  jmp      dword ptr [@@JumpTable1-64-ecx*4]
  nop
  nop
@@Small:
  add      edx, ecx        {End of String}
  xor      eax, eax        {Count from 0}
  jmp      dword ptr [@@JumpTable1-ecx*4]
  nop
@@JumpTable1:
  dd       @@NotFound, @@01, @@02, @@03, @@04, @@05, @@06, @@07
  dd       @@08, @@09, @@10, @@11, @@12, @@13, @@14, @@15, @@16
@@JumpTable2:
  dd       @@16, @@15, @@14, @@13, @@12, @@11, @@10, @@09, @@08
  dd       @@07, @@06, @@05, @@04, @@03, @@02, @@01, @@NotFound
@@16:
  add      eax, 1
  cmp      bl, [edx-16]
  je       @@Done
@@15:
  add      eax, 1
  cmp      bl, [edx-15]
  je       @@Done
@@14:
  add      eax, 1
  cmp      bl, [edx-14]
  je       @@Done
@@13:
  add      eax, 1
  cmp      bl, [edx-13]
  je       @@Done
@@12:
  add      eax, 1
  cmp      bl, [edx-12]
  je       @@Done
@@11:
  add      eax, 1
  cmp      bl, [edx-11]
  je       @@Done
@@10:
  add      eax, 1
  cmp      bl, [edx-10]
  je       @@Done
@@09:
  add      eax, 1
  cmp      bl, [edx-9]
  je       @@Done
@@08:
  add      eax, 1
  cmp      bl, [edx-8]
  je       @@Done
@@07:
  add      eax, 1
  cmp      bl, [edx-7]
  je       @@Done
@@06:
  add      eax, 1
  cmp      bl, [edx-6]
  je       @@Done
@@05:
  add      eax, 1
  cmp      bl, [edx-5]
  je       @@Done
@@04:
  add      eax, 1
  cmp      bl, [edx-4]
  je       @@Done
@@03:
  add      eax, 1
  cmp      bl, [edx-3]
  je       @@Done
@@02:
  add      eax, 1
  cmp      bl, [edx-2]
  je       @@Done
@@01:
  add      eax, 1
  cmp      bl, [edx-1]
  je       @@Done
@@NotFound:
  xor      eax, eax
  pop      ebx
  ret
@@Done:
  pop      ebx
end;
Ich hab kein Delphi, um es zu testen.. Aber ich vermute, dass es so läuft. Was ich hier tue, entspricht weitgehend deiner Vermutung: am Anfang sagen wir einfach, dass der String aStart Zeichen kürzer ist als tatsächlich und setzen den Anfang des Strings (für die Funktion) auf das Zeichen bei aStart.

bigg 23. Dez 2007 20:00

Re: Bitte Assembler-Routine verbessern
 
hi alzaimar,

die Funktion greift auf SSE2- und MMX-Register zu, die nicht bei jedem Prozessor verfügbar sind. Es könnte also durchaus sein, das die Funktion auf einem Athlon XP nette Fehlerchen wirft bzw. überhaupt nicht funktioniert. Aber frag doch mal John O'Harrow, ob er dir eine erweiterte Version bastelt/ zur Verfügung stellt. :mrgreen:

alzaimar 23. Dez 2007 21:52

Re: Bitte Assembler-Routine verbessern
 
Hi Dax, Hi bigg,

Erstmal Danke an Dich, Dax, für die Erweiterung. Das mit den Registern habe ich mir irgendwann mal so gedacht, zumal es bei den FastCode-Projekten eine Prozedure gibt, die anhand der CPU die korrekte Routine verwendet. So etwas in der Art sollte ich dann auch machen, um meine FastPos-Routine (Verbesserung des PosEx) allgemeingültig zu machen.

Aber ich meine, das ich auf meinem Arbeits-PC (irgendso ein AMD 64) eine Version am Laufen habe ...

Egal, ich check das mal.

Danke auf jeden Fall!

Und frohe Weihnacht an Alle.

dizzy 23. Dez 2007 23:53

Re: Bitte Assembler-Routine verbessern
 
Die Athlon64 können auch SSE2, die "alten" 32er Athlon XP und darunter jedoch noch nicht. Nur SSE (ohne 2), aber immerhin können die schon MMX. Man kann eigentlich mittlerweile fast von MMX und SSE ausgehen, XPs sind aber denke ich noch genug im Einsatz um das zu bedenken. Alles weitere sind Sonderfälle meiner Meinung nach, zumindest im Desktopbereich.

Amateurprofi 24. Dez 2007 09:54

Re: Bitte Assembler-Routine verbessern
 
Liste der Anhänge anzeigen (Anzahl: 1)
Zitat:

Zitat von Dax
Delphi-Quellcode:
function CharPos_JOH_SSE2_1_b(Ch : Char; const Str : AnsiString; aStart : Integer = 1) : Integer;
asm
  test     edx, edx
  jz       @@NullString
  mov      esi, ecx
  dec      esi
  mov      ecx, [edx-4]
  cmp      esi, ecx
  jle @@Continue
  xor      eax, eax
  ret
 
@@Continue:
  add      ecx, esi
  add      edx, esi
  push     ebx
  mov      ebx, eax
  cmp      ecx, 16
  jl       @@Small
  ...
  ...
end;
Ich hab kein Delphi, um es zu testen.. Aber ich vermute, dass es so läuft. Was ich hier tue, entspricht weitgehend deiner Vermutung: am Anfang sagen wir einfach, dass der String aStart Zeichen kürzer ist als tatsächlich und setzen den Anfang des Strings (für die Funktion) auf das Zeichen bei aStart.

@Dax:
Dann sollte es hinter @@Continue heißen
sub ecx,esi
Oder hab ich da was falsch verstanden?

Und mehr grundsätzlicher Natur :
ESI sollte nicht verändert werden (oder vorher gepushed und vor dem RET wieder gepopt werden).


@Alzaimar:
Ich habe meine PosEx - Funktion inzwischen erweitert, sie kann jetzt vorwärts und rückwärts suchen, in beiden Fällen mit beliebigem AStart. Und : Wenn nur ein Zeichen gesucht wird, dann werden (sowohl für Vorwärtssuche wie auch Rückwärtssuche) Routinen benutzt, die auf dem Code von John O'Harrow basieren.

alzaimar 24. Dez 2007 11:10

Re: Bitte Assembler-Routine verbessern
 
Hi Amateurprofi. Du solltest für kurze Pattern die Gewinner der FastCode-Challenge 'PosEx' untersuchen. sie sind doch schneller als der Quicksearch. Meine Tests (Worstcase) haben das jedenfalls gezeigt.

Kannst Du mir freundlicherweise die korrigierte Version des von Dax bereits modifizierten Codes einstellen. Für Dich ist das ein Klacks, aber für mich eine Nummer zu groß..

Frohes Fest!

Dax 24. Dez 2007 11:31

Re: Bitte Assembler-Routine verbessern
 
@Profi: Du hast Recht! Ist mir gestern gar nicht aufgefallen, Danke :)

Wegen ESI: Ich hab den Code jetzt auf ESI-Erhalt erweitert, weiß auch nicht mehr, wo ich mir gemerkt hab, dass man ESI einfach ändern kann.. :gruebel:

Delphi-Quellcode:
function CharPos_JOH_SSE2_1_b(Ch : Char; const Str : AnsiString; aStart : Integer = 1) : Integer;
asm
  test     edx, edx
  jz       @@NullString
  push     esi
  mov      esi, ecx
  dec      esi
  mov      ecx, [edx-4]
  cmp      esi, ecx
  jle @@Continue
  xor      eax, eax
  pop esi
  ret
 
@@Continue:
  sub      ecx, esi
  add      edx, esi
  push     ebx
  mov      ebx, eax
  cmp      ecx, 16
  jl       @@Small
@@NotSmall:
  mov      ah, al          {Fill each Byte of XMM1 with AL}
  movd     xmm1, eax
  pshuflw  xmm1, xmm1, 0
  pshufd   xmm1, xmm1, 0
@@First16:
  movups   xmm0, [edx]     {Unaligned}
  pcmpeqb  xmm0, xmm1       {Compare First 16 Characters}
  pmovmskb eax, xmm0
  test     eax, eax
  jnz      @@FoundStart    {Exit on any Match}
  cmp      ecx, 32
  jl       @@Medium        {If Length(Str) < 32, Check Remainder}
@@Align:
  sub      ecx, 16          {Align Block Reads}
  push     ecx
  mov      eax, edx
  neg      eax
  and      eax, 15
  add      edx, ecx
  neg      ecx
  add      ecx, eax
@@Loop:
  movaps   xmm0, [edx+ecx] {Aligned}
  pcmpeqb  xmm0, xmm1       {Compare Next 16 Characters}
  pmovmskb eax, xmm0
  test     eax, eax
  jnz      @@Found         {Exit on any Match}
  add      ecx, 16
  jle      @@Loop
  pop      eax             {Check Remaining Characters}
  add      edx, 16
  add      eax, ecx        {Count from Last Loop End Position}
  jmp      dword ptr [@@JumpTable2-ecx*4]
  nop
  nop
@@NullString:
  xor      eax, eax        {Result = 0}
  ret
  nop
@@FoundStart:
  bsf      eax, eax        {Get Set Bit}
  pop      ebx
  pop      esi
  inc      eax             {Set Result}
  ret
  nop
  nop
@@Found:
  pop      edx
  bsf      eax, eax        {Get Set Bit}
  add      edx, ecx
  pop      ebx
  pop      esi
  lea      eax, [eax+edx+1] {Set Result}
  ret
@@Medium:
  add      edx, ecx        {End of String}
  mov      eax, 16          {Count from 16}
  jmp      dword ptr [@@JumpTable1-64-ecx*4]
  nop
  nop
@@Small:
  add      edx, ecx        {End of String}
  xor      eax, eax        {Count from 0}
  jmp      dword ptr [@@JumpTable1-ecx*4]
  nop
@@JumpTable1:
  dd       @@NotFound, @@01, @@02, @@03, @@04, @@05, @@06, @@07
  dd       @@08, @@09, @@10, @@11, @@12, @@13, @@14, @@15, @@16
@@JumpTable2:
  dd       @@16, @@15, @@14, @@13, @@12, @@11, @@10, @@09, @@08
  dd       @@07, @@06, @@05, @@04, @@03, @@02, @@01, @@NotFound
@@16:
  add      eax, 1
  cmp      bl, [edx-16]
  je       @@Done
@@15:
  add      eax, 1
  cmp      bl, [edx-15]
  je       @@Done
@@14:
  add      eax, 1
  cmp      bl, [edx-14]
  je       @@Done
@@13:
  add      eax, 1
  cmp      bl, [edx-13]
  je       @@Done
@@12:
  add      eax, 1
  cmp      bl, [edx-12]
  je       @@Done
@@11:
  add      eax, 1
  cmp      bl, [edx-11]
  je       @@Done
@@10:
  add      eax, 1
  cmp      bl, [edx-10]
  je       @@Done
@@09:
  add      eax, 1
  cmp      bl, [edx-9]
  je       @@Done
@@08:
  add      eax, 1
  cmp      bl, [edx-8]
  je       @@Done
@@07:
  add      eax, 1
  cmp      bl, [edx-7]
  je       @@Done
@@06:
  add      eax, 1
  cmp      bl, [edx-6]
  je       @@Done
@@05:
  add      eax, 1
  cmp      bl, [edx-5]
  je       @@Done
@@04:
  add      eax, 1
  cmp      bl, [edx-4]
  je       @@Done
@@03:
  add      eax, 1
  cmp      bl, [edx-3]
  je       @@Done
@@02:
  add      eax, 1
  cmp      bl, [edx-2]
  je       @@Done
@@01:
  add      eax, 1
  cmp      bl, [edx-1]
  je       @@Done
@@NotFound:
  xor      eax, eax
  pop      ebx
  pop      esi
  ret
@@Done:
  pop      ebx
  pop      esi
end;

alzaimar 24. Dez 2007 13:12

Re: Bitte Assembler-Routine verbessern
 
Hi,

Dank Euch beiden habe ich nun eine Version von PosEx, die wesentlich schneller ist als die Delphi-RTL Variante, und zwar in allen Lebenslagen. Dabei handelt es sich eigentlich um drei Routinen:
1. Wenn nach einem String der Länge 1 gesucht wird, dann wird die hier verbesserte CharPos-Variante aufgerufen
2. Wenn nach einem String der Länge 2,3 oder 4 gesucht wird, dann wird der Gewinner der PosEx-FastCode-Challenge aufgerufen
3. Wenn der zu durchsuchende Text kürzer als 1000 Zeichen ist, dann wird ebenfalls der Gewinner der PosEx-FastCode-Challenge aufgerufen.
4. In allen anderen Fällen wird die vom Amateurprofi optimierte QuickSearch-Variante aufgerufen.

Ich eröffne einen neuen Thread und stelle 'meine' Routine, die ja in Wirklichkeit von John O'Hare, Amateurprofi, Dax und ein wenig von mir ist, vor.

QStorm 2. Mai 2011 11:12

AW: Re: Bitte Assembler-Routine verbessern
 
Zitat:

Zitat von alzaimar (Beitrag 717928)
Hi,
Ich eröffne einen neuen Thread und stelle 'meine' Routine, die ja in Wirklichkeit von John O'Hare, Amateurprofi, Dax und ein wenig von mir ist, vor.

Hi,

könntest du bitte den oben erwähnten Thread hier verlinken? Ich bin an der endgültigen Version der Routine interessiert, habe den Thread aber leider nicht finden können.

Danke :)

/QStorm


Alle Zeitangaben in WEZ +1. Es ist jetzt 06:25 Uhr.
Seite 1 von 2  1 2      

Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz