News:

MASM32 SDK Description, downloads and other helpful links
MASM32.com New Forum Link
masmforum WebSite

Strange result with my StrCat function... Why ?

Started by jdoe, January 04, 2008, 08:14:29 AM

Previous topic - Next topic

jdoe

Hi,

I wrote this algo (which is imho a fast one) and I was not expecting linear results for each exit labels because of the design of this algo (all exit labels are different). But I try to understand why the timing is higher where I was not expecting it to be higher. The labels @0 and @3 are slower then the two other ones. I thought that was going to be the fast labels and I'm surprised it is not.

Someone have an idea why it is like that ?

P.S.: All my string functions returns the destination string length in EAX and pointer in EDX.



OPTION PROLOGUE:NONE
OPTION EPILOGUE:NONE

ALIGN 16
NOP

;
; Appends one string to another
;
; Returns the new destination string length in EAX and pointer in EDX
;
; p_lpszStr1 = Pointer to the destination string (must be large enough to contain both strings)
; p_lpszStr2 = Pointer to the string to be appended
;
AzmtStrCatA PROC p_lpszStr1:DWORD, p_lpszStr2:DWORD

    push dword ptr [esp+4]
    mov dword ptr [esp+8], esi
    mov esi, dword ptr [esp+12]
    call AzmtStrLenA

@S:
    mov ecx, dword ptr [esi]
    test ecx, 0FFh
    jz @0
    test ecx, 0FF00h
    jz @1
    test ecx, 0FF0000h
    jz @2
    test ecx, 0FF000000h
    jz @3
    mov dword ptr [edx+eax], ecx
    add esi, 4
    add eax, 4
    jmp @S

    align 16

@0:                              ; SLOW
    mov esi, dword ptr [esp+4]
    mov byte ptr [edx+eax], cl
    ret 8

    align 16

@1:
    mov esi, dword ptr [esp+4]
    mov word ptr [edx+eax], cx
    add eax, 1
    ret 8

    align 16

@2:
    mov esi, dword ptr [esp+4]
    mov word ptr [edx+eax], cx
    mov byte ptr [edx+eax+2], 0
    add eax, 2
    ret 8

    align 16

@3:                              ; SLOW
    mov esi, dword ptr [esp+4]
    mov dword ptr [edx+eax], ecx
    add eax, 3
    ret 8

AzmtStrCatA ENDP

OPTION PROLOGUE:PROLOGUEDEF
OPTION EPILOGUE:EPILOGUEDEF



NightWare

#1
it shouldn't be slower... or just a bit... coz those exit labels are just executed once and the loop do the same job until those exit labels... are you sure it's not a problem with your AzmtStrLenA algo ?

edit : i've adapted your code and made speed test, and there is 4 or 5 cycles of difference in fonction of the size of the string to add... is it why it's slow ?

note : pretty good result, near to mine...

jdoe

Quote from: NightWare on January 04, 2008, 10:51:02 PM
it shouldn't be slower... or just a bit... coz those exit labels are just executed once and the loop do the same job until those exit labels... are you sure it's not a problem with your AzmtStrLenA algo ?

edit : i've adapted your code and made speed test, and there is 4 or 5 cycles of difference in fonction of the size of the string to add... is it why it's slow ?

note : pretty good result, near to mine...

Hi NightWare,

You're right about the fact that there is not a big difference with these two labels (not twice as slow, only few clock cycles but enough to make it looks weird... 1-2 length OK, 3-4 length weird and so on). I made the same algo for StrCmp and StrCpy and there is always an exit label which is slower (the one I don't suspect) and I don't understand why. I'm sure AzmtStrLenA is not the problem because I don't use it with StrCmp and StrCpy and the same behavior appears.
Yes, I think I forgot to say it, it is the length of the string to be appended that make the clock cycles raising weirdly on those two labels ... even though my strings are aligned.

Est-ce trop demandé de voir ta version de StrCat puisqu'elle semble être très rapide aussi ?

En passant... Bonne année !!!
By the way...Happy new year to all our members !!!!


