Wie wird das Registerflagbei CMPSD gesetzt?


  • Mod

    @cmovb: Das sieht ganz gut aus, was ergeben sich denn für Zeiten? Ein wenig loop-unrolling ist ggf. noch möglich.

    @FrEEzE2046: Die Kommentare zu cmovbs Code beachten:

    Außerdem vergleichst du hier:

    test ecx,0FFFFFFFCh
    

    ob in ECX 4294967292 steht - bedenke, in ECX steht ein DWORD-Typ (unsigned long). Ich denke du möchstest mit 4 vergleichen.

    test setzt die Flags, wie sie bei and entstehen würden. Das ist also korrekt.



  • FrEEzE2046 schrieb:

    @cmovb
    Nicht böse gemeint: Hast du nur die Geschwindigkeit getestet oder auch die Funktionalität? Deine Funktion liefert immer 1 zurück bei mir, egal ob es wirklich größer, kleiner oder sogar gleich ist.

    Du möchtest beliebig große Zahlen Vergleichen? - so hab ich das verstanden. Und ja, ich hab die Funktion getestet: sowohl auf Geschwindigkeit als auch auf Funktionalität!

    FrEEzE2046 schrieb:

    Was machst du da eigentlich? Du hast doch vollkommen falsche Adressen im EDI und ESI Register, da du einfach die nimmst, die vorher schon drin standen. Das kann so ja nicht funktionieren 😉

    nun, ich gehe mal davon aus, das du in der Lage bist die minimalen Anpassungen selber vor zu nehmen - Welcher Parameter wo drin ist hab ich ja extra angegeben!

    FrEEzE2046 schrieb:

    Außerdem vergleichst du hier:

    test ecx,0FFFFFFFCh
    

    ob in ECX 4294967292 steht - bedenke, in ECX steht ein DWORD-Typ (unsigned long). Ich denke du möchstest mit 4 vergleichen.

    test = and - überleg dir mal auf was geprüft wird

    FrEEzE2046 schrieb:

    Btw: Welche Rolle spielt der Core 2 Duo, wenn ich fragen darf.

    Die Ausführungszeiten(clocks) und Latenzen der Befehle unterscheiden sich zwischen verschieden CPU-Generation und -Herstellern.

    🕶



  • camper schrieb:

    @cmovb: Das sieht ganz gut aus, was ergeben sich denn für Zeiten? Ein wenig loop-unrolling ist ggf. noch möglich.

    @FrEEzE2046: Die Kommentare zu cmovbs Code beachten:

    Habe ich, aber sie sind doch einfach falsch. Wenn hier kein Funktionsheader angegeben ist, denke ich doch, dass er die selbe annimmt, wie ich sie gestellt hatte.
    Außerdem kenne ich keine Aufrufkonvention die direkt ins esi, edi Register schreibt.

    camper schrieb:

    test setzt die Flags, wie sie bei and entstehen würden. Das ist also korrekt.

    Das stimmt. Aber er möchte doch keine Konjunktion mit 4294967292 machen oder?



  • @camper: hab dazu nen kleines testbed (Konsole) in masm geschrieben, bzw immer zur Hand:

    repe cmpsd vs. loop
     - angabe in clocks
     - loop count: 10000000
    ---------------------------
     string size: 1
            loop: 4
      repe movsd: 88
    
     string size: 2
            loop: 11
      repe movsd: 93
    
     string size: 4
            loop: 5
      repe movsd: 89
    
     string size: 8
            loop: 12
      repe movsd: 94
    
     string size: 16
            loop: 24
      repe movsd: 105
    
     string size: 32
            loop: 48
      repe movsd: 125
    
     string size: 64
            loop: 97
      repe movsd: 165
    
     string size: 128
            loop: 193
      repe movsd: 245
    
     string size: 256
            loop: 387
      repe movsd: 406
    

    Zum Testen hab ich hier zwei gleiche Strings (0) gewählt - dass zwingt beide Algo‘s den gesamten String zu scannen. Der Cache spielt hier keine Rolle, da die Strings von beiden Funktionen gleich abgegriffen werden (hier gibt es also keine Benachteiligung).
    Wenn Interesse besteht, kann ich den Quellcode Posten.



  • cmovb schrieb:

    Wenn Interesse besteht, kann ich den Quellcode Posten.

    Ich bin sehr interessiert 🙂
    @cmovb: Übrigens, Du hast guten Stil, habe mir sogar die Zeit genommen, Deine Funktion zu lesen. Kannst Du bitte den vollständigen Code der Funktion posten? 👍



  • abc.w schrieb:

    Du hast guten Stil

    Dann wirs du gleich deine Meinung ändern (sag nur macros...) 😃

    include masm32rt.inc
    include C:\masm32\macros\timers.asm
    .686p
    .mmx
    .xmm
    
    .code
    start:
    
        print "repe cmpsd vs. loop",10,13
        print " - angabe in clocks",10,13
        print " - loop count: 10000000 ",10,13
        print "---------------------------",10,13
    
        .data       
            align 16
            s1 dd 64 dup (0)
            s2 dd 64 dup (0)
        .code
    
        _size = 1
        REPEAT 9
            print " string size: "
            print str$(_size),10,13
    
            counter_begin 10000000, REALTIME_PRIORITY_CLASS
                    mov esi,OFFSET s1
                    mov edi,OFFSET s2
                    mov ecx,_size
                    ; esi = lho 
                    ; edi = rho 
                    ; ecx = size
    
                    test ecx,0FFFFFFFCh 
                    lea edi,[edi+ecx-1] 
                    lea esi,[esi+ecx-1] 
                    jz  @CatStr(<@bytes>,%(_size))  
                    lea edi,[edi-3] 
                    lea esi,[esi-3] 
                @CatStr(<@dwords>,%(_size),<:>) 
                    mov eax,DWORD ptr [esi] 
                    mov edx,DWORD ptr [edi] 
                    lea edi,[edi-4] 
                    lea esi,[esi-4] 
                    lea ecx,[ecx-4] 
                    cmp eax,edx 
                    mov eax,0 
                    seta al 
                    sbb eax,0 
                    jnz  @CatStr(<@fin>,%(_size)) 
                    test ecx,0FFFFFFFCh 
                    jnz @CatStr(<@dwords>,%(_size)) 
                    test ecx,ecx 
                    jz  @CatStr(<@fin>,%(_size))  
    
                    lea edi,[edi+3] 
                    lea esi,[esi+3] 
               @CatStr(<@bytes>,%(_size),<:>) 
                    movzx eax,BYTE ptr [esi] 
                    movzx edx,BYTE ptr [edi] 
                    lea edi,[edi-1] 
                    lea esi,[esi-1] 
                    cmp eax,edx 
                    mov eax,0 
                    seta al 
                    sbb eax,0 
                    jnz  @CatStr(<@fin>,%(_size)) 
                    dec ecx 
                    jnz  @CatStr(<@bytes>,%(_size)) 
                @CatStr(<@fin>,%(_size),<:>)    
            counter_end
    
            push eax
            print "        loop: "
            pop eax
            print udword$(eax),10,13
    
            counter_begin 10000000, REALTIME_PRIORITY_CLASS
                    mov eax,OFFSET s1
                    mov edx,OFFSET s2
                    mov ecx,_size
    
                    std                                   
                    lea        esi, DWORD PTR [eax+ecx-1] 
                    lea        edi, DWORD PTR [edx+ecx-1] 
    
                    xor        eax, eax                   
                    mov        edx, ecx                   
    
                    shr        ecx, 2                     
                    jz         @CatStr(<@Rest>,%(_size)) 
    
                    lea        esi, DWORD PTR [esi-3]     
                    lea        edi, DWORD PTR [edi-3]     
    
                    repe    cmpsd 
                    jne         @CatStr(<@Exit>,%(_size))  
    
                   @CatStr(<@Rest>,%(_size),<:>) 
                    mov        ecx, edx 
                    and        ecx, 3                     
                    jz         @CatStr(<@Exit>,%(_size))  
    
                    lea        esi, DWORD PTR [esi+3]     
                    lea        edi, DWORD PTR [edi+3] 
    
                    repe    cmpsb 
    
                   @CatStr(<@Exit>,%(_size),<:>)  
                      cld                          
                    seta  al                       
                    sbb   eax, 0                   
            counter_end
    
            push eax
            print "  repe movsd: "
            pop eax
            print udword$(eax),10,13 ,10,13    
    
            _size = _size*2
        ENDM
        inkey
        exit
    
    end start
    


  • @cmovbs
    So, ich hatte jetzt auch mal die Zeit mir deinen Code zu Gemüte zu führen. Und er ist tatsächlich 6 Sekunden schneller als meiner (nach meinen Tests mit 4294967295 (MAX_UINT) vergleichen über 16 Byte identische Operanden.

    Ich habe mal deinen Code etwas verändert und war nochmals 7 Sekunden (!) und damit um die Hälfte schneller.

    push  edi
        push  esi
        push  ebx
    
        //mov   ebx, 0
        xor   ebx, ebx
    
        test  ecx, $FFFFFFFC
        lea   esi, DWORD PTR [eax+ecx-1]
        lea   edi, DWORD PTR [edx+ecx-1]
        jz    @@Bytes
    
        //lea   esi, [esi-3]
        //lea   edi, [edi-3]
        sub     esi, 3
        sub     edi, 3
    
      @@DWORDs:
        mov   eax, DWORD PTR [esi]
        mov   edx, DWORD PTR [edi]
    
        cmp   eax, edx
        //mov   eax, 0
        jnz   @@Exit
    
        //lea   esi, [esi-4]
        //lea   edi, [edi-4]
        //lea   ecx, [ecx-4]
        sub   esi, 4
        sub   edi, 4
        sub   ecx, 4
    
        test  ecx, $FFFFFFFC
        jnz   @@DWORDs
        test  ecx, ecx
        jz    @@Exit
    
        //lea   esi, [esi+3]
        //lea   edi, [edi+3]
        add   esi, 3
        add   edi, 3
    
      @@Bytes:
        movzx eax, BYTE PTR [esi]
        movzx edx, BYTE PTR [edi]
    
        //lea   edi, [edi-1]
        //lea   esi, [esi-1]
        dec   edi
        dec   esi
    
        cmp   eax, edx
        //mov   eax, 0
        jnz   @@Exit
    
        dec   ecx
        jnz   @@Bytes
    
      @@Exit:
        seta  bl
        sbb   ebx, 0
        mov   eax, ebx
    
        pop   ebx
        pop   esi
        pop   edi
    


  • gut 👍
    Auf die Idee, die Conditionals aus der Schleife zu ziehen, hätte ich Ansicht auch kommen sollen 😃



  • BTW: Wie groß sind den die Zahlen maximal - bei 16 Byte vergleicht man ohne Schleife. Des weiteren wäre es interessant zu wissen, wie die Zahlen im Speicher ausgerichtet sind (align).



  • Hallo,

    in meiner Testumgebung hatte ich ein Alignment von 4. Das erste Bit eines jeden Bytes habe ich testweise gesetzt. Der Byte loop wurde nicht gebraucht, dass ist richtig.

    Gestern war es aber schon spät. Ich denke ich werde heute noch ein paar Tests machen und ggf. optimieren.

    Durch die Verwendung des EBX Registers spart man noch etwas Zeit ein, da man auf ein lästiges mov verzichten kann. Ist aber natürlich Ansichtssache das EBX Register hier unberührt zu lassen.


Anmelden zum Antworten