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.
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.
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.
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.
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).
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.
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).
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:
Option Explicit
Private Declare Sub CopyMemory Lib "Kernel32" Alias "RtlMoveMemory" (Destination As Any, Source As Any, ByVal Length As Long)
Private Declare Function QueryPerformanceCounter Lib "Kernel32" _
(X As Currency) As Boolean
Private Declare Function QueryPerformanceFrequency Lib "Kernel32" _
(X As Currency) As Boolean
Private Type TimerData
StartCount As Currency
StopCount As Currency
Overhead As Currency
Frequency As Currency
End Type
Const ArrayMax = 2500
'returns the number of seconds elapsed between StopCount and StartCount
'Assumes that InitPerformanceTimer has been called
Private Function ElapsedTime(mydata As TimerData) As Single
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.
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.
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:
Option Explicit
Private Declare Sub CopyMemory Lib "Kernel32" Alias "RtlMoveMemory" _
(Destination As Any, Source As Any, ByVal Length As Long)
Private Declare Function QueryPerformanceCounter Lib "Kernel32" (X As Currency) As Boolean
Private Declare Function QueryPerformanceFrequency Lib "Kernel32" (X As Currency) As Boolean
Private Type TimerData
StartCount As Currency
StopCount As Currency
Overhead As Currency
Frequency As Currency
End Type
Const ARRAYMAX As Long = 1000000
Const ITERATIONS As Long = 10
Dim MyData As TimerData
Dim sngArray(0 To ARRAYMAX) As Long
'returns the number of seconds elapsed between StopCount and StartCount
'Assumes that InitPerformanceTimer has been called
Private Function ElapsedTime(MyData As TimerData) As Single