Author Topic: A Different Approach  (Read 4365 times)

zedd151

  • Member
  • **
  • Posts: 241
A Different Approach
« on: September 16, 2015, 08:29:06 PM »
Following a suggestion from hutch (can't remember where I read it) I have devised for myself
a different timer testbed using GetTickCount, rather than using the timer/counter macros.

My cpu behaves unpredictably in regards to using RDTSC especially. If I fiddle with the
'LoopCount' - only sometimes can I achieve stable and repeatable results. Most other
times, there is doubling or quadrupling of the resulting cycle 'counts' - and often the
results are just erratic.

Therefore, I decided to do some experimenting using GetTickCount. Yes GTC also has its
faults, I am sure; but I decided to proceed in this manner:

Knowing that the resulting values from GTC (GetTickCount) may be very small, or sometimes
zero due to rounding, I use the 'REPEAT' macro to repeat the test algo 1000 times. The result
is therefore the tick count times 1000. Since the tick count refers to milliseconds, the result
from my tests are effectively in microseconds (averaged).

For comparing one algorithm to another, this is just perfect. No need to worry about the
peculiarities of RDTSC with this method. It is probably not perfect, but I believe that for
simple comparisons, this method should work pretty well.

Results will of course vary from one cpu to the next due to different cpu speeds, cpu
load, additional processes running, etc.

NOTE: This test is not intended to compare string length algorithms. It is intending to
demonstrate using GetTickCount for timing purposes.

Here are some results:

Code: [Select]
test using GetTickCount
 get length of windows.inc with lstrlen

1203  microseconds
1062  microseconds
1062  microseconds
1063  microseconds
1063  microseconds
1063  microseconds
1063  microseconds
1062  microseconds
1062  microseconds
1062  microseconds

 test using GetTickCount
 get length of windows.inc with StrLen

468  microseconds
468  microseconds
469  microseconds
469  microseconds
469  microseconds
469  microseconds
469  microseconds
469  microseconds
468  microseconds
468  microseconds


-- done! --

The GetTickCount testbed:

Code: [Select]

            include \masm32\include\masm32rt.inc

        .data
            TC1             dd 0
            ctrTop          dd 0
            windowsinclude  dd 0
            bRead           dd 0
            hFile           dd 0
            fSize           dd 0
            pWinInc         dd 0
                              ; you may need to change the path to windows.inc
            strwininc       db "C:\masm32\include\windows.inc", 0
        .code

        start:
       
            ; settings
           
            SleepMs    =    100  ; needed if results are displayed too fast, else not really necessary
           
            LOOP_COUNT =    1000 ; == milliseconds x 1000 == microseconds ; how many times the algo will repeat
           
            repeet     =    20   ; how many consecutive tests to run


            invoke CreateFile, addr strwininc, GENERIC_READ, 0, 0, OPEN_EXISTING, 0, 0
            mov hFile, eax
            invoke GetFileSize, hFile, 0
            mov fSize, eax
            invoke GlobalAlloc, GPTR, fSize
            mov pWinInc, eax
            invoke ReadFile, hFile, pWinInc, fSize, addr bRead, 0
            invoke CloseHandle, hFile
           
; test 1           
; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
            print " test using GetTickCount", 13, 10
            print " get length of windows.inc with lstrlen", 13, 10, 13, 10
           
    mov ctrTop, 10       
     top:   
        invoke SleepEx, SleepMs, 0
       
        invoke GetCurrentProcess
        invoke SetPriorityClass, eax, HIGH_PRIORITY_CLASS
       
        invoke GetTickCount
        mov TC1, eax
       
        ; ##############################################    current test
       
        repeat LOOP_COUNT
        invoke lstrlen, pWinInc
        endm
       
        ; ##############################################
       
        invoke GetTickCount
        sub eax, TC1
       
        print str$(eax), 20h, " microseconds", 13, 10   ;   print result of current test
       
        invoke GetCurrentProcess
        invoke SetPriorityClass, eax, NORMAL_PRIORITY_CLASS
       
    dec ctrTop
    cmp ctrTop, 0
    jnz top           
            print chr$(13, 10)

; test 2
; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
            print " test using GetTickCount", 13, 10
            print " get length of windows.inc with StrLen", 13, 10, 13, 10
           
mov ctrTop, 10       
 top2:   
        invoke SleepEx, SleepMs, 0
       
        invoke GetCurrentProcess
        invoke SetPriorityClass, eax, HIGH_PRIORITY_CLASS
       
        invoke GetTickCount
        mov TC1, eax
       
        ; ##############################################    current test
       
        repeat LOOP_COUNT
        invoke StrLen, pWinInc
        endm
       
        ; ##############################################
       
        invoke GetTickCount
        sub eax, TC1
       
        print str$(eax), 20h, " microseconds", 13, 10   ;   print result of current test
       
        invoke GetCurrentProcess
        invoke SetPriorityClass, eax, NORMAL_PRIORITY_CLASS
       
dec ctrTop
cmp ctrTop, 0
jnz top2           
            print chr$(13, 10)
           
; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
            invoke GlobalFree, pWinInc
            inkey chr$(13, 10, "-- done! --", 13)
            exit

    end start

edit = typo
edit #2 = remove unused variable from source
« Last Edit: September 16, 2015, 09:40:00 PM by zedd151 »
Links broken - to be remedied soon
----------------------------------------------
hutch: "MASM does not have bugs, it just has features you need to understand." 8)

