News:

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

Slignt tweak of Jibz's WCRT.LIB strcpy

Started by hutch--, June 06, 2005, 12:33:00 PM

Previous topic - Next topic

hutch--

Its fun to actually play with someone elses code occasionally so here is a PIV version of the asm source in Jibz's wcrt library. The rewrite appears to abe about 18 - 20% faster but has a slightly larger instruction count.


; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
    include \masm32\include\masm32rt.inc
; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««

comment * -----------------------------------------------------
                        Build this  template with
                       "CONSOLE ASSEMBLE AND LINK"
        ----------------------------------------------------- *

    strcpy  PROTO C :DWORD,:DWORD
    strcpyj PROTO C :DWORD,:DWORD

    .code

start:
   
; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««

    call main
    exit

; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««

main proc

    LOCAL pstr  :DWORD
    LOCAL pbuf  :DWORD
    LOCAL buffer[64]:BYTE

    mov pbuf, ptr$(buffer)
    sas pstr, "This is a test of strcpy"

    invoke GetTickCount
    push eax

    push esi
    mov esi, 10000000

  @@:
    invoke strcpy,pbuf,pstr
    sub esi, 1
    jnz @B

    pop esi

    invoke GetTickCount
    pop ecx
    sub eax, ecx

    print str$(eax),13,10

    ret

main endp

; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««

align 16

OPTION PROLOGUE:NONE
OPTION EPILOGUE:NONE

strcpy proc C dst:DWORD,src:DWORD

    sub eax, eax                ; clear EAX
    mov [esp-4], esi            ; preserve ESI on the stack

    mov ecx, [esp+4]            ; destination in ECX
    mov edx, [esp+8]            ; source in EDX
    mov esi, -1                 ; preload ESI at -1

  align 4
  @@:
    add esi, 1
    mov al, [edx+esi]
    mov [ecx+esi], al
    test al, al
    jnz @B

    mov esi, [esp-4]            ; restore ESI

    mov eax, [esp+8]

    ret

strcpy endp

OPTION PROLOGUE:PrologueDef
OPTION EPILOGUE:EpilogueDef

; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««

align 16

OPTION PROLOGUE:NONE
OPTION EPILOGUE:NONE

strcpyj proc C dst:DWORD,src:DWORD

    ; char *strcpy(char *s, const char *ct)

    _ct$ = 8
    _s$  = 4

    mov    ecx, [esp + _s$]
    mov    edx, [esp + _ct$]

    push   ecx

  @@:
    mov    al, [edx]
    inc    edx
    mov    [ecx], al
    inc    ecx
    test   al, al
    jnz    @B

    pop    eax

    ret

strcpyj endp

OPTION PROLOGUE:PrologueDef
OPTION EPILOGUE:EpilogueDef

; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««

end start
Download site for MASM32      New MASM Forum
https://masm32.com          https://masm32.com/board/index.php

Jibz

The P4 version is roughly 15% slower than the original on my Athlon64. Speed optimization in general is hopeless these days :toothy.

hutch--

Probably.  :green

How does it benchmark on PII, PIII and 32 bit AMD ?
Download site for MASM32      New MASM Forum
https://masm32.com          https://masm32.com/board/index.php

Mark Jones

"To deny our impulses... foolish; to revel in them, chaos." MCJ 2003.08

hutch--

Mark,

I was interested to see the timing for the second procedure as well, just change the name from strcpy to strcpyj to get the difference.

LATER :

Here is a modified version that tests both algos 8 times, averages the results and displays them. You can get some different results by turning the high priority off and on.


; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
    include \masm32\include\masm32rt.inc
; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««

comment * -----------------------------------------------------
                        Build this  template with
                       "CONSOLE ASSEMBLE AND LINK"
        ----------------------------------------------------- *

    strcpy  PROTO C :DWORD,:DWORD
    strcpyj PROTO C :DWORD,:DWORD

    set_priority equ 0  ; change to 1 to set high priority

    .code

start:
   
; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««

    call main
    exit

; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««

