Results 1 to 21 of 21

Thread: Speed Test - Loop vs CopyMemory

  1. #1

    Thread Starter
    PowerPoster
    Join Date
    Jul 2001
    Location
    Tucson, AZ
    Posts
    2,166

    Resolved Speed Test - Loop vs CopyMemory

    I was curious which was faster to move values up in a group of arrays,
    a loop or copymemory.

    For some reason program blowing up on last CopyMemory call.

    Any help/suggestions appreciated?

    Thanks
    David
    Attached Files Attached Files
    Last edited by dw85745; Jul 9th, 2005 at 03:29 PM.

  2. #2
    Banned dglienna's Avatar
    Join Date
    Jun 2004
    Location
    Center of it all
    Posts
    17,901

    Re: Speed Test - Loop vs CopyMemory

    You still have to loop to copy memory, don't you? Or are you going to read a large block at once to copy 4K of info? That may be the problem.

  3. #3
    Old Member moeur's Avatar
    Join Date
    Nov 2004
    Location
    Wait'n for Free Stuff
    Posts
    2,712

    Re: Speed Test - Loop vs CopyMemory

    Copymemory is much faster.
    It is more difficult to move the array up than down

    VB Code:
    1. 'move array up
    2.    '1st to temp array
    3.    CopyMemory temp(LBound(temp)), arr(LBound(arr)), (UBound(arr) - 1) * Len(arr(UBound(arr)))
    4.    'back to our array
    5.    CopyMemory arr(LBound(arr) + 1), temp(LBound(temp)), (UBound(arr) - 1) * Len(arr(UBound(arr)))
    6.    
    7.    'move array down
    8.    CopyMemory arr(LBound(arr)), arr(LBound(arr) + 1), (UBound(arr) - 1) * Len(arr(UBound(arr)))

  4. #4

    Thread Starter
    PowerPoster
    Join Date
    Jul 2001
    Location
    Tucson, AZ
    Posts
    2,166

    Re: Speed Test - Loop vs CopyMemory

    moeur

    Thanks for taking your time to respond and pointing out my error.

    I'm still not convinced CopyMemory is faster. From my testing so far,
    like most things it depends. If you have multiple arrays then the loop
    may be faster than multiple calls to CopyMemory.

    From the tests I've run so far, the Loop = CopyMemory till around 12000 elements (at least will 5 arrays), then CopyMemory wins.

    Attached is a revised example.

    David.
    Attached Files Attached Files

  5. #5
    I'm about to be a PowerPoster!
    Join Date
    Jan 2005
    Location
    Everywhere
    Posts
    13,647

    Re: Speed Test - Loop vs CopyMemory

    I'm not altogether sure what you're trying to achieve, but RtlMoveMemory a.k.a. CopyMemory is always faster than a loop.

    Also, there is no need for a temporary array. RtlMoveMemory can handle overlapped blocks of memory.

    VB Code:
    1. ' Move array elements up
    2. CopyMemory arr(LBound(arr)), arr(LBound(arr) + 1), (UBound(arr) - 1) * LenB(arr(UBound(arr)))

    Also, your test is non-existent. I had to loop it 1000 times for a result to show

    Code:
    Loop: 1.875 seconds
    CopyMemory: 0.047 seconds

  6. #6
    I'm about to be a PowerPoster!
    Join Date
    Jan 2005
    Location
    Everywhere
    Posts
    13,647

    Re: Speed Test - Loop vs CopyMemory

    I found your question interesting so I made a test project myself

    For me, no matter what the number of elements, MoveMemory always takes the same amount of time.

    Attached Files Attached Files

  7. #7
    Elite Hacker Jacob Roman's Avatar
    Join Date
    Aug 2004
    Location
    Miami Beach, FL
    Posts
    5,349

    Re: Speed Test - Loop vs CopyMemory

    CopyMemory will always be faster because it is a low level API call. Odds are, the function was made in Assembly in like a couple lines of code. And that will most certainly be way faster than VB, hands down.

  8. #8
    I'm about to be a PowerPoster!
    Join Date
    Jan 2005
    Location
    Everywhere
    Posts
    13,647

    Re: Speed Test - Loop vs CopyMemory

    Quite apart from that, it is one call no matter the number of elements to shift. The time is therefore always constant, whereas with a one-by-one element moving loop the time will scale linearly relative to the number of elements.

    An API call will always be disgustingly complex compared to straight assembly though. If VB had something like a MemMove statement then it would be much faster than using RtlMoveMemory.

  9. #9
    Elite Hacker Jacob Roman's Avatar
    Join Date
    Aug 2004
    Location
    Miami Beach, FL
    Posts
    5,349

    Re: Speed Test - Loop vs CopyMemory

    There is, well sort of. It's called =


    Only thing is that it can't copy entire array's instantly.

  10. #10

    Thread Starter
    PowerPoster
    Join Date
    Jul 2001
    Location
    Tucson, AZ
    Posts
    2,166

    Re: Speed Test - Loop vs CopyMemory

    Thanks for all the comments.

    The reason for the post was that I have multiple arrays whose
    elements need to be moved up/down to allow insertion.

    The question than became is it faster to loop once, moving all elements
    or make multiple calls to CopyMemory (here my assumption is the OS needs to either reallocate a block of memory and then copy OR reallocate one additional memory area and then move the pointers.) which at some point may take longer.

    --------------------------------------------------------------------
    I also have another interesting question -- maybe should be another post.

    Question: When using a timer less than a one second interval (1000),
    is it more efficient to pick a multiple of 60 (here Hertz). So 480 would be better than 500.

    David

  11. #11
    I'm about to be a PowerPoster!
    Join Date
    Jan 2005
    Location
    Everywhere
    Posts
    13,647

    Re: Speed Test - Loop vs CopyMemory

    Depends what sort of timer you use. If it is a VB timer control it won't be accurate to less than a second anyway. If it is an API timer it should be accurate to a bit less than a tenth (JR's the expert here).

  12. #12

    Thread Starter
    PowerPoster
    Join Date
    Jul 2001
    Location
    Tucson, AZ
    Posts
    2,166

    Re: Speed Test - Loop vs CopyMemory

    Thanks for response Penagate.

    Had forgot about the difference between the two.
    Using a supplied ActiveX to link to a server.

    Had previously tried using an API timer in their control but did wierd things. For some reason the VB timer worked as it should so went with it.

    Now going back over my code to try to speed things up a little. Saw yesterday I was running behind. Previously got info from the server about once every 10 seconds. Now getting info about once a second. So thought I would see if copying arrays would help as well as decreasing my buffer timer to 480 from 1000.

    David
    Last edited by dw85745; Jul 9th, 2005 at 01:58 PM.

  13. #13
    Elite Hacker Jacob Roman's Avatar
    Join Date
    Aug 2004
    Location
    Miami Beach, FL
    Posts
    5,349

    Re: Speed Test - Loop vs CopyMemory

    Actually I know a method that's 1 ms accurate.

  14. #14
    VB6, XHTML & CSS hobbyist Merri's Avatar
    Join Date
    Oct 2002
    Location
    Finland
    Posts
    6,654

    Re: Speed Test - Loop vs CopyMemory

    If you copy only a few bytes of data, then a loop is certainly faster. Calling API isn't all that fast, unfortunatenaly, so when you have only a few bytes to move, there is no point calling an API for that. If you need to move, say, over 100 bytes, then API is worthwhile (I haven't done a comparison test, so I don't know the critical point).

  15. #15

    Thread Starter
    PowerPoster
    Join Date
    Jul 2001
    Location
    Tucson, AZ
    Posts
    2,166

    Re: Speed Test - Loop vs CopyMemory

    As always thanks for input.

    Jacob Roman are you going to enlighten us regarding:

    Actually I know a method that's 1 ms accurate.
    David

  16. #16
    New Member
    Join Date
    Jun 2005
    Posts
    13

    Thumbs up Re: Speed Test - Loop vs CopyMemory

    Can we use the CopyMemory to copy a string array that is returned in Variant, please see my post here and any help will be appreciated:

    http://www.vbforums.com/showthread.php?t=348703

    Thanks

  17. #17
    Old Member moeur's Avatar
    Join Date
    Nov 2004
    Location
    Wait'n for Free Stuff
    Posts
    2,712

    Re: Speed Test - Loop vs CopyMemory

    The best method for timing is the Performance Counters
    This gives a resolution of about 300 nanoseconds if supported.
    Code below

    I used it to run speed tests on copymemory vs loop method
    copymemory is always faster than loop method even with only 25 elements in the array

    I was suprised to learn (thanks pengate) that copymemory will handle block copies in both directions. This means that the routine has to calculate whether the destination is going to be over written and if so copy it to a buffer.

    This suspicion is born out by the fact that the below shiftUp routine takes more than 3 times as long as the shift down routine. The loop methos takes 10 times as long as the ShiftUp routine.

    I posted this timing stuff in the codebank FAQ thread before they made us stop posting there

    VB Code:
    1. Option Explicit
    2.  
    3. Private Declare Sub CopyMemory Lib "Kernel32" Alias "RtlMoveMemory" (Destination As Any, Source As Any, ByVal Length As Long)
    4.  
    5.  
    6. Private Declare Function QueryPerformanceCounter Lib "Kernel32" _
    7.                                  (X As Currency) As Boolean
    8. Private Declare Function QueryPerformanceFrequency Lib "Kernel32" _
    9.                                  (X As Currency) As Boolean
    10.  
    11. Private Type TimerData
    12.     StartCount As Currency
    13.     StopCount As Currency
    14.     Overhead As Currency
    15.     Frequency As Currency
    16. End Type
    17.  
    18. Const ArrayMax = 2500
    19.  
    20. 'returns the number of seconds elapsed between StopCount and StartCount
    21. 'Assumes that InitPerformanceTimer has been called
    22. Private Function ElapsedTime(mydata As TimerData) As Single
    23.  With mydata
    24.     ElapsedTime = (.StopCount - .StartCount - .Overhead) / .Frequency 'seconds
    25.  End With
    26. End Function
    27.  
    28. 'Initializes the data structure so that the ElapsedTime function can be called
    29. 'Returns false if the High-resolution timer is not supported
    30. Private Function InitPerformanceTimer(mydata As TimerData) As Boolean
    31.     Dim Ctr1 As Currency, Ctr2 As Currency
    32.     With mydata
    33.       If QueryPerformanceCounter(Ctr1) Then
    34.           QueryPerformanceCounter Ctr2
    35.           QueryPerformanceFrequency .Frequency
    36.           '1/Freq*10000 is resolution of timer in seconds
    37.           Debug.Print "QueryPerformanceCounter minimum resolution: 1/" & _
    38.                       .Frequency * 10000; " seconds"
    39.           'This overhead is present for each call to API
    40.           .Overhead = Ctr2 - Ctr1
    41.           Debug.Print "API Overhead: "; .Overhead / .Frequency; "seconds"
    42.           InitPerformanceTimer = True
    43.         Else
    44.           Debug.Print "High-resolution counter not supported."
    45.           InitPerformanceTimer = False
    46.         End If
    47.     End With
    48. End Function
    49.  
    50. Sub LoopMethod(myArray() As Single)
    51. Dim i As Integer
    52. 'shift up
    53. For i = UBound(myArray) To LBound(myArray) + 1 Step -1
    54.     myArray(i) = myArray(i - 1)
    55. Next i
    56. End Sub
    57.  
    58.  
    59. Sub ShiftDown(myArray() As Single)
    60. 'shift array down one
    61. Dim Begin As Integer
    62. Begin = LBound(myArray)
    63. CopyMemory myArray(Begin), myArray(Begin + 1), (UBound(myArray) - Begin) * Len(myArray(Begin))
    64.  
    65. End Sub
    66.  
    67. Sub ShiftUp(myArray() As Single)
    68. 'shift array up one
    69. Dim Begin As Integer
    70. Begin = LBound(myArray)
    71. CopyMemory myArray(Begin + 1), myArray(Begin), (UBound(myArray) - Begin) * Len(myArray(Begin))
    72. End Sub
    73.  
    74. Private Sub Command1_Click()
    75. Dim i As Integer
    76.  
    77. Dim mydata As TimerData
    78. InitPerformanceTimer mydata
    79.  
    80. Dim sngArray(0 To ArrayMax) As Single
    81. For i = 0 To ArrayMax
    82.     sngArray(i) = i / 10
    83. Next i
    84. QueryPerformanceCounter mydata.StartCount
    85. For i = 1 To 100
    86.     ShiftUp sngArray
    87. Next i
    88. QueryPerformanceCounter mydata.StopCount
    89. Debug.Print "ShiftUp Elapsed time is " & CStr(ElapsedTime(mydata) * 1000) & " milliseconds."
    90.  
    91. QueryPerformanceCounter mydata.StartCount
    92. For i = 1 To 100
    93.     ShiftDown sngArray
    94. Next i
    95. QueryPerformanceCounter mydata.StopCount
    96. Debug.Print "ShiftDown Elapsed time is " & CStr(ElapsedTime(mydata) * 1000) & " milliseconds."
    97.  
    98. QueryPerformanceCounter mydata.StartCount
    99. For i = 1 To 100
    100.     LoopMethod sngArray
    101. Next i
    102. QueryPerformanceCounter mydata.StopCount
    103. Debug.Print "Loopmethod(Up) Elapsed time is " & CStr(ElapsedTime(mydata) * 1000) & " milliseconds."
    104. End Sub

  18. #18

    Thread Starter
    PowerPoster
    Join Date
    Jul 2001
    Location
    Tucson, AZ
    Posts
    2,166

    Re: Speed Test - Loop vs CopyMemory

    Thanks moeur for your input as well as everyone else.

    I hope we all learned something today -- I did!

  19. #19
    VB6, XHTML & CSS hobbyist Merri's Avatar
    Join Date
    Oct 2002
    Location
    Finland
    Posts
    6,654

    Re: Speed Test - Loop vs CopyMemory

    I have one request: place the comparison code for each test in their own command button. I've found out that for some reason the results seem to get distorted when you do multiple benchmarks within one procedure.


    I tested the critical point: with 15 elements VB6 is faster. With 16 elements using API is faster. Though, this is when we are both reading and writing to an array. I don't (yet) know the critical point for just reading the array (of which I personally need information of).


    Edit No wait a second here... *sigh* we were also testing the speed of UBound and LBound here! Retest...

    Edit #2 With just the required code and without anything needless, then with 12 elements VB6 is faster, with 13 elements API.
    Last edited by Merri; Jul 9th, 2005 at 05:02 PM.

  20. #20
    Old Member moeur's Avatar
    Join Date
    Nov 2004
    Location
    Wait'n for Free Stuff
    Posts
    2,712

    Re: Speed Test - Loop vs CopyMemory

    it seems you didn't compile the program using all advanced optimizations! This is critical! VB6 speeds up a huge amount when you compile your program
    You're right, I just ran it from the IDE

    Putting all methods into their own button and compiling for speed, I see that the loop method beats the copymemory when shifting up (only) with 20 elements.

    Loop method beats copymemory when shifting down with 9 elements in the array.

    with 2500 elements in the array the loop method is only now about 2 times slower than copymemory shift up, and 7.5 times slower than copymemory shift down.

  21. #21
    VB6, XHTML & CSS hobbyist Merri's Avatar
    Join Date
    Oct 2002
    Location
    Finland
    Posts
    6,654

    Re: Speed Test - Loop vs CopyMemory

    Ok, I've done some more testing (and correcting my thinking, I'm tired at this time of day being 1 AM already). I've found out, that VB6 keeps being faster when shifting items up. VB6 doesn't even lose badly when copying million items the other way. Here is my code:

    VB Code:
    1. Option Explicit
    2.  
    3. Private Declare Sub CopyMemory Lib "Kernel32" Alias "RtlMoveMemory" _
    4.     (Destination As Any, Source As Any, ByVal Length As Long)
    5.  
    6. Private Declare Function QueryPerformanceCounter Lib "Kernel32" (X As Currency) As Boolean
    7. Private Declare Function QueryPerformanceFrequency Lib "Kernel32" (X As Currency) As Boolean
    8.  
    9. Private Type TimerData
    10.     StartCount As Currency
    11.     StopCount As Currency
    12.     Overhead As Currency
    13.     Frequency As Currency
    14. End Type
    15.  
    16. Const ARRAYMAX As Long = 1000000
    17. Const ITERATIONS As Long = 10
    18. Dim MyData As TimerData
    19. Dim sngArray(0 To ARRAYMAX) As Long
    20. 'returns the number of seconds elapsed between StopCount and StartCount
    21. 'Assumes that InitPerformanceTimer has been called
    22. Private Function ElapsedTime(MyData As TimerData) As Single
    23.  With MyData
    24.     ElapsedTime = (.StopCount - .StartCount - .Overhead) / .Frequency 'seconds
    25.  End With
    26. End Function
    27. 'Initializes the data structure so that the ElapsedTime function can be called
    28. 'Returns false if the High-resolution timer is not supported
    29. Private Function InitPerformanceTimer(MyData As TimerData) As Boolean
    30.     Dim Ctr1 As Currency, Ctr2 As Currency
    31.     With MyData
    32.       If QueryPerformanceCounter(Ctr1) Then
    33.           QueryPerformanceCounter Ctr2
    34.           QueryPerformanceFrequency .Frequency
    35.           '1/Freq*10000 is resolution of timer in seconds
    36.           Debug.Print "QueryPerformanceCounter minimum resolution: 1/" & _
    37.                       .Frequency * 10000; " seconds"
    38.           'This overhead is present for each call to API
    39.           .Overhead = Ctr2 - Ctr1
    40.           Debug.Print "API Overhead: "; .Overhead / .Frequency; "seconds"
    41.           InitPerformanceTimer = True
    42.         Else
    43.           Debug.Print "High-resolution counter not supported."
    44.           InitPerformanceTimer = False
    45.         End If
    46.     End With
    47. End Function
    48. Private Sub Command1_Click()
    49.     Dim I As Long
    50.     Dim Begin As Long, DataLength As Long
    51.     For I = 0 To ARRAYMAX
    52.         sngArray(I) = I
    53.     Next I
    54.     Begin = LBound(sngArray)
    55.     DataLength = (UBound(sngArray) - Begin) * Len(sngArray(Begin))
    56.     QueryPerformanceCounter MyData.StartCount
    57.     For I = 1 To ITERATIONS
    58.         CopyMemory sngArray(Begin + 1), sngArray(Begin), DataLength
    59.     Next I
    60.     QueryPerformanceCounter MyData.StopCount
    61.     Label1.Caption = CStr(ElapsedTime(MyData) * 1000) & " milliseconds."
    62. End Sub
    63. Private Sub Command2_Click()
    64.     Dim I As Long
    65.     Dim Begin As Long, DataLength As Long
    66.     For I = 0 To ARRAYMAX
    67.         sngArray(I) = I
    68.     Next I
    69.     Begin = LBound(sngArray)
    70.     DataLength = (UBound(sngArray) - Begin) * Len(sngArray(Begin))
    71.     QueryPerformanceCounter MyData.StartCount
    72.     For I = 1 To ITERATIONS
    73.         CopyMemory sngArray(Begin), sngArray(Begin + 1), DataLength
    74.     Next I
    75.     QueryPerformanceCounter MyData.StopCount
    76.     Label2.Caption = CStr(ElapsedTime(MyData) * 1000) & " milliseconds."
    77. End Sub
    78. Private Sub Command3_Click()
    79.     Dim I As Long, J As Long
    80.     Dim Begin As Long, Ending As Long
    81.     For I = 0 To ARRAYMAX
    82.         sngArray(I) = I
    83.     Next I
    84.     Begin = LBound(sngArray) + 1
    85.     Ending = UBound(sngArray)
    86.     QueryPerformanceCounter MyData.StartCount
    87.     For I = 1 To ITERATIONS
    88.         For J = Begin To Ending
    89.             sngArray(J - 1) = sngArray(J)
    90.         Next J
    91.     Next I
    92.     QueryPerformanceCounter MyData.StopCount
    93.     Label3.Caption = CStr(ElapsedTime(MyData) * 1000) & " milliseconds."
    94. End Sub
    95. Private Sub Command4_Click()
    96.     Dim I As Long, J As Long
    97.     Dim Begin As Long, Ending As Long
    98.     For I = 0 To ARRAYMAX
    99.         sngArray(I) = I
    100.     Next I
    101.     Begin = LBound(sngArray) + 1
    102.     Ending = UBound(sngArray)
    103.     QueryPerformanceCounter MyData.StartCount
    104.     For I = 1 To ITERATIONS
    105.         For J = Ending To Begin Step -1
    106.             sngArray(J) = sngArray(J - 1)
    107.         Next J
    108.     Next I
    109.     QueryPerformanceCounter MyData.StopCount
    110.     Label4.Caption = CStr(ElapsedTime(MyData) * 1000) & " milliseconds."
    111. End Sub
    112. Private Sub Form_Load()
    113.     Dim I As Integer
    114.     InitPerformanceTimer MyData
    115. End Sub

    So I wouldn't call VB6 array handling very slow So my message here would be: "think about what you are testing!"
    Last edited by Merri; Jul 9th, 2005 at 05:23 PM.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  



Click Here to Expand Forum to Full Width