jj2007

  • Member
  • *****
  • Posts: 7737
  • Assembler is fun ;-)
    • MasmBasic
Re: A Different Approach
« Reply #1 on: September 16, 2015, 09:04:30 PM »
Intel i5:
Code: [Select]
test using GetTickCount
 get length of windows.inc with lstrlen

484  microseconds
484  microseconds
515  microseconds
499  microseconds
515  microseconds
483  microseconds
500  microseconds
515  microseconds
499  microseconds
515  microseconds

 test using GetTickCount
 get length of windows.inc with StrLen

234  microseconds
234  microseconds
218  microseconds
219  microseconds
219  microseconds
219  microseconds
203  microseconds
218  microseconds
203  microseconds
187  microseconds

TWell

  • Member
  • ****
  • Posts: 748
Re: A Different Approach
« Reply #2 on: September 16, 2015, 10:55:48 PM »
Is there examples of QueryPerformanceCounter ?

zedd151

  • Member
  • **
  • Posts: 241
Re: A Different Approach
« Reply #3 on: September 16, 2015, 11:01:49 PM »
Is there examples of QueryPerformanceCounter ?

Sure is. MichaelW's timing macro is based upon it (along with QueryPerformanceFrequency)
See the first posting in this forum.

fyi, the timing macro is in \masm32\macros\timers.asm

This thread is experimenting with GetTickCount.
Links broken - to be remedied soon
----------------------------------------------
hutch: "MASM does not have bugs, it just has features you need to understand." 8)

zedd151

  • Member
  • **
  • Posts: 241
Macro!!
« Reply #4 on: September 17, 2015, 01:26:35 AM »
I wasn't sure it would work as a macro, so I tried anyway. I made it super easy to use.
The algo under test must be placed in a <lable>; ret construct much like an old style procedure.
xxxxxxxxxxxxxxxxxxxxxxxxx

SuperAlgoUnderTest:

some code here

ret

xxxxxxxxxxxxxxxxxxxxxxxxx

Of course it slighlty adds to the overhead, but the macro was designed for more simplicity.
Plus if comparing two similar algorithms, the overhead will be present in each of them,
thereby validating the results. The idea is NOT to get the exact time it takes for an algorithm
to run, but to compare RELATIVE speed of one algorithm to the next.