main proc

    LOCAL pstr  :DWORD
    LOCAL pbuf  :DWORD
    LOCAL var1  :DWORD
    LOCAL var2  :DWORD
    LOCAL buffer[64]:BYTE

    mov pbuf, ptr$(buffer)
    sas pstr, "This is a test of strcpy"

    mov var1, 0
    mov var2, 0

    IF set_priority
  ; ----------------------
  ; a couple of empty runs
  ; ----------------------
    invoke strcpy,pbuf,pstr
    invoke strcpyj,pbuf,pstr
    invoke strcpy,pbuf,pstr
    invoke strcpyj,pbuf,pstr

    invoke SetPriorityClass,FUNC(GetCurrentProcess),REALTIME_PRIORITY_CLASS
    ENDIF

    REPEAT 8

    invoke GetTickCount
    push eax

    push esi
    mov esi, 10000000

  @@:
    invoke strcpy,pbuf,pstr
    sub esi, 1
    jnz @B

    pop esi

    invoke GetTickCount
    pop ecx
    sub eax, ecx

    add var1, eax

    print str$(eax)," strcpy",13,10

    invoke GetTickCount
    push eax

    push esi
    mov esi, 10000000

  @@:
    invoke strcpyj,pbuf,pstr
    sub esi, 1
    jnz @B

    pop esi

    invoke GetTickCount
    pop ecx
    sub eax, ecx

    add var2, eax

    print str$(eax)," strcpyj",13,10

    ENDM

    IF set_priority
    invoke SetPriorityClass,FUNC(GetCurrentProcess),NORMAL_PRIORITY_CLASS
    ENDIF

    shr var1, 3

    print "Average strcpy "
    print str$(var1)," MS",13,10

    shr var2, 3

    print "Average strcpyj "
    print str$(var2)," MS",13,10

    ret

main endp

; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««

align 16

OPTION PROLOGUE:NONE
OPTION EPILOGUE:NONE

strcpy proc C dst:DWORD,src:DWORD

    sub eax, eax                ; clear EAX
    mov [esp-4], esi            ; preserve ESI on the stack

    mov ecx, [esp+4]            ; destination in ECX
    mov edx, [esp+8]            ; source in EDX
    mov esi, -1                 ; preload ESI at -1

  align 16
  @@:
    add esi, 1
    mov al, [edx+esi]
    mov [ecx+esi], al
    test al, al
    jnz @B

    mov esi, [esp-4]            ; restore ESI

    mov eax, [esp+8]

    ret

strcpy endp

OPTION PROLOGUE:PrologueDef
OPTION EPILOGUE:EpilogueDef

; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««

align 16

OPTION PROLOGUE:NONE
OPTION EPILOGUE:NONE

strcpyj proc C dst:DWORD,src:DWORD

    ; char *strcpy(char *s, const char *ct)

    _ct$ = 8
    _s$  = 4

    mov    ecx, [esp + _s$]
    mov    edx, [esp + _ct$]

    push   ecx

  align 16                  ; <<< modified label alignment
  @@:
    mov    al, [edx]
    inc    edx
    mov    [ecx], al
    inc    ecx
    test   al, al
    jnz    @B

    pop    eax

    ret

strcpyj endp

OPTION PROLOGUE:PrologueDef
OPTION EPILOGUE:EpilogueDef

; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««

end start
Download site for MASM32      New MASM Forum
https://masm32.com          https://masm32.com/board/index.php

Mark Jones

High priority:

Average strcpy 521 MS
Average strcpyj 451 MS


Normal priority:

Average strcpy 584 MS
Average strcpyj 507 MS

"To deny our impulses... foolish; to revel in them, chaos." MCJ 2003.08

hutch--

Thanks Mark.

Theses are the results I get on my PIV.


Normal priority
515 strcpy
594 strcpyj
516 strcpy
609 strcpyj
500 strcpy
609 strcpyj
500 strcpy
610 strcpyj
500 strcpy
593 strcpyj
516 strcpy
594 strcpyj
500 strcpy
609 strcpyj
516 strcpy
609 strcpyj
Average strcpy 507 MS
Average strcpyj 603 MS

Real time priority
500 strcpy
594 strcpyj
500 strcpy
610 strcpyj
484 strcpy
594 strcpyj
500 strcpy
593 strcpyj
500 strcpy
610 strcpyj
500 strcpy
578 strcpyj
516 strcpy
593 strcpyj
500 strcpy
610 strcpyj
Average strcpy 500 MS
Average strcpyj 597 MS


Here are the results on my AMD Sempron 2.4


Normal Priority
578 strcpy
500 strcpyj
562 strcpy
516 strcpyj
578 strcpy
500 strcpyj
563 strcpy
515 strcpyj
594 strcpy
500 strcpyj
563 strcpy
500 strcpyj
562 strcpy
531 strcpyj
610 strcpy
500 strcpyj
Average strcpy 576 MS
Average strcpyj 507 MS

Real Time Priority
562 strcpy
485 strcpyj
562 strcpy
485 strcpyj
578 strcpy
547 strcpyj
562 strcpy
484 strcpyj
563 strcpy
500 strcpyj
547 strcpy
500 strcpyj
578 strcpy
594 strcpyj
562 strcpy
485 strcpyj
Average strcpy 564 MS
Average strcpyj 510 MS


It would appears that AMD is still weak in terms of complex addressing mode code as was the old K6-2 in the PIII era.

LATER AGAIN :

An interesting result, change the INC to ADD in Jibz's algo and it runs in almost identical time to the tweaked version on the PIV. It seems to be slower on the AMD though.
Download site for MASM32      New MASM Forum
https://masm32.com          https://masm32.com/board/index.php

