Wie wird das Registerflagbei CMPSD gesetzt?



  • @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