Code: [Select]
        include \masm32\include\masm32rt.inc
       
    comment * ##################################################################
   
            TickTimer - Timing Macro using GetTickCount
            pAlgo is the offset to the procedure where the algorithm is located
            In this version the algorithm must be constructed as a procedure.
            A simple label and return will suffice, as shown below.
       
    ########################################################################## *

    ; ##########################################################################
    ; ##########################################################################
   
        TickTimer MACRO pAlgo
        local top
            pushad
            mov ctrTop, repeet       
         top:   
            invoke SleepEx, SleepMs, 0
            invoke GetCurrentProcess
            invoke SetPriorityClass, eax, HIGH_PRIORITY_CLASS
            invoke GetTickCount
            mov TC1, eax
       
    ; ##############################################    current test
   
            repeat LOOP_COUNT
            call pAlgo
            endm
       
    ; ##############################################
   
            invoke GetTickCount
            sub eax, TC1
            print str$(eax), 20h, " microseconds", 13, 10   ;   print result of current test
            invoke GetCurrentProcess
            invoke SetPriorityClass, eax, NORMAL_PRIORITY_CLASS
            dec ctrTop
            cmp ctrTop, 0
        jnz top           
            print chr$(13, 10)
            popad
        ENDM       

    ; ##########################################################################
    ; ##########################################################################

        .data
            TC1             dd 0
            ctrTop          dd 0
            windowsinclude  dd 0
            bRead           dd 0
            hFile           dd 0
            fSize           dd 0
            pWinInc         dd 0
                              ; you may need to change the path to windows.inc
            strwininc       db "C:\masm32\include\windows.inc", 0
        .code

    ; ##########################################################################

            testlstrlen:
                invoke lstrlen, pWinInc
            ret
       
    ; ##########################################################################

            testStrLen:
                invoke StrLen, pWinInc
            ret

    ; ##########################################################################

            testRegLen:
                push esi
                mov esi, pWinInc
                xor eax, eax
                dec eax
            @@:
                inc eax
                cmp byte ptr [esi+eax], 0
            jz @f
            jmp @b
            @@:
                pop esi
            ret

    ; ##########################################################################

        start:
           
            ; settings
           
            SleepMs    =    100  ; needed if results are displayed too fast, else not really necessary
           
            LOOP_COUNT =    1000 ; == milliseconds x 1000 == microseconds ; how many times the algo will repeat
           
            repeet     =    20   ; how many consecutive tests to run
   
            invoke CreateFile, addr strwininc, GENERIC_READ, 0, 0, OPEN_EXISTING, 0, 0
            mov hFile, eax
            invoke GetFileSize, hFile, 0
            mov fSize, eax
            invoke GlobalAlloc, GPTR, fSize
            mov pWinInc, eax
            invoke ReadFile, hFile, pWinInc, fSize, addr bRead, 0
            invoke CloseHandle, hFile
           
    ; test 1           
    ; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
       
            print " get length of windows.inc with lstrlen", 13, 10, 13, 10
           
            TickTimer offset testlstrlen
   
    ; test 2
    ; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
   
            print " get length of windows.inc with StrLen", 13, 10, 13, 10
           
            TickTimer offset testStrLen
   
    ; test 3
    ; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
   
            print " get length of windows.inc using registers", 13, 10, 13, 10
           
            TickTimer offset testRegLen
   
    ; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
            invoke GlobalFree, pWinInc
            inkey chr$(13, 10, "-- done! --", 13)
            exit
   
        end start

Here are the results:
They are way similar to the results of the first tests with the timer as a procedure

Code: [Select]
get length of windows.inc with lstrlen

1171  microseconds
1062  microseconds
1062  microseconds
1062  microseconds
1063  microseconds
1063  microseconds
1063  microseconds
1063  microseconds
1062  microseconds
1062  microseconds

 get length of windows.inc with StrLen

468  microseconds
469  microseconds
469  microseconds
469  microseconds
469  microseconds
469  microseconds
469  microseconds
468  microseconds
468  microseconds
469  microseconds

 get length of windows.inc using registers

