StringCompare in ASM

    • Offizieller Beitrag

    Meine Assembler-Erfahrungen gehen weiter. Jetzt habe ich mir mal den Umgang mit Strings vorgenommen.

    Wie übergibt man Strings von AutoIt an Assembler?

    Und wie kann man in Assembler zwei Strings miteinander vergleichen?

    So nebenbei ist dann noch eine Assemblerfunktion zum ermitteln der Stringlänge entstanden.

  • Hi,

    Wie übergibt man Strings von AutoIt an Assembler?

    Hier habe ich das schon mal behandelt. Zu beachten ist, dass AutoIt bei Verwendung von Pointern auf Variablen immer (!) eine Kopie anlegt, mit dessen Pointer dann gearbeitet wird. Dann reduziert sich das Script zu

    Bei "kleinen" Daten wie int/float/dword oder Strings mit Größen von einigen Bytes usw ist das idR kein Problem, aber bei großen Strings übersteigt teilweise das Erstellen der Kopie in AutoIt die Laufzeit des ASM-Programms!

    Nach Möglichkeit sollten daher bei großen Datenmengen die auch noch mehrmals bearbeitet werden sollen, wie auch im oberen Script gezeigt, die Daten in "eigene" Structs gepackt werden.

    Btw. ist die Programmierung der "schnellsten" Stringlen-Funktion eine Aufgabe für ASM-Programmierer seit anbeginn aller Zeiten...und ein guter Einstieg in die Verwendung von SSE...16Bytes auf einen Schlag vergleichen FTW:rock:

    ciao
    Andy


    "Schlechtes Benehmen halten die Leute doch nur deswegen für eine Art Vorrecht, weil keiner ihnen aufs Maul haut." Klaus Kinski
    "Hint: Write comments after each line. So you can (better) see what your program does and what it not does. And we can see what you're thinking what your program does and we can point to the missunderstandings." A-Jay

    Wie man Fragen richtig stellt... Tutorial: Wie man Script-Fehler findet und beseitigt...X-Y-Problem

    4 Mal editiert, zuletzt von Andy (28. Dezember 2017 um 08:33)

    • Offizieller Beitrag

    Zu beachten ist, dass AutoIt bei Verwendung von Pointern auf Variablen immer (!) eine Kopie anlegt, mit dessen Pointer dann gearbeitet wird. Dann reduziert sich das Script zu

    Oh, ok!

    Das vereinfacht zumindest die Verwendung von kurzen Strings.

    Btw. ist die Programmierung der "schnellsten" Stringlen-Funktion eine Aufgabe für ASM-Programmierer seit anbeginn aller Zeiten...und ein guter Einstieg in die Verwendung von SSE...16Bytes auf einen Schlag vergleichen FTW

    Naja, ab welcher Stringlänge macht sich eine solche Optimierung denn bemerkbar?

    Meine obige Funktion habe ich übrigens auch noch etwas optimiert:

    AutoIt
        StringLen:                                    ; eax = Pointer auf den String
            mov ecx,-1                                ; ecx = Counter (auf -1 setzen)
            @CountLen:                                ; Schleife
                inc ecx                               ; ecx++
                test byte[eax+ecx],0xff               ; wenn "Zeichen and 0xff" <> 0
                jnz @CountLen                         ; dann Schleife fortsetzen
            inc ecx                                   ; ecx++ (Nullbyte mitzaehlen)
            ret                                       ; return = ecx = Anzahl der Zeichen
  • Naja, ab welcher Stringlänge macht sich eine solche Optimierung denn bemerkbar?

    Es geht um Clockticks pro Zeichen, je weniger, desto besser. Bei langen Strings werden deshalb bei guten String/Textbe-(bzw. ver-)arbeitungsprogrammen die Stringlängen genau EIN MAL berechnet und dann im Handle mit abgespeichert. Jede Funktion bekommt somit mit einem DWORD-Zugriff die Länge des Strings. Jeder Tastendruck, um einen Buchstaben bspw. ein Zeichen irgendwo einzutippern, erhöht dann auch automatisch den Stringlen-Counter.....

    test byte[eax+ecx],0xff ; wenn "Zeichen and 0xff" <> 0

    Auf das TEST wollte ich dich auch schon aufmerksam machen, gerade bspw. Test eax,eax (prüft eax auf 0 ) benötigt nur 2 Bytes in der Prozessorpipeline und einen Takt.

  • Na klar! Also passt man die Größe des Speicherbereichs entsprechend an. Und natürlich auch die 16-Byte-aligned Startadresse. Dafür hatte ich die Funktion _dllstructcreate64() in AssembleIt vorgesehen.

    Dort hinein die Daten, und alles geht glatt.

    Bei Bitmaps ist es einfacher, der Startpointer ist durch die entsprechenden GDI-Funktionen immer 16-Byte-aligned.

    Über die Länge der Bitmap kann man auch festzustellen, ob und wieviele Bytes ggf. "anzuhängen" sind, um eine glatt durch 16 teilbare Größe zu erhalten.

    Für die Verwendung von 256-Bit (das sind die YMM-Register für den 64-Bit-Modus von SSE) oder gar 512-Bit AVX gilt entsprechendes!

    • Offizieller Beitrag

    Das heißt, wenn ich SSE verwenden will, dann muss der Anfang des Speicherbereichs 16 Byte-aligned sein und er muss auch in der Größe immer durch 16 teilbar sein?

    Für einen String, der beispielsweise 33 Byte lang ist, muss ich also 48 Bytes reservieren und den dann auch noch auf eine 16-Byte-Adresse ausrichten?

    Und wie sieht das mit der Übergabe bei AutoIt aus? Zum Beispiel bei der obigen Stringübergabe. Die Adresse scheint 16-Byte-aligned zu sein, aber ist auch die Größe korrekt?

  • Für einen String, der beispielsweise 33 Byte lang ist, muss ich also 48 Bytes reservieren und den dann auch noch auf eine 16-Byte-Adresse ausrichten?

    Exakt. Dafür bearbeitest du aber 128Bit / 16 Bytes/ 8 Words / 4 Dwords oder 2 Qwords mit einem SSE-Befehl in einem einzigen Takt!

    Am Anfang des Scriptes einen String aus 16 Nullbytes erstellen und dann an den String anhängen wäre auch eine Möglichkeit.

    Und wie sieht das mit der Übergabe bei AutoIt aus? Zum Beispiel bei der obigen Stringübergabe. Die Adresse scheint 16-Byte-aligned zu sein, aber ist auch die Größe korrekt?

    Keine Ahnung, ob Strings 16-Byte aligned in AutoIt angelegt sind. Könnte man mal eruieren. Da AutoIt imho auf C++-Füßen steht, könnte das sein....Sagen wir mal so, wenn ICH einen Compiler geschrieben hätte, dann wären alle dessen Daten grundsätzlich aligned angelegt^^. Könnte ja sein, dass jemand ausnahmsweise mal "schnelle" Routinen schreiben wollte und sich keine (kaum) Gedanken über Prozessorcache usw. machen will/muss:Face:

    • Offizieller Beitrag

    Ich habe im Netz eine "strlenSSE2.asm" von Agner Fog gefunden. Die sieht recht gut aus!

    Damit habe ich jetzt mal ein Testprogramm geschrieben, welches 2 Strings (mit jeweils 10 Mio. Chars) vergleicht.

    Einmal mit dem Befehl StringCompare von AutoIt und einmal mit meiner ASM-Version davon. Und obwohl StringCompare ein interner AutoIt-Befehl ist, gewinnt die ASM-Version (6.7 ms zu 17.4 ms) deutlich. :)

    • Offizieller Beitrag

    Ach Mist, das vergleichen von Strings geht ja noch viel einfacher. :S

    Wenn man die Schleife selbst macht, dann braucht man vorher gar nicht die Stringlänge ermitteln.

    Und fairerweise muss man StringCompare unter AutoIt auch mit "1" oder "2" als dritten Parameter starten (geht schneller).

    Somit liegt die ASM-Version nur knapp vor der AutoIt-Version (5.9 ms zu 6.7 ms).