SafeArrayCopy SLOWER than iterating string array!


DevX Home    Today's Headlines   Articles Archive   Tip Bank   Forums   

Results 1 to 11 of 11

Thread: SafeArrayCopy SLOWER than iterating string array!

Hybrid View

  1. #1
    Mark Alexander Bertenshaw Guest

    SafeArrayCopy SLOWER than iterating string array!

    Good day!

    Being one of those people who is obsessed with maximising the performance of
    repetitive operations, I was looking for alternative ways to copy one string
    array to another in VB5. I have previously been writing a functions to
    convert a Variant containing a String Array to a String Array, and had used
    the SafeArrayCopy function. This then got me thinking that maybe this
    function would be a quicker way to copy large string arrays, as happens a
    lot in our code. After much messing about, I came up with the following
    code, which requires a type library for the VarPtrStringArray() function
    (see MSDN Knowledge Base Q199824 - HOWTO: Get the Address of Variables in
    Visual Basic) :

    -------

    Option Explicit

    Private Declare Function SafeArrayCopy Lib "oleaut32.dll" ( _
    ByVal psa As Long, _
    ByVal ppsaOut As Long) As Long

    Private Type VARIANT_PTR
    vt As Integer
    reserved1 As Integer
    reserved2 As Integer
    reserved3 As Integer
    ptr As Long
    filler(1 To 4) As Byte
    End Type

    Public Sub GVariantToStringArray(ByRef v As Variant, _
    ByRef s() As String)
    ' Purpose: Retrieves a string array from a variant.
    ' Inputs: v
    ' Outputs: s()
    ' In/Outs: <None>
    ' Created: 12/06/2000: MAB
    Dim udtVariant As VARIANT_PTR

    ' Take a copy of the variant to the variant structure.
    win.CopyMemory udtVariant, v, 16
    ' Only allow variant string arrays.
    If udtVariant.vt = (vbString Or vbArray) Then
    ' Ensure that any strings in existance are released.
    Erase s()
    ' Copy the array in the variant over to s().
    SafeArrayCopy udtVariant.ptr, VarPtrStringArray(s())
    Else
    ' Raise a Type Mismatch error.
    Err.Raise win.VBErrorConst.eeTypeMismatch
    End If

    End Sub

    Public Sub GCopyStringArray(ByRef asSource() As String, _
    ByRef asDestination() As String)
    ' Purpose: Copies the string array, asSource, to asDestination.
    ' Inputs: asSource
    ' Outputs: asDestination
    ' In/Outs: <None>
    ' Created: 12/06/2000: MAB
    Dim ptr As Long

    ' Destroy asDestination.
    Erase asDestination

    ' Get a pointer to the pointer to asSource.
    win.CopyMemory ptr, ByVal VarPtrStringArray(asSource), 4
    ' Copy data from asSource to asDestination.
    SafeArrayCopy ptr, VarPtrStringArray(asDestination)

    End Sub

    -------

    Well, the GCopyStringArray routine works, but in tests, it is approximately
    5.5 times slower than simply Redim'ing a new string array, and then copying
    strings between the old and new arrays. Most perplexing. Can anybody
    explain this big difference in speed?

    Thanks,

    ---------------------------------------
    Mark Alexander Bertenshaw
    Programmer/Analyst
    Prime Response
    Brentford
    UK



  2. #2
    Michael \(michka\) Kaplan Guest

    Re: SafeArrayCopy SLOWER than iterating string array!

    Not sure what you need to have explained here.... you assume because it uses
    APIs it must be faster?

    What is, speaks for itself. Such as the numbers you have been given.

    --
    MichKa
    "Cause it's a bittersweet symphony, thats life..." -- The Verve

    random junk of dubious value, at the multilingual,
    no scripts required, http://www.trigeminal.com/

    "Mark Alexander Bertenshaw" <Mark.Bertenshaw@virgin.net> wrote in message
    news:39457bdf@news.devx.com...
    > Good day!
    >
    > Being one of those people who is obsessed with maximising the performance

    of
    > repetitive operations, I was looking for alternative ways to copy one

    string
    > array to another in VB5. I have previously been writing a functions to
    > convert a Variant containing a String Array to a String Array, and had

    used
    > the SafeArrayCopy function. This then got me thinking that maybe this
    > function would be a quicker way to copy large string arrays, as happens a
    > lot in our code. After much messing about, I came up with the following
    > code, which requires a type library for the VarPtrStringArray() function
    > (see MSDN Knowledge Base Q199824 - HOWTO: Get the Address of Variables in
    > Visual Basic) :
    >
    > -------
    >
    > Option Explicit
    >
    > Private Declare Function SafeArrayCopy Lib "oleaut32.dll" ( _
    > ByVal psa As Long, _
    > ByVal ppsaOut As Long) As Long
    >
    > Private Type VARIANT_PTR
    > vt As Integer
    > reserved1 As Integer
    > reserved2 As Integer
    > reserved3 As Integer
    > ptr As Long
    > filler(1 To 4) As Byte
    > End Type
    >
    > Public Sub GVariantToStringArray(ByRef v As Variant, _
    > ByRef s() As String)
    > ' Purpose: Retrieves a string array from a variant.
    > ' Inputs: v
    > ' Outputs: s()
    > ' In/Outs: <None>
    > ' Created: 12/06/2000: MAB
    > Dim udtVariant As VARIANT_PTR
    >
    > ' Take a copy of the variant to the variant structure.
    > win.CopyMemory udtVariant, v, 16
    > ' Only allow variant string arrays.
    > If udtVariant.vt = (vbString Or vbArray) Then
    > ' Ensure that any strings in existance are released.
    > Erase s()
    > ' Copy the array in the variant over to s().
    > SafeArrayCopy udtVariant.ptr, VarPtrStringArray(s())
    > Else
    > ' Raise a Type Mismatch error.
    > Err.Raise win.VBErrorConst.eeTypeMismatch
    > End If
    >
    > End Sub
    >
    > Public Sub GCopyStringArray(ByRef asSource() As String, _
    > ByRef asDestination() As String)
    > ' Purpose: Copies the string array, asSource, to asDestination.
    > ' Inputs: asSource
    > ' Outputs: asDestination
    > ' In/Outs: <None>
    > ' Created: 12/06/2000: MAB
    > Dim ptr As Long
    >
    > ' Destroy asDestination.
    > Erase asDestination
    >
    > ' Get a pointer to the pointer to asSource.
    > win.CopyMemory ptr, ByVal VarPtrStringArray(asSource), 4
    > ' Copy data from asSource to asDestination.
    > SafeArrayCopy ptr, VarPtrStringArray(asDestination)
    >
    > End Sub
    >
    > -------
    >
    > Well, the GCopyStringArray routine works, but in tests, it is

    approximately
    > 5.5 times slower than simply Redim'ing a new string array, and then

    copying
    > strings between the old and new arrays. Most perplexing. Can anybody
    > explain this big difference in speed?
    >
    > Thanks,
    >
    > ---------------------------------------
    > Mark Alexander Bertenshaw
    > Programmer/Analyst
    > Prime Response
    > Brentford
    > UK
    >
    >




  3. #3
    Mark Alexander Bertenshaw Guest

    Re: SafeArrayCopy SLOWER than iterating string array!


    Michael -

    I fully understand that APIs can be slower than VB code, which is why I bothered
    to do the test. However, as a general rule, the hackers who wrote API code
    probably have more experience with them than me, and probably know the "guts"
    of the routines, and as a result are more likely to have a faster way to
    use their more primitive routines than me.

    I was just somewhat surprised that my code was 5.5 times faster than theirs.
    I would have expected at least something comparable with mine. I am wondering
    whether there is something in my code that is bound to slow the API routine
    down.

    "Michael \(michka\) Kaplan" <former_mvp@spamfree.trigeminal.nospam.com> wrote:
    >Not sure what you need to have explained here.... you assume because it

    uses
    >APIs it must be faster?
    >
    >What is, speaks for itself. Such as the numbers you have been given.
    >
    >--
    >MichKa
    >"Cause it's a bittersweet symphony, thats life..." -- The Verve
    >
    >random junk of dubious value, at the multilingual,
    >no scripts required, http://www.trigeminal.com/
    >
    >"Mark Alexander Bertenshaw" <Mark.Bertenshaw@virgin.net> wrote in message
    >news:39457bdf@news.devx.com...
    >> Good day!
    >>
    >> Being one of those people who is obsessed with maximising the performance

    >of
    >> repetitive operations, I was looking for alternative ways to copy one

    >string
    >> array to another in VB5. I have previously been writing a functions to
    >> convert a Variant containing a String Array to a String Array, and had

    >used
    >> the SafeArrayCopy function. This then got me thinking that maybe this
    >> function would be a quicker way to copy large string arrays, as happens

    a
    >> lot in our code. After much messing about, I came up with the following
    >> code, which requires a type library for the VarPtrStringArray() function
    >> (see MSDN Knowledge Base Q199824 - HOWTO: Get the Address of Variables

    in
    >> Visual Basic) :
    >>
    >> -------
    >>
    >> Option Explicit
    >>
    >> Private Declare Function SafeArrayCopy Lib "oleaut32.dll" ( _
    >> ByVal psa As Long, _
    >> ByVal ppsaOut As Long) As Long
    >>
    >> Private Type VARIANT_PTR
    >> vt As Integer
    >> reserved1 As Integer
    >> reserved2 As Integer
    >> reserved3 As Integer
    >> ptr As Long
    >> filler(1 To 4) As Byte
    >> End Type
    >>
    >> Public Sub GVariantToStringArray(ByRef v As Variant, _
    >> ByRef s() As String)
    >> ' Purpose: Retrieves a string array from a variant.
    >> ' Inputs: v
    >> ' Outputs: s()
    >> ' In/Outs: <None>
    >> ' Created: 12/06/2000: MAB
    >> Dim udtVariant As VARIANT_PTR
    >>
    >> ' Take a copy of the variant to the variant structure.
    >> win.CopyMemory udtVariant, v, 16
    >> ' Only allow variant string arrays.
    >> If udtVariant.vt = (vbString Or vbArray) Then
    >> ' Ensure that any strings in existance are released.
    >> Erase s()
    >> ' Copy the array in the variant over to s().
    >> SafeArrayCopy udtVariant.ptr, VarPtrStringArray(s())
    >> Else
    >> ' Raise a Type Mismatch error.
    >> Err.Raise win.VBErrorConst.eeTypeMismatch
    >> End If
    >>
    >> End Sub
    >>
    >> Public Sub GCopyStringArray(ByRef asSource() As String, _
    >> ByRef asDestination() As String)
    >> ' Purpose: Copies the string array, asSource, to asDestination.
    >> ' Inputs: asSource
    >> ' Outputs: asDestination
    >> ' In/Outs: <None>
    >> ' Created: 12/06/2000: MAB
    >> Dim ptr As Long
    >>
    >> ' Destroy asDestination.
    >> Erase asDestination
    >>
    >> ' Get a pointer to the pointer to asSource.
    >> win.CopyMemory ptr, ByVal VarPtrStringArray(asSource), 4
    >> ' Copy data from asSource to asDestination.
    >> SafeArrayCopy ptr, VarPtrStringArray(asDestination)
    >>
    >> End Sub
    >>
    >> -------
    >>
    >> Well, the GCopyStringArray routine works, but in tests, it is

    >approximately
    >> 5.5 times slower than simply Redim'ing a new string array, and then

    >copying
    >> strings between the old and new arrays. Most perplexing. Can anybody
    >> explain this big difference in speed?
    >>
    >> Thanks,
    >>
    >> ---------------------------------------
    >> Mark Alexander Bertenshaw
    >> Programmer/Analyst
    >> Prime Response
    >> Brentford
    >> UK
    >>
    >>

    >
    >



  4. #4
    Anthony Jones Guest

    Re: SafeArrayCopy SLOWER than iterating string array!

    Mark,

    What happens if you just assign one array to the other. My guess would be
    that VB uses SafeArrayCopy to achieve this so it should be slow to.

    --
    Anthony Jones
    Secta Group Ltd




  5. #5
    Mark Alexander Bertenshaw Guest

    Re: SafeArrayCopy SLOWER than iterating string array!

    Probably - but I am using VB5, thus the API call.

    --

    ---------------------------------------
    Mark Alexander Bertenshaw
    Programmer/Analyst
    Prime Response
    Brentford
    UK
    "Anthony Jones" <yadayadayada@msn.com> wrote in message
    news:394654ff@news.devx.com...
    > Mark,
    >
    > What happens if you just assign one array to the other. My guess would be
    > that VB uses SafeArrayCopy to achieve this so it should be slow to.
    >
    > --
    > Anthony Jones
    > Secta Group Ltd
    >
    >
    >




  6. #6
    Bill McCarthy Guest

    Re: SafeArrayCopy SLOWER than iterating string array!

    Hi Mark,

    When I test the SafeArrayCopy and SafeArrayCopyData functions here, they all
    take about the same time as VB's assignment (VB6) or VB's For..Next methods,
    for large arrays of strings. (see my code below).

    A couple of things.. you don't need a type library to get the pointer for a
    string array. See my code below, and/or see July's VBPJ for more details.
    Also the safearraycopy is most probably the same as VB's assignment, whereas
    safeArrayCopyData would be equivalent of For.. Next loop.

    It could be your timings weren't done on a random basis, and hence the
    sequence of events favoured one method over the other. Try running the code
    I have posted, and you will see which ever method get's called first will
    have the fastest time by far but only that one time.. on subsequent calls
    all methods tend to be about the same, although the For..Next method seems
    to be one or two percent slower.

    Note: the timer class used for timings is Karl Peterson's stop watch class
    (www.mvps.org/vb)


    BTW: it's G'day not "Good day".


    Option Explicit

    Private Enum ArrayCopyMethods
    mCopyNone = 0
    mForNext = 1
    mVbAssign = 2
    mOleCopyData = 3
    mOleCopy = 4
    End Enum

    Private Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory"
    (Destination As Any, Source As Any, ByVal Length As Long)

    Private Declare Function SafeArrayCopyData Lib "oleaut32.dll" (ByVal
    psaSource As Long, ByVal psaTarget As Long) As Long
    Private Declare Function SafeArrayCopy Lib "oleaut32.dll" (ByVal psa As
    Long, ByVal ppsaOut As Long) As Long

    Private Function GetppSA(vVar As Variant) As Long
    CopyMemory GetppSA, ByVal VarPtr(vVar) + 8&, 4&
    End Function

    Private Function GetpSA(vVar As Variant) As Long
    Dim ppSA As Long
    CopyMemory ppSA, ByVal VarPtr(vVar) + 8&, 4&
    CopyMemory GetpSA, ByVal ppSA, 4&
    End Function

    Private Function CopyArray(ByRef asIn() As String, _
    ByRef asOut() As String, _
    ByVal CopyMethod As ArrayCopyMethods) _
    As String

    Dim i As Long, lngUb As Long

    If CopyMethod Then
    If CopyMethod And &H2 Then
    If CopyMethod And &H1 Then
    'mForNext
    lngUb = UBound(asIn)
    ReDim asOut(lngUb)
    For i = 0 To lngUb
    asOut(i) = asIn(i)
    Next i
    CopyArray = "VBForNext"
    Else
    'mVbAssign
    asOut = asIn
    CopyArray = "VBAssign"
    End If

    Else
    If CopyMethod And &H1 Then
    'mOleCopyData
    lngUb = UBound(asIn)
    ReDim asOut(lngUb)
    SafeArrayCopyData GetpSA(asIn), GetpSA(asOut)
    CopyArray = "SafeArrayCopyData"
    Else
    'mOleCopy
    Erase asOut
    SafeArrayCopy GetpSA(asIn), GetppSA(asOut)
    CopyArray = "SafeArrayCopy"
    End If
    End If

    Else
    CopyArray = "function call overhead "
    End If

    End Function

    Sub Main()
    Dim s1() As String, s2() As String
    Dim lngTime As Long
    Dim i As Long, j As Long
    Dim ff As Long
    Dim strMsg As String
    Dim strFile As String

    strFile = App.Path
    If Right$(strFile, 1) <> "\" Then strFile = strFile & "\"
    strFile = strFile & "ArrayCopyTimes.txt"

    ReDim s1(10000)
    For j = 0 To 9
    s1(0 + j * 1000) = "C:\windows\system\" & Dir("C:\windows\system\*.*")
    For i = 1 To 1000
    s1(i + j * 1000) = "C:\windows\system\" & Dir()
    Next i
    Next j
    Dim cSW As CStopWatch
    Set cSW = New CStopWatch
    cSW.Reset

    Randomize Timer
    ff = FreeFile

    Open strFile For Output As ff

    For i = 0 To 99
    j = Rnd * 4
    cSW.Reset
    strMsg = CopyArray(s1, s2, j)
    lngTime = cSW.Elapsed

    Print #ff, strMsg, lngTime
    If j Then
    j = Rnd * 10000
    Print #ff, "item " & j
    Print #ff, s1(j)
    Print #ff, s2(j)
    End If
    Next i

    Close #ff
    MsgBox "finished"
    End Sub




  7. #7
    Michael \(michka\) Kaplan Guest

    Re: SafeArrayCopy SLOWER than iterating string array!

    Not sure what you need to have explained here.... you assume because it uses
    APIs it must be faster?

    What is, speaks for itself. Such as the numbers you have been given.

    --
    MichKa
    "Cause it's a bittersweet symphony, thats life..." -- The Verve

    random junk of dubious value, at the multilingual,
    no scripts required, http://www.trigeminal.com/

    "Mark Alexander Bertenshaw" <Mark.Bertenshaw@virgin.net> wrote in message
    news:39457bdf@news.devx.com...
    > Good day!
    >
    > Being one of those people who is obsessed with maximising the performance

    of
    > repetitive operations, I was looking for alternative ways to copy one

    string
    > array to another in VB5. I have previously been writing a functions to
    > convert a Variant containing a String Array to a String Array, and had

    used
    > the SafeArrayCopy function. This then got me thinking that maybe this
    > function would be a quicker way to copy large string arrays, as happens a
    > lot in our code. After much messing about, I came up with the following
    > code, which requires a type library for the VarPtrStringArray() function
    > (see MSDN Knowledge Base Q199824 - HOWTO: Get the Address of Variables in
    > Visual Basic) :
    >
    > -------
    >
    > Option Explicit
    >
    > Private Declare Function SafeArrayCopy Lib "oleaut32.dll" ( _
    > ByVal psa As Long, _
    > ByVal ppsaOut As Long) As Long
    >
    > Private Type VARIANT_PTR
    > vt As Integer
    > reserved1 As Integer
    > reserved2 As Integer
    > reserved3 As Integer
    > ptr As Long
    > filler(1 To 4) As Byte
    > End Type
    >
    > Public Sub GVariantToStringArray(ByRef v As Variant, _
    > ByRef s() As String)
    > ' Purpose: Retrieves a string array from a variant.
    > ' Inputs: v
    > ' Outputs: s()
    > ' In/Outs: <None>
    > ' Created: 12/06/2000: MAB
    > Dim udtVariant As VARIANT_PTR
    >
    > ' Take a copy of the variant to the variant structure.
    > win.CopyMemory udtVariant, v, 16
    > ' Only allow variant string arrays.
    > If udtVariant.vt = (vbString Or vbArray) Then
    > ' Ensure that any strings in existance are released.
    > Erase s()
    > ' Copy the array in the variant over to s().
    > SafeArrayCopy udtVariant.ptr, VarPtrStringArray(s())
    > Else
    > ' Raise a Type Mismatch error.
    > Err.Raise win.VBErrorConst.eeTypeMismatch
    > End If
    >
    > End Sub
    >
    > Public Sub GCopyStringArray(ByRef asSource() As String, _
    > ByRef asDestination() As String)
    > ' Purpose: Copies the string array, asSource, to asDestination.
    > ' Inputs: asSource
    > ' Outputs: asDestination
    > ' In/Outs: <None>
    > ' Created: 12/06/2000: MAB
    > Dim ptr As Long
    >
    > ' Destroy asDestination.
    > Erase asDestination
    >
    > ' Get a pointer to the pointer to asSource.
    > win.CopyMemory ptr, ByVal VarPtrStringArray(asSource), 4
    > ' Copy data from asSource to asDestination.
    > SafeArrayCopy ptr, VarPtrStringArray(asDestination)
    >
    > End Sub
    >
    > -------
    >
    > Well, the GCopyStringArray routine works, but in tests, it is

    approximately
    > 5.5 times slower than simply Redim'ing a new string array, and then

    copying
    > strings between the old and new arrays. Most perplexing. Can anybody
    > explain this big difference in speed?
    >
    > Thanks,
    >
    > ---------------------------------------
    > Mark Alexander Bertenshaw
    > Programmer/Analyst
    > Prime Response
    > Brentford
    > UK
    >
    >




  8. #8
    Mark Alexander Bertenshaw Guest

    Re: SafeArrayCopy SLOWER than iterating string array!


    Michael -

    I fully understand that APIs can be slower than VB code, which is why I bothered
    to do the test. However, as a general rule, the hackers who wrote API code
    probably have more experience with them than me, and probably know the "guts"
    of the routines, and as a result are more likely to have a faster way to
    use their more primitive routines than me.

    I was just somewhat surprised that my code was 5.5 times faster than theirs.
    I would have expected at least something comparable with mine. I am wondering
    whether there is something in my code that is bound to slow the API routine
    down.

    "Michael \(michka\) Kaplan" <former_mvp@spamfree.trigeminal.nospam.com> wrote:
    >Not sure what you need to have explained here.... you assume because it

    uses
    >APIs it must be faster?
    >
    >What is, speaks for itself. Such as the numbers you have been given.
    >
    >--
    >MichKa
    >"Cause it's a bittersweet symphony, thats life..." -- The Verve
    >
    >random junk of dubious value, at the multilingual,
    >no scripts required, http://www.trigeminal.com/
    >
    >"Mark Alexander Bertenshaw" <Mark.Bertenshaw@virgin.net> wrote in message
    >news:39457bdf@news.devx.com...
    >> Good day!
    >>
    >> Being one of those people who is obsessed with maximising the performance

    >of
    >> repetitive operations, I was looking for alternative ways to copy one

    >string
    >> array to another in VB5. I have previously been writing a functions to
    >> convert a Variant containing a String Array to a String Array, and had

    >used
    >> the SafeArrayCopy function. This then got me thinking that maybe this
    >> function would be a quicker way to copy large string arrays, as happens

    a
    >> lot in our code. After much messing about, I came up with the following
    >> code, which requires a type library for the VarPtrStringArray() function
    >> (see MSDN Knowledge Base Q199824 - HOWTO: Get the Address of Variables

    in
    >> Visual Basic) :
    >>
    >> -------
    >>
    >> Option Explicit
    >>
    >> Private Declare Function SafeArrayCopy Lib "oleaut32.dll" ( _
    >> ByVal psa As Long, _
    >> ByVal ppsaOut As Long) As Long
    >>
    >> Private Type VARIANT_PTR
    >> vt As Integer
    >> reserved1 As Integer
    >> reserved2 As Integer
    >> reserved3 As Integer
    >> ptr As Long
    >> filler(1 To 4) As Byte
    >> End Type
    >>
    >> Public Sub GVariantToStringArray(ByRef v As Variant, _
    >> ByRef s() As String)
    >> ' Purpose: Retrieves a string array from a variant.
    >> ' Inputs: v
    >> ' Outputs: s()
    >> ' In/Outs: <None>
    >> ' Created: 12/06/2000: MAB
    >> Dim udtVariant As VARIANT_PTR
    >>
    >> ' Take a copy of the variant to the variant structure.
    >> win.CopyMemory udtVariant, v, 16
    >> ' Only allow variant string arrays.
    >> If udtVariant.vt = (vbString Or vbArray) Then
    >> ' Ensure that any strings in existance are released.
    >> Erase s()
    >> ' Copy the array in the variant over to s().
    >> SafeArrayCopy udtVariant.ptr, VarPtrStringArray(s())
    >> Else
    >> ' Raise a Type Mismatch error.
    >> Err.Raise win.VBErrorConst.eeTypeMismatch
    >> End If
    >>
    >> End Sub
    >>
    >> Public Sub GCopyStringArray(ByRef asSource() As String, _
    >> ByRef asDestination() As String)
    >> ' Purpose: Copies the string array, asSource, to asDestination.
    >> ' Inputs: asSource
    >> ' Outputs: asDestination
    >> ' In/Outs: <None>
    >> ' Created: 12/06/2000: MAB
    >> Dim ptr As Long
    >>
    >> ' Destroy asDestination.
    >> Erase asDestination
    >>
    >> ' Get a pointer to the pointer to asSource.
    >> win.CopyMemory ptr, ByVal VarPtrStringArray(asSource), 4
    >> ' Copy data from asSource to asDestination.
    >> SafeArrayCopy ptr, VarPtrStringArray(asDestination)
    >>
    >> End Sub
    >>
    >> -------
    >>
    >> Well, the GCopyStringArray routine works, but in tests, it is

    >approximately
    >> 5.5 times slower than simply Redim'ing a new string array, and then

    >copying
    >> strings between the old and new arrays. Most perplexing. Can anybody
    >> explain this big difference in speed?
    >>
    >> Thanks,
    >>
    >> ---------------------------------------
    >> Mark Alexander Bertenshaw
    >> Programmer/Analyst
    >> Prime Response
    >> Brentford
    >> UK
    >>
    >>

    >
    >



  9. #9
    Anthony Jones Guest

    Re: SafeArrayCopy SLOWER than iterating string array!

    Mark,

    What happens if you just assign one array to the other. My guess would be
    that VB uses SafeArrayCopy to achieve this so it should be slow to.

    --
    Anthony Jones
    Secta Group Ltd




  10. #10
    Mark Alexander Bertenshaw Guest

    Re: SafeArrayCopy SLOWER than iterating string array!

    Probably - but I am using VB5, thus the API call.

    --

    ---------------------------------------
    Mark Alexander Bertenshaw
    Programmer/Analyst
    Prime Response
    Brentford
    UK
    "Anthony Jones" <yadayadayada@msn.com> wrote in message
    news:394654ff@news.devx.com...
    > Mark,
    >
    > What happens if you just assign one array to the other. My guess would be
    > that VB uses SafeArrayCopy to achieve this so it should be slow to.
    >
    > --
    > Anthony Jones
    > Secta Group Ltd
    >
    >
    >




  11. #11
    Bill McCarthy Guest

    Re: SafeArrayCopy SLOWER than iterating string array!

    Hi Mark,

    When I test the SafeArrayCopy and SafeArrayCopyData functions here, they all
    take about the same time as VB's assignment (VB6) or VB's For..Next methods,
    for large arrays of strings. (see my code below).

    A couple of things.. you don't need a type library to get the pointer for a
    string array. See my code below, and/or see July's VBPJ for more details.
    Also the safearraycopy is most probably the same as VB's assignment, whereas
    safeArrayCopyData would be equivalent of For.. Next loop.

    It could be your timings weren't done on a random basis, and hence the
    sequence of events favoured one method over the other. Try running the code
    I have posted, and you will see which ever method get's called first will
    have the fastest time by far but only that one time.. on subsequent calls
    all methods tend to be about the same, although the For..Next method seems
    to be one or two percent slower.

    Note: the timer class used for timings is Karl Peterson's stop watch class
    (www.mvps.org/vb)


    BTW: it's G'day not "Good day".


    Option Explicit

    Private Enum ArrayCopyMethods
    mCopyNone = 0
    mForNext = 1
    mVbAssign = 2
    mOleCopyData = 3
    mOleCopy = 4
    End Enum

    Private Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory"
    (Destination As Any, Source As Any, ByVal Length As Long)

    Private Declare Function SafeArrayCopyData Lib "oleaut32.dll" (ByVal
    psaSource As Long, ByVal psaTarget As Long) As Long
    Private Declare Function SafeArrayCopy Lib "oleaut32.dll" (ByVal psa As
    Long, ByVal ppsaOut As Long) As Long

    Private Function GetppSA(vVar As Variant) As Long
    CopyMemory GetppSA, ByVal VarPtr(vVar) + 8&, 4&
    End Function

    Private Function GetpSA(vVar As Variant) As Long
    Dim ppSA As Long
    CopyMemory ppSA, ByVal VarPtr(vVar) + 8&, 4&
    CopyMemory GetpSA, ByVal ppSA, 4&
    End Function

    Private Function CopyArray(ByRef asIn() As String, _
    ByRef asOut() As String, _
    ByVal CopyMethod As ArrayCopyMethods) _
    As String

    Dim i As Long, lngUb As Long

    If CopyMethod Then
    If CopyMethod And &H2 Then
    If CopyMethod And &H1 Then
    'mForNext
    lngUb = UBound(asIn)
    ReDim asOut(lngUb)
    For i = 0 To lngUb
    asOut(i) = asIn(i)
    Next i
    CopyArray = "VBForNext"
    Else
    'mVbAssign
    asOut = asIn
    CopyArray = "VBAssign"
    End If

    Else
    If CopyMethod And &H1 Then
    'mOleCopyData
    lngUb = UBound(asIn)
    ReDim asOut(lngUb)
    SafeArrayCopyData GetpSA(asIn), GetpSA(asOut)
    CopyArray = "SafeArrayCopyData"
    Else
    'mOleCopy
    Erase asOut
    SafeArrayCopy GetpSA(asIn), GetppSA(asOut)
    CopyArray = "SafeArrayCopy"
    End If
    End If

    Else
    CopyArray = "function call overhead "
    End If

    End Function

    Sub Main()
    Dim s1() As String, s2() As String
    Dim lngTime As Long
    Dim i As Long, j As Long
    Dim ff As Long
    Dim strMsg As String
    Dim strFile As String

    strFile = App.Path
    If Right$(strFile, 1) <> "\" Then strFile = strFile & "\"
    strFile = strFile & "ArrayCopyTimes.txt"

    ReDim s1(10000)
    For j = 0 To 9
    s1(0 + j * 1000) = "C:\windows\system\" & Dir("C:\windows\system\*.*")
    For i = 1 To 1000
    s1(i + j * 1000) = "C:\windows\system\" & Dir()
    Next i
    Next j
    Dim cSW As CStopWatch
    Set cSW = New CStopWatch
    cSW.Reset

    Randomize Timer
    ff = FreeFile

    Open strFile For Output As ff

    For i = 0 To 99
    j = Rnd * 4
    cSW.Reset
    strMsg = CopyArray(s1, s2, j)
    lngTime = cSW.Elapsed

    Print #ff, strMsg, lngTime
    If j Then
    j = Rnd * 10000
    Print #ff, "item " & j
    Print #ff, s1(j)
    Print #ff, s2(j)
    End If
    Next i

    Close #ff
    MsgBox "finished"
    End Sub




Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  
HTML5 Development Center
 
 
FAQ
Latest Articles
Java
.NET
XML
Database
Enterprise
Questions? Contact us.
C++
Web Development
Wireless
Latest Tips
Open Source


   Development Centers

   -- Android Development Center
   -- Cloud Development Project Center
   -- HTML5 Development Center
   -- Windows Mobile Development Center