1593  microseconds
1593  microseconds
1594  microseconds
1594  microseconds
1594  microseconds
1594  microseconds
1594  microseconds
1594  microseconds
1593  microseconds
1593  microseconds


-- done! --
« Last Edit: September 17, 2015, 03:42:56 AM by zedd151 »
Links broken - to be remedied soon
----------------------------------------------
hutch: "MASM does not have bugs, it just has features you need to understand." 8)

zedd151

  • Member
  • **
  • Posts: 241
Re: A Different Approach
« Reply #5 on: September 17, 2015, 04:52:54 AM »
As with my other timer/counter experiments, I found a flaw with using GetTickCount. :(

It seems that the result (even after 1000 reps) has an affinity towards 'snapping' towards the nearest 1, 15 or 16.
I though this is odd. So I ran many tests on different length files using the same procedures as in both of the
examples above.

The most common differences within the same test are 0, 1, 15 and 16.

I have never seen a difference of 2,3,4,5,6,7,8,9,10,11,12,13,14,17.....
Strange behaviour now with GetTickCount.

Starting with a smaller filesize, the count remains zero. Even as I keep increasing the size, it remains zero.
Then every so often a 15 would slip into the mix. So I continue increasing the size. 0,0,15, 0, 0, 16, 0.....

Then all of a sudden... 16, 16, 16, 16, 16, 16, 16 ~~ 16, 16. (It seems to have 'snapped' to 16) :dazzled:
If you guess that the next will be 32, you're close...

Continuing my little experiment still increasing the size-----

We start getting 16, 31, 16, 16, 31, 16, ....

Then 32, 32, 32, 31, 32, 32, 32...

Weird behaviour indeed. Now I would expect that IF we were only making one test at
a time, with no looping - - but we are running each test 1000 times each. So, I cannot
understand why this would happen with GetTickCount - at least not doing it the way
I have done with the examples above.

Through all of the trial runs I have made, I left all of the settings as in the example pieces above.
The only difference is the length of the file under test. Not always an even length, btw.

Now I am totally perplexed.
Links broken - to be remedied soon
----------------------------------------------
hutch: "MASM does not have bugs, it just has features you need to understand." 8)

jj2007

  • Member
  • *****
  • Posts: 7737
  • Assembler is fun ;-)
    • MasmBasic
Re: A Different Approach
« Reply #6 on: September 17, 2015, 05:26:03 AM »
It's called granularity. GetTickCount makes sense only for timings above one second or so. If you need a finer granularity: NanoTimer() uses QPC with a 0.3 microseconds resolution. Under the hood it's a little bit more complicated than GTC, though.

You may search the old forum for GetTickCount granularity.

zedd151

  • Member
  • **
  • Posts: 241
Re: A Different Approach
« Reply #7 on: September 17, 2015, 05:49:28 AM »
.... GetTickCount makes sense only for timings above one second or so....

I understand, but I would think that repeating the 'algo' 1000 times as I do in the examples, would help
to offset such occurences.

Quote
If you need a finer granularity: NanoTimer().....

Unless it is coded in a way I can read it, sorry I am not interested.
MasmBasic, RichMasm, and all of their accessories don't appeal to me.
So I wish you'd stop sending that stuff to me - lol
But I will take a better look at QueryPerformanceFrequency//QueryPerformanceCounter.

I think rrr314(whatever - I can't remeber his full screen name) had a nice example of QPF/QPC......
Links broken - to be remedied soon
----------------------------------------------
hutch: "MASM does not have bugs, it just has features you need to understand." 8)

hutch--

  • Administrator
  • Member
  • ******
  • Posts: 4924
  • Mnemonic Driven API Grinder
    • The MASM32 SDK
Re: A Different Approach
« Reply #8 on: September 17, 2015, 06:32:02 AM »
Z,