NightWare

the adaptation of your code,
ALIGN 16
FusionnerChainesAscii PROC

push edx ;; empiler edx
push esi ;; empiler esi
push edi ;; empiler edi


; premièrement on va trouver le zéro final de la chaine de destination
Label1: mov eax,DWORD PTR [edi] ;; placer le motlong de l'adresse actuelle dans eax
add edi,4 ;; incrémenter edi (l'adresse) de 4 (un dword)
lea edx,[eax-01010101h] ;; placer eax (- 1 à chaque octets du motlong) dans edx
xor eax,edx ;; inverser les bits en eax, en utilisant le résultat obtenu dans edx comme masque
and eax,80808080h ;; ne conserver que le bit de poids fort de chaques octets en eax
jz Label1 ;; si le filtrage est égal à 0, aller Label1
and eax,edx ;; ne conserver en eax que les bits positionnés en edx
jz Label1 ;; si le filtrage est égal à 0, aller Label1
bsf edx,eax ;; sinon, scanner le premier bit armé en eax, en commencant par la droite. et placer le numéro du bit en edx
sub edx,4 ;; soustraire 4 au numéro du bit obtenu
shr edx,3 ;; décaler edx à droite de 3 bits pour obtenir le nombre d'octets
lea edi,[edi+edx-4] ;; placer edi + edx - 1 dword dans edi
; et on effectue la copie
xor eax,eax ;; effacer eax (notre compteur d'octets)
@S:
mov edx,DWORD PTR [esi]
test edx,0000000FFh
jz @0
test edx,00000FF00h
jz @1
test edx,000FF0000h
jz @2
test edx,0FF000000h
jz @3
mov DWORD PTR [edi+eax],edx
add esi,DWORD
add eax,DWORD
jmp @S

align 16
@0:                              ; SLOW
mov BYTE PTR [edi+eax],0
add eax,edi ;; ajouter edi à eax

pop edi ;; désempiler edi
pop esi ;; désempiler esi
pop edx ;; désempiler edx
sub eax,edi ;; et on soustrait l'adresse originelle à eax pour obtenir la nouvelle taille de la chaîne
ret ;; retourner (sortir de la procédure)

align 16
@1:
mov WORD PTR [edi+eax],dx
add eax,edi ;; ajouter edi à eax
add eax,1

pop edi ;; désempiler edi
pop esi ;; désempiler esi
pop edx ;; désempiler edx
sub eax,edi ;; et on soustrait l'adresse originelle à eax pour obtenir la nouvelle taille de la chaîne
ret ;; retourner (sortir de la procédure)

align 16
@2:
mov WORD PTR [edi+eax],dx
mov BYTE PTR [edi+eax+2],0
add eax,edi ;; ajouter edi à eax
add eax,2

pop edi ;; désempiler edi
pop esi ;; désempiler esi
pop edx ;; désempiler edx
sub eax,edi ;; et on soustrait l'adresse originelle à eax pour obtenir la nouvelle taille de la chaîne
ret ;; retourner (sortir de la procédure)

align 16
@3:                              ; SLOW
mov DWORD PTR [edi+eax],edx
add eax,edi ;; ajouter edi à eax
add eax,3

pop edi ;; désempiler edi
pop esi ;; désempiler esi
pop edx ;; désempiler edx
sub eax,edi ;; et on soustrait l'adresse originelle à eax pour obtenir la nouvelle taille de la chaîne
ret ;; retourner (sortir de la procédure)
FusionnerChainesAscii ENDP


and mine,
ALIGN 16
;
; fusionner des chaines de caractères
;
; Réceptionne :
; esi = adresse de la chaîne source que l'on ajoutera
; edi = adresse de la chaîne de destination
;
; Retourne :
; eax = la taille de la nouvelle chaine obtenue
;
; syntaxe : FusionnerChainesAscii
;
FusionnerChainesAscii PROC
push ecx ;; empiler ecx
push edx ;; empiler edx
push edi ;; empiler edi

; premièrement on va trouver le zéro final de la chaine de destination
Label1: mov eax,DWORD PTR [edi] ;; placer le motlong de l'adresse actuelle dans eax
add edi,4 ;; incrémenter edi (l'adresse) de 4 (un dword)
lea edx,[eax-01010101h] ;; placer eax (- 1 à chaque octets du motlong) dans edx
xor eax,edx ;; inverser les bits en eax, en utilisant le résultat obtenu dans edx comme masque
and eax,80808080h ;; ne conserver que le bit de poids fort de chaques octets en eax
jz Label1 ;; si le filtrage est égal à 0, aller Label1
and eax,edx ;; ne conserver en eax que les bits positionnés en edx
jz Label1 ;; si le filtrage est égal à 0, aller Label1
bsf edx,eax ;; sinon, scanner le premier bit armé en eax, en commencant par la droite. et placer le numéro du bit en edx
sub edx,4 ;; soustraire 4 au numéro du bit obtenu
shr edx,3 ;; décaler edx à droite de 3 bits pour obtenir le nombre d'octets
lea edi,[edi+edx-4] ;; placer edi + edx - 1 dword dans edi
; et on effectue la copie
xor eax,eax ;; effacer eax (notre compteur d'octets)
jmp Label3 ;; aller Label3
Label2: add ecx,01010101h ;; ajouter ce que l'on a enlevé précedemment pour retrouver la valeur de eax
mov DWORD PTR [edi+eax],ecx ;; placer cette valeur à l'adresse de destination
add eax,4 ;; incrémenter esi (l'adresse) de 4 (un dword)
; nop ;; ) aucun alignement nécessaire pour un meilleur rendement
; nop ;; )
; nop ;; )
; nop ;; )
; nop ;; )
; nop ;; )
; nop ;; )
; nop ;; )
Label3: mov edx,DWORD PTR [esi+eax] ;; placer le motlong de l'adresse actuelle dans eax
lea ecx,[edx-01010101h] ;; placer eax (- 1 à chaque octets du motlong) dans ecx
xor edx,ecx ;; inverser les bits en eax, en utilisant le résultat obtenu dans ecx comme masque
and edx,80808080h ;; ne conserver que le bit de poids fort de chaques octets en eax
jz Label2 ;; si le filtrage est égal à 0, aller Label2
and edx,ecx ;; ne conserver en eax que les bits positionnés en ecx
jz Label2 ;; si le filtrage est égal à 0, aller Label2
add ecx,01010101h ;; ajouter ce que l'on a enlevé précedemment pour retrouver la valeur de edx
mov [edi+eax],cl ;; placer cl à l'adresse en edi+eax
test cl,cl ;; fixer les flags de cl
jz Label6 ;; si c'est égal à 0, aller Label5
mov [edi+eax+1],ch ;; placer ch à l'adresse en edi+eax+1
test ch,ch ;; fixer les flags de ch
jz Label5 ;; si c'est égal à 0, aller Label4
shr ecx,16 ;; décaler ecx à droite de 16 bits
mov [edi+eax+2],cl ;; placer cl à l'adresse en edi+eax+2
test cl,cl ;; fixer les flags de cl
jz Label4 ;; si c'est égal à 0, aller Label3
mov [edi+eax+3],ch ;; placer ch à l'adresse en edi+eax+3
inc eax ;; ajouter 1 à eax ) (optionnel) pour obtenir la taille de la chaine dans eax
Label4: inc eax ;; ajouter 1 à eax )
Label5: inc eax ;; ajouter 1 à eax )
Label6: add eax,edi ;; ajouter edi à eax