hutch--

I have been playing with the two algos on the Sempron 2.4 and have modified the two algos accordingly

The WCRT version needs the label to be aligned by at least 8, better 16 to be faster but I have done a re-order mod on the other version to seperate the read after write to AL which has brought it down close to the WCRT version on the Sempron. It is still about 18 - 20% faster on the PIV.


; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
    include \masm32\include\masm32rt.inc
; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««

comment * -----------------------------------------------------
                        Build this  template with
                       "CONSOLE ASSEMBLE AND LINK"
        ----------------------------------------------------- *

    strcpy  PROTO C :DWORD,:DWORD
    strcpyj PROTO C :DWORD,:DWORD

    set_priority equ 0  ; change to 1 to set high priority

    .code

start:
   
; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««

    call main
    exit

; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««

main proc

    LOCAL pstr  :DWORD
    LOCAL pbuf  :DWORD
    LOCAL var1  :DWORD
    LOCAL var2  :DWORD
    LOCAL void  :DWORD
    LOCAL buffer[128]:BYTE

    mov pbuf, ptr$(buffer)
    sas pstr, "This is a test of strcpy"

    mov var1, 0
    mov var2, 0

    IF set_priority
  ; ----------------------
  ; a couple of empty runs
  ; ----------------------
    invoke strcpy,pbuf,pstr
    invoke strcpyj,pbuf,pstr
    invoke strcpy,pbuf,pstr
    invoke strcpyj,pbuf,pstr

    invoke SetPriorityClass,FUNC(GetCurrentProcess),REALTIME_PRIORITY_CLASS
    ENDIF

    REPEAT 8

    invoke GetTickCount
    push eax

    push esi
    mov esi, 10000000

  @@:
    invoke strcpy,pbuf,pstr
    sub esi, 1
    jnz @B

    pop esi

    invoke GetTickCount
    pop ecx
    sub eax, ecx

    add var1, eax

    print str$(eax)," strcpy",13,10

    invoke GetTickCount
    push eax

    push esi
    mov esi, 10000000

  @@:
    invoke strcpyj,pbuf,pstr
    sub esi, 1
    jnz @B

    pop esi

    invoke GetTickCount
    pop ecx
    sub eax, ecx

    add var2, eax

    print str$(eax)," strcpyj",13,10

    ENDM

    IF set_priority
    invoke SetPriorityClass,FUNC(GetCurrentProcess),NORMAL_PRIORITY_CLASS
    ENDIF

    shr var1, 3

    print "Average strcpy "
    print str$(var1)," MS",13,10

    shr var2, 3

    print "Average strcpyj "
    print str$(var2)," MS",13,10

    mov void, input("press Enter to exit")

    ret

main endp

; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««

align 16

OPTION PROLOGUE:NONE
OPTION EPILOGUE:NONE

strcpy proc C dst:DWORD,src:DWORD

    mov [esp-4], esi            ; preserve ESI on the stack

    mov ecx, [esp+4]            ; destination in ECX
    mov edx, [esp+8]            ; source in EDX
    mov esi, -1                 ; preload ESI at -1

  align 16
  @@:
    mov al, [edx+esi+1]
    add esi, 1
    mov [ecx+esi], al
    test al, al
    jnz @B

    mov esi, [esp-4]            ; restore ESI
    mov eax, [esp+8]

    ret

strcpy endp

OPTION PROLOGUE:PrologueDef
OPTION EPILOGUE:EpilogueDef

; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««

align 16

OPTION PROLOGUE:NONE
OPTION EPILOGUE:NONE

strcpyj proc C dst:DWORD,src:DWORD

    ; char *strcpy(char *s, const char *ct)

    _ct$ = 8
    _s$  = 4

    mov    ecx, [esp + _s$]
    mov    edx, [esp + _ct$]

    push   ecx

  align 16      ; << required on the Sempron.
  @@:
    mov    al, [edx]
    inc    edx
    mov    [ecx], al
    inc    ecx
    test   al, al
    jnz    @B

    pop    eax

    ret

strcpyj endp

OPTION PROLOGUE:PrologueDef
OPTION EPILOGUE:EpilogueDef

; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««

end start
.
Download site for MASM32      New MASM Forum
https://masm32.com          https://masm32.com/board/index.php

Jibz

Average strcpy 396 MS
Average strcpyj 380 MS


Quite interesting :U.

It would be nice to see some results from P3 or below, since the P4 has shifted the rules of optimization a bit.

Mark Jones

Average strcpy 502 MS
Average strcpyj 498 MS
"To deny our impulses... foolish; to revel in them, chaos." MCJ 2003.08

MichaelW

P3-500:

Average strcpy 1663 MS
Average strcpyj 2079 MS

eschew obfuscation