Here is a simple test piece on GetTickCount benchmarking. It uses 3 algos, a simple byte scanner, an unrolled byte scanner and the library version of Strlen that is unrolled by 4. Characteristically the 2 byte scanners increase in duration in a linear manner based on the data length where the unrolled DWORD version StrLen is a lot fast as the string length gets longer. GetTickCount is a reasonably crude low resolution technique but its real advantage is it tests in real time, not simply counting processor cycles. The trick is to make the data sample last long enough to avoid most of the problems of its low resolution. A half second is usually enough, a bit longer improves the accuracy some but running for more than a few seconds does not improve it much at all.


; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
    include \masm32\include\masm32rt.inc
; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤

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

    sslen  PROTO :DWORD
    sslen2 PROTO :DWORD

    .code

start:
   
; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤

    call main
    inkey
    exit

; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤

main proc

    push esi

    fn GetTickCount
    push eax

    .data
      tsttxt db "1234567890123456789012345678901234567890",0
    .code

    mov esi, 100000000

  lbl:
    ; mov edx, rv(sslen,OFFSET tsttxt)

    ; mov edx, rv(sslen2,OFFSET tsttxt)

    mov edx, rv(StrLen,OFFSET tsttxt)

    sub esi, 1
    jnz lbl

    fn GetTickCount
    pop ecx
    sub eax, ecx

    print str$(eax),13,10

    pop esi

    ret

main endp

; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤

OPTION PROLOGUE:NONE
OPTION EPILOGUE:NONE

sslen proc pstr:DWORD

    mov eax, [esp+4]
    sub eax, 1

  lp:
    add eax, 1
    cmp BYTE PTR [eax], 0
    jne lp

    sub eax, [esp+4]

    ret 4

sslen endp

OPTION PROLOGUE:PrologueDef
OPTION EPILOGUE:EpilogueDef

; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤

OPTION PROLOGUE:NONE
OPTION EPILOGUE:NONE

sslen2 proc pstr:DWORD

    mov eax, [esp+4]
    sub eax, 1

  lp:
  REPEAT 4
    add eax, 1
    cmp BYTE PTR [eax], 0
    je lo
  ENDM

    add eax, 1
    cmp BYTE PTR [eax], 0
    jne lp
  lo:

    sub eax, [esp+4]

    ret 4

sslen2 endp

OPTION PROLOGUE:PrologueDef
OPTION EPILOGUE:EpilogueDef

; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤

end start
hutch at movsd dot com
http://www.masm32.com    :biggrin:  :biggrin:

jj2007

  • Member
  • *****
  • Posts: 7737
  • Assembler is fun ;-)
    • MasmBasic
Re: A Different Approach
« Reply #9 on: September 17, 2015, 06:43:04 AM »
So I wish you'd stop sending that stuff to me - lol. But I will take a better look at QueryPerformanceFrequency//QueryPerformanceCounter.

No problem, I will ignore your posts from now on. For complete code using QPC, see \Masm32\MasmBasic\MasmBasic.inc, lines 7588ff.

zedd151

  • Member
  • **
  • Posts: 241
Re: A Different Approach
« Reply #10 on: September 17, 2015, 06:59:49 AM »
Z,

Here is a simple test piece on GetTickCount benchmarking...

Thanks hutch. I'm pretty sure I have seen this here somewhere before, or something similar.
I'll take a look at it, run strings of various lengths, etc.

But I can't see the outcome being much better than the results from my examples here.
Yours loops through 10,000,000 reps - so maybe it will be better. :t

@jj don't be angry with me, I did whisper the request with small type, I didn't shout it with large, bold, UPPERCASE.
I respect you and your coding knowledge, however am not interested in MB. Thank you.  8)
Links broken - to be remedied soon
----------------------------------------------
hutch: "MASM does not have bugs, it just has features you need to understand." 8)

zedd151

  • Member
  • **
  • Posts: 241
Re: A Different Approach
« Reply #11 on: September 17, 2015, 07:51:27 AM »
Results using hutch's testbed:

Code: [Select]
5750 sslen
5484 sslen2
3110 StrLen

5594 sslen
5484 sslen2
3125 StrLen

5641 sslen
5468 sslen2
3110 StrLen

5578 sslen
5484 sslen2
3141 StrLen

5687 sslen
5500 sslen2
3110 StrLen


Looks like it will work fine for shorter strings, or smaller algos.

The modified version (to run 3 tests - repeated 5 times)

Code: [Select]


; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
    include \masm32\include\masm32rt.inc
; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤

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

    sslen  PROTO :DWORD
    sslen2 PROTO :DWORD

    .code

start:
   
; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤

    call main
    inkey
    exit

; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤

main proc
    .data
      tsttxt db "1234567890123456789012345678901234567890",0
      repctr dd 0
    .code

    push esi
    mov repctr, 5 ; show 5 tests

top:

; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
;   test 1
; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤

    fn GetTickCount
    push eax
    mov esi, 100000000
  align 4
  lbl1:
    mov edx, rv(sslen,OFFSET tsttxt)
    sub esi, 1
    jnz lbl1
    fn GetTickCount
    pop ecx
    sub eax, ecx
    print str$(eax)," sslen",13,10

; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
;   test 2
; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤

    fn GetTickCount
    push eax
    mov esi, 100000000
  align 4
  lbl2:
   
    mov edx, rv(sslen2,OFFSET tsttxt)
    sub esi, 1
    jnz lbl2
    fn GetTickCount
    pop ecx
    sub eax, ecx
    print str$(eax)," sslen2", 13,10
   
; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
;   test 3
; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤

    fn GetTickCount
    push eax
    mov esi, 100000000
  align 4
  lbl3:
   
    mov edx, rv(StrLen,OFFSET tsttxt)
   
    sub esi, 1
    jnz lbl3
    fn GetTickCount
    pop ecx
    sub eax, ecx
    print str$(eax)," StrLen", 13,10, 13,10

; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
; end tests
; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤

    sub repctr, 1
jnz top
   
    pop esi

    ret

main endp

; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤

OPTION PROLOGUE:NONE
OPTION EPILOGUE:NONE

sslen proc pstr:DWORD

    mov eax, [esp+4]
    sub eax, 1

  lp:
    add eax, 1
    cmp BYTE PTR [eax], 0
    jne lp

    sub eax, [esp+4]

    ret 4

sslen endp

OPTION PROLOGUE:PrologueDef
OPTION EPILOGUE:EpilogueDef

; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤

OPTION PROLOGUE:NONE
OPTION EPILOGUE:NONE

sslen2 proc pstr:DWORD

    mov eax, [esp+4]
    sub eax, 1

  lp:
  REPEAT 4
    add eax, 1
    cmp BYTE PTR [eax], 0
    je lo
  ENDM

    add eax, 1
    cmp BYTE PTR [eax], 0
    jne lp
  lo:

    sub eax, [esp+4]

    ret 4

sslen2 endp

OPTION PROLOGUE:PrologueDef
OPTION EPILOGUE:EpilogueDef

; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤

end start

Now all that is left is to make a macro out of it  :eusa_dance:

And then a PlugIn  :biggrin:
Links broken - to be remedied soon
----------------------------------------------
hutch: "MASM does not have bugs, it just has features you need to understand." 8)

zedd151

  • Member
  • **
  • Posts: 241
Macro 2
« Reply #12 on: September 17, 2015, 08:49:02 AM »
macro using hutch's test bench:

Code: [Select]

; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
    include \masm32\include\masm32rt.inc
; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤

    comment * -----------------------------------------------------
                            Build this  template with
                           "CONSOLE ASSEMBLE AND LINK"
            ----------------------------------------------------- *
   
        sslen  PROTO :DWORD
        sslen2 PROTO :DWORD
       
; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
; macro utilizing GetTickCount
; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤

    hutchtb MACRO pAlgo, pText
        local lbl1
       
        push esi
   
        mov esi, 100000000
       
        fn GetTickCount
        push eax
   
    align 4
    lbl1:
     
        push pText
        call pAlgo
       
        sub esi, 1
       
    jnz lbl1
   
        fn GetTickCount
       
        pop ecx
        sub eax, ecx
       
        print str$(eax),13,10
       
        pop esi
   
    ENDM

; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
; end macro
; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
   
        .code
   
    start:
       
; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤

        call main
        inkey
        exit

; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤

    main proc
   
        .data
          tsttxt db "1234567890123456789012345678901234567890",0
          repctr dd 0
        .code

; test 1
; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
;            invoke SleepEx, 100, 0  ; didn't work good here, increased return by 3000 :shock:
; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤ ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤

        print "sslen", 13,10
      repeat 5
   
        hutchtb offset sslen, offset tsttxt
   
      endm
        print " ", 13,10, 13,10

; test 2
; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
            invoke SleepEx, 100, 0
; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤

        print "sslen2", 13,10
      repeat 5
   
        hutchtb offset sslen2, offset tsttxt
   
      endm
        print " ", 13,10, 13,10

; test 3
; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
            invoke SleepEx, 100, 0
; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤

        print "StrLen", 13,10
      repeat 5
   
        hutchtb offset StrLen, offset tsttxt
   
      endm
        print " ", 13,10, 13,10

; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤

        ret
   
    main endp

; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤

OPTION PROLOGUE:NONE
OPTION EPILOGUE:NONE

sslen proc pstr:DWORD

    mov eax, [esp+4]
    sub eax, 1

  lp:
    add eax, 1
    cmp BYTE PTR [eax], 0
    jne lp

    sub eax, [esp+4]

    ret 4

sslen endp

OPTION PROLOGUE:PrologueDef
OPTION EPILOGUE:EpilogueDef

; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤

OPTION PROLOGUE:NONE
OPTION EPILOGUE:NONE

sslen2 proc pstr:DWORD

    mov eax, [esp+4]
    sub eax, 1

  lp:
  REPEAT 4
    add eax, 1
    cmp BYTE PTR [eax], 0
    je lo
  ENDM

    add eax, 1
    cmp BYTE PTR [eax], 0
    jne lp
  lo:

    sub eax, [esp+4]

    ret 4

sslen2 endp

OPTION PROLOGUE:PrologueDef
OPTION EPILOGUE:EpilogueDef

; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤

end start

Results after adding sleeepies:

Code: [Select]
sslen
5687
5594
5531
5610
5609


sslen2
5454
5468
5469
5484
5469


StrLen
3078
3093
3094
3094
3031

edit = add ZZZzzzz

darned paste wiped out the original
Links broken - to be remedied soon
----------------------------------------------
hutch: "MASM does not have bugs, it just has features you need to understand." 8)

hutch--

  • Administrator
  • Member
  • ******
  • Posts: 4924
  • Mnemonic Driven API Grinder
    • The MASM32 SDK
Re: A Different Approach
« Reply #13 on: September 17, 2015, 08:52:43 AM »
Z,

When you are doing multiple timings, it helps to stabilise the results by putting a delay of about 100 ms between tests.

Code: [Select]
invoke SleepEx,100,0
hutch at movsd dot com
http://www.masm32.com    :biggrin:  :biggrin:

zedd151

  • Member
  • **
  • Posts: 241
Re: A Different Approach
« Reply #14 on: September 17, 2015, 08:57:22 AM »

...When you are doing multiple timings....

Code: [Select]
invoke SleepEx,100,0

Doh!!! :shock:
I knew I was missing something

from the previous macro:
Quote
        invoke SleepEx, SleepMs, 0

edit = formatting
Links broken - to be remedied soon
----------------------------------------------
hutch: "MASM does not have bugs, it just has features you need to understand." 8)