pop edi ;; désempiler edi
pop edx ;; désempiler edx
pop ecx ;; désempiler ecx
sub eax,edi ;; et on soustrait l'adresse originelle à eax pour obtenir la nouvelle taille de la chaîne
ret ;; retourner (sortir de la procédure)
FusionnerChainesAscii ENDP



happy new year too  :wink

jdoe

NightWare,

Nice algo   :U

-----

I didn't found a reason about the behavior of my algo but after all it's fast and I'm gonna keep it this way in my library.

And by the way, I made a little modification to prevent a register stall...


@S:
    mov ecx, dword ptr [esi]
    add esi, 4
    test ecx, 0FFh
    jz @0
    test ecx, 0FF00h
    jz @1
    test ecx, 0FF0000h
    jz @2
    test ecx, 0FF000000h
    jz @3
    mov dword ptr [edx+eax], ecx
    add eax, 4
    jmp @S



NightWare

why not using
mov ecx, dword ptr [esi+eax]
instead of
mov ecx, dword ptr [esi]
add esi, 4
?

one operation less inside a loop is always appreciate  :U
beside, if you add SUB ESI,EAX before the loop, you will not need to use an extra register

jdoe

Quote from: NightWare on January 06, 2008, 12:30:36 AM
why not using
mov ecx, dword ptr [esi+eax]
instead of
mov ecx, dword ptr [esi]
add esi, 4
?


Why not... Because it slip from my sight   :red

Thanks


OPTION PROLOGUE:NONE
OPTION EPILOGUE:NONE

ALIGN 16
DB 3 DUP (90h)

;
; Appends one string to another
;
; Returns the new destination string length in EAX and pointer in EDX
;
; p_lpszStr1 = Pointer to the destination string (must be large enough to contain both strings)
; p_lpszStr2 = Pointer to the string to be appended
;
AzmtStrCatA PROC p_lpszStr1:DWORD, p_lpszStr2:DWORD

    push dword ptr [esp+4]
    mov dword ptr [esp+8], esi
    mov esi, dword ptr [esp+12]
    call AzmtStrLenA
    sub esi, eax

@S:
    mov ecx, dword ptr [esi+eax]
    add eax, 4
    test ecx, 0FFh
    jz @0
    test ecx, 0FF00h
    jz @1
    test ecx, 0FF0000h
    jz @2
    test ecx, 0FF000000h
    jz @3
    mov dword ptr [edx+eax-4], ecx
    jmp @S

    align 8

@0:
    mov esi, dword ptr [esp+4]
    mov byte ptr [edx+eax-4], cl
    sub eax, 4
    ret 8

    align 8

@1:
    mov esi, dword ptr [esp+4]
    mov word ptr [edx+eax-4], cx
    sub eax, 3
    ret 8

    align 8

@2:
    mov esi, dword ptr [esp+4]
    mov word ptr [edx+eax-4], cx
    mov byte ptr [edx+eax-2], 0
    sub eax, 2
    ret 8

    align 8

@3:
    mov esi, dword ptr [esp+4]
    mov dword ptr [edx+eax-4], ecx
    sub eax, 1
    ret 8

AzmtStrCatA ENDP

OPTION PROLOGUE:PROLOGUEDEF
OPTION EPILOGUE:EPILOGUEDEF



NightWare

Quote from: jdoe on January 06, 2008, 12:00:56 AM
I didn't found a reason about the behavior of my algo
on the topic concerning "cycle high level" rockoon probably point the problem, it's possibly because of the alignment

jdoe

Quote from: NightWare on January 10, 2008, 01:10:54 AM
Quote from: jdoe on January 06, 2008, 12:00:56 AM
I didn't found a reason about the behavior of my algo
on the topic concerning "cycle high level" rockoon probably point the problem, it's possibly because of the alignment

My strings are always aligned.





NightWare


jdoe

Quote from: NightWare on January 10, 2008, 02:37:02 AM
Quote from: jdoe on January 10, 2008, 01:57:55 AM
My strings are always aligned.
the last bytes of the string too ?  :toothy

I can't say no.

@0 : Write one byte at an aligned address
@3 : Write one dword at an aligned address (this one really doesn't make sense to be slower)


NightWare

Quote from: NightWare on January 10, 2008, 02:37:02 AM
the last bytes of the string too ?  :toothy

omg, it's too late, i need to sleep... forget what i've said... i really need to sleep  :(