Page 1 of 2 12 LastLast
Results 1 to 40 of 59

Thread: Array optimization - String or Integer?

  1. #1

    Thread Starter
    Hyperactive Member Krass's Avatar
    Join Date
    Aug 2000
    Location
    Montreal
    Posts
    489

    Array optimization - String or Integer?

    My app is currently running pretty good, but I'm trying to figure out if my current setup can be furthermore optimized.

    I have a database table containing only 2 columns, an X and an Y coordinate. At the beginning of my application, I use a recordset to transfer all those coordinates in an array. I didn't feel like simply using the recordset because I felt that dealing with a matrix/array would make things MUCH quicker. (Ain't I right?) I'll be browsing that huge array back and forth many times.

    That database/array might end up containing a million records. YES it'll take a while at startup to fill the array - but that's not a big problem for me.. The app will afterward work with it for 2-3 days until I ask it to stop ( or unless I figure out I made a programming mistake and the memory-ressources gets eaten up too quick )

    (please feel free to comment any of these techniques - I'm open to all good suggestions)

    Another concern would be the array itself: it is declared as a STRING array. Now, if we nevermind the "Why use string if it only contains X,Y integer data???" - Will using a string array make things slower than using an integer array? I've been suggested this and I'd like to have some clarifications. Maybe does it only apply to string variables and such?

    Thank you guys for the feedback.
    Chris

  2. #2
    Member
    Join Date
    May 2007
    Posts
    60

    Re: Array optimization - String or Integer?

    Will using a string array make things slower than using an integer array?
    You bet it will!

    The conversion from string to integer every time you make use of a value will take forever. If they aren't already integers in the database, convert the columns to a numeric data type and save tons of time. At the very least convert them when you read them in.

  3. #3
    Super Moderator si_the_geek's Avatar
    Join Date
    Jul 2002
    Location
    Bristol, UK
    Posts
    41,974

    Re: Array optimization - String or Integer?

    As you are using the data repeatedly, using an array (rather than a recordset) is a good idea - it should be much quicker.

    As to it containing a million records, you may find that it uses up all of your spare physical memory, at which point your computer will become dramatically slower. Whether this is an issue or not depends on the size of the data, and the physical memory you have spare at any point when the program runs.


    As to the data type of the array.. think what you would use if you had lots of separate variables instead, as an array is basically a group of variables.

    To hold numeric data, Strings will use more space than the proper data types (any Integer takes 2 bytes, but a string takes 10 bytes plus the length of the string - so "99" will take 12 bytes [10 extra], and "32000" will take 15 [13 extra]). Assuming a million rows of just two values, that would be between 20MB and 30MB as string data, but only 4MB as numeric data.

    Strings in VB are generally very slow, and if you are performing any type of mathematical calculations on them, this will be even worse - as they will get automatically converted to numbers (possibly Integers) before the calculation, and the final result converted back to a string.


    You should always try to use the correct data type for the data, as it not only removes the extra conversions, but also dramatically reduces the chances of conversion/concatenation errors too.

  4. #4

    Thread Starter
    Hyperactive Member Krass's Avatar
    Join Date
    Aug 2000
    Location
    Montreal
    Posts
    489

    Re: Array optimization - String or Integer?

    si_the_geek, bogie: GREAT FEEDBACK... thank you!

    My database is already in INTEGER type. The reason why I used a string array is that this array contains information from many sources - it's like having 500 arrays into one. So at the end of each "sub-array", I have some string-info in the array, something like "END-OF-ARRAY;INFO-BLABLA" to know where I'm at, in the array.

    I guess I'll reconfigure how it works to avoid having that huge array as a string array - I guess I could manage to do that easily.

    My machine has 3GB of physical memory. I'm planning on having a standalone machine(s) to deal with this - and I'll add all the required memory if needed.

    si_the_beek, thanks for the brief but very informative tips about byte-usage of those variables.

    Chris

  5. #5

    Thread Starter
    Hyperactive Member Krass's Avatar
    Join Date
    Aug 2000
    Location
    Montreal
    Posts
    489

    Re: Array optimization - String or Integer?

    Another question comes to mind:

    To make sure my app doesn't crash, I have some checkups here and there on the "UBound(matMyMatrix, 1)" to avoid going further.

    Should I save the UBound result in a variable and use this for the checkup instead? Or will UBound offer me an as blazing-fast result?
    Chris

  6. #6
    Super Moderator si_the_geek's Avatar
    Join Date
    Jul 2002
    Location
    Bristol, UK
    Posts
    41,974

    Re: Array optimization - String or Integer?

    Rather than having the extra string info in the array, I would add a third 'column' to the array which points to another (string) array which contains that data. You would then be able to know from any row of the original data which 'sub-array' the data comes from.


    As for storing the result of UBound to a variable, that could be a good idea (especially if you are calling it within a loop), as calling functions (even built in ones) takes time, as does actually running them. In this particular case the difference isn't huge, but if you also make a similar sort of change for other function calls you will get a noticeable gain.

    If you are resizing the array at any point (which is very slow, especially with Preserve), using this variable allows you to use a much faster method.


    I would recommend reading the article How do I optimize my code? from our Classic VB FAQs (in the FAQ forum, which is shown near the top of our home page), as it contains several useful tips.

  7. #7

    Thread Starter
    Hyperactive Member Krass's Avatar
    Join Date
    Aug 2000
    Location
    Montreal
    Posts
    489

    Re: Array optimization - String or Integer?

    si_the_geek strikes again.

    Good stuff.. I was already thinking about that 3rd row idea. But I think I will store info in that 3rd row only at the beginning of a "sub-array" since I don't need to check it up at any row. When I reach the beginning of a sub-array, I will simply keep its info in another variable and loop until the 3rd columns contains something again. I guess that'll lighten my array, too.

    I do have to redim the array with PRESERVE.. But I'll put it on a 5-10 minutes timer so it won't be growing THAT much. Or anyway not that often.

    I'll make sure I read that optimize-your-code thread. I think I print it once to help me pass time in the plane, but I didn't read it and prolly lost it since.

    Thank again for the tips.
    Chris

  8. #8
    Banned randem's Avatar
    Join Date
    Oct 2002
    Location
    Maui, Hawaii
    Posts
    11,385

    Re: Array optimization - String or Integer?

    Long is the fastest data type to process since it is native to the processor.

  9. #9
    PowerPoster Code Doc's Avatar
    Join Date
    Mar 2007
    Location
    Omaha, Nebraska
    Posts
    2,354

    Re: Array optimization - String or Integer?

    Rule of thumb:
    When in doubt use integer, long if necessary (>32768). Integer processing will always outrun strings and single precision.

    I recall writing code once upon a time that converted single precision to integers by removing the decimal, performing the integer calculations, tracking the decimal point movement, and then displaying the results as a string by repositioning the decimal after the integer computations finished.

    That "idiotic" procedure was faster than letting the computer perform single-precision manipulations with the same values.
    Doctor Ed

  10. #10

    Thread Starter
    Hyperactive Member Krass's Avatar
    Join Date
    Aug 2000
    Location
    Montreal
    Posts
    489

    Re: Array optimization - String or Integer?

    I might have to benchmark both solutions. If randem is right, it sounds like I should go LONG. I will NEVER deal with decimals.
    Chris

  11. #11
    Frenzied Member
    Join Date
    Jun 2006
    Posts
    1,098

    Re: Array optimization - String or Integer?

    If your values will never exceed the range of Integer, -32768 to 32767, then stick with the Integer data type. They are half the size of Long, which could be significant given the size of your array, and you will never notice the difference in speed.

  12. #12
    PowerPoster Ellis Dee's Avatar
    Join Date
    Mar 2007
    Location
    New England
    Posts
    3,530

    Re: Array optimization - String or Integer?

    randem's generalized point about Long being more efficient is correct, but Logo's point about using an extra 4mb of memory is the bottom line for speed in this case.
    Quote Originally Posted by Krass
    My database is already in INTEGER type. The reason why I used a string array is that this array contains information from many sources - it's like having 500 arrays into one. So at the end of each "sub-array", I have some string-info in the array, something like "END-OF-ARRAY;INFO-BLABLA" to know where I'm at, in the array.
    Sounds like it could be done better as a UDT array. A UDT array would also give you a more logical structure. Something like:
    vb Code:
    1. Private Type CoordinateType
    2.     x As Integer
    3.     y As Integer
    4. End Type
    5.  
    6. Private Type MainType
    7.     Info As String
    8.     Coords() As CoordinateType
    9.     Length As Long ' Stores the UBound() of Coords()
    10. End Type
    11.  
    12. Private mtyp() As MainType
    13.  
    14. Public Sub InitArray()
    15.     Dim i As Long
    16.     Dim j As Long
    17.  
    18.     ReDim mtyp(500)
    19.     For i = 0 To 500
    20.         With mtyp(i)
    21.             .Info = "Description goes here"
    22.             ReDim .Coords(2000)
    23.             .Length = 2000
    24.             For j = 0 To 2000
    25.                 With .Coords(j)
    26.                     .x = rst!x
    27.                     .y = rst!y
    28.                 End With
    29.             Next
    30.         End With
    31.     Next
    32. End Sub
    That's the basic idea, anyway.

  13. #13
    Banned randem's Avatar
    Join Date
    Oct 2002
    Location
    Maui, Hawaii
    Posts
    11,385

    Re: Array optimization - String or Integer?

    Getting back to the database most large database engines use the integer type but it is really a long data type... Unless it is defined as short integer or small integer or something like that.

  14. #14
    Banned randem's Avatar
    Join Date
    Oct 2002
    Location
    Maui, Hawaii
    Posts
    11,385

    Re: Array optimization - String or Integer?

    Besides I have never heard of a resultset being a million records and I have done some of the most busy financial systems and no where near that many records are used at one time...

  15. #15
    Super Moderator si_the_geek's Avatar
    Join Date
    Jul 2002
    Location
    Bristol, UK
    Posts
    41,974

    Re: Array optimization - String or Integer?

    That's a much better idea Ellis... I knew there was something that could be done for the organisational side of things, but didn't think of that even tho I use it regularly myself.
    Quote Originally Posted by randem
    Getting back to the database most large database engines use the integer type but it is really a long data type... Unless it is defined as short integer or small integer or something like that.
    Very true, but as long as the values are always within the valid range for VB's Integer, that wont be a problem - the coercion will be fine.

    I definitely agree with Logophobic's comments on the use of Integer for this - the Long data type is likely to cause more harm than good, unless it is required due to the scale of the numbers.
    Besides I have never heard of a resultset being a million records and I have done some of the most busy financial systems and no where near that many records are used at one time...
    That's a fair point.. this amount of data is rather extreme (but not unheard of), and there may well be a much better/faster way to cope with this data - but it depends on what Krass is actually trying to achieve.

  16. #16

    Thread Starter
    Hyperactive Member Krass's Avatar
    Join Date
    Aug 2000
    Location
    Montreal
    Posts
    489

    Re: Array optimization - String or Integer?

    Hah. The usefulness of those forums will always amaze me.

    I never played with UDT. At least not for such large jobs. I'll dig into that and that'll probably be my next posts topic!

    A million records is something I never had to play with, too. Those X,Y coordinates are actually the coordinates of each "given-color"-pixels in many different pictures, which I'll have to compare with another smaller array (another picture).

    Thanks for the feedback.
    Chris

  17. #17

    Thread Starter
    Hyperactive Member Krass's Avatar
    Join Date
    Aug 2000
    Location
    Montreal
    Posts
    489

    Re: Array optimization - String or Integer?

    From a brief first reading of Ellis Dee's idea of using a User-Defined Type Array, the following questions pops up:

    Will I be able to redim that array with PRESERVE just like normal arrays?

    the .info (declared as string) will be filled with data 0.005% of the time. I guess it would be a waste of memory (speed) having that string declaration in there? I mean, even if it was integer! I'll need to know that the "sub-array" I'm browsing right now is, let's say, "252", but I'll only note that down when I'm reaching a new sub-array, I won't be using its content all the time.

    Also I don't think the UBound result should be stored in the UDT, since it's pretty static and an outside variable would do the job as well.

    Just my first 2 cents.. I'll work a bit on this and see how it goes.

    Thanks
    Chris

  18. #18
    Super Moderator si_the_geek's Avatar
    Join Date
    Jul 2002
    Location
    Bristol, UK
    Posts
    41,974

    Re: Array optimization - String or Integer?

    You will be able to ReDim in the usual way, as the UDT's (MainType and CoordinateType) are treated the same way as other data types (Integer/String/..).

    Your concerns about the .Info and .Length items aren't valid, as there is only one copy for each set of data, and the actual X/Y data is in the Coords() array (which itself is based on a UDT!).


    It would probably be a good idea to create a quick test program with a similar data structure, and step through it (including adding items to the watch window) to help you understand it.

  19. #19

    Thread Starter
    Hyperactive Member Krass's Avatar
    Join Date
    Aug 2000
    Location
    Montreal
    Posts
    489

    Re: Array optimization - String or Integer?

    si_the_geek, thanks for clearing things up.

    I understand that whole UDT thing very good now, well.... how Ellis Dee used it. - I must say that looks perfect. Nicely done, Ellis Dee, your sample code will probably look a lot like my final code

    While playing Guitar Hero 2 and Settlers of Catan tonight I was thinking of keeping it the way it is (but manage to avoid strings). But that new method sure looks sweet!

    You guys should play guitar hero 2..

    Thanks for the help again
    (gh2)
    Chris

  20. #20
    PowerPoster Ellis Dee's Avatar
    Join Date
    Mar 2007
    Location
    New England
    Posts
    3,530

    Re: Array optimization - String or Integer?

    Quote Originally Posted by Krass
    Also I don't think the UBound result should be stored in the UDT, since it's pretty static and an outside variable would do the job as well.
    Either way works, but in the code sample above the UBound() effectively is "outside", because it's not a part of the coordinates array.

    Is each subarray the same length? If so, then you're right, it's pointless waste to maintain 500 copies of the same number in the UDT.

    For the text descriptions, though, regardless of how infrequently you need to reference them the way it is shown above is the best way to go if you have a different description for each subarray.

  21. #21

    Thread Starter
    Hyperactive Member Krass's Avatar
    Join Date
    Aug 2000
    Location
    Montreal
    Posts
    489

    Re: Array optimization - String or Integer?

    Ellis, each subarray will indeed be of a diffrent length. So your method is good.

    That makes me think: some of my arrays are going to be 300-long, some 900-long, but the average will be about 500. I guess it would be a good idea to redim Coords() to 1000 right at the beginning of my procedure (when I fill the X,Y) .. and, at the end, do a last negative redim to remove all unused rows?

    That sounds like a good idea to me, because I used to do a loop and do a redim preserve to add +1 each time I need to add a new X,Y.. So that's a lot or redim PRESERVE.

    My only worry is: Are the memory/ressources gonna get free'd nicely without hassle? Would you recommend this approach?

    (... I *just* realised : if this approach is good, alright.. it is good knowledge for me. But that would be optimizing the part of filling my arrays - the part that is not critical for me, optimizingly speaking!.. oh well)

    Thanks.
    Chris

  22. #22
    PowerPoster Ellis Dee's Avatar
    Join Date
    Mar 2007
    Location
    New England
    Posts
    3,530

    Re: Array optimization - String or Integer?

    Quote Originally Posted by Krass
    That makes me think: some of my arrays are going to be 300-long, some 900-long, but the average will be about 500. I guess it would be a good idea to redim Coords() to 1000 right at the beginning of my procedure (when I fill the X,Y) .. and, at the end, do a last negative redim to remove all unused rows?
    That'd work fine. Memory will be freed nicely when you ReDim Preserve it down to the final size after each subarray loop finishes.

    You don't have any way to identify how many coordinate pairs are in a given subarray before you start populating it?

  23. #23
    Cumbrian Milk's Avatar
    Join Date
    Jan 2007
    Location
    0xDEADBEEF
    Posts
    2,448

    Re: Array optimization - String or Integer?

    Just out of interest, you say this is about comparing arrays (representing particular pixels) between many different images. Would you mind telling us a little more about that? There are some blindingly fast ways to work with pixel data which might help if appropriate.

  24. #24

    Thread Starter
    Hyperactive Member Krass's Avatar
    Join Date
    Aug 2000
    Location
    Montreal
    Posts
    489

    Re: Array optimization - String or Integer?

    Each sub-arrays are MASKS of a word (for some reason I couldn't go by letter). Comparing all those sub-arrays (masks) against one other main picture will allow me to extract info from that image as it if was text (some player stats info from an online game: that has been done before, it's something like it, but in a more personal field) - anyway you get the idea.

    My loops are checking up blue pixels, as it's all I need. Sometimes yellow, for numbers - in case I need that to be done.

    I know I've been proven wrong before (!), but I'm pretty sure the part of storing X,Ys in a database, to then fill an array/udt is the way to go. Those sub-arrays are actually created by me, dynamically, and it would slow down the whole process to have it deal with "finding blue pixels" everytime in my "huge" loop. - those are already found out and in a DB!

    That method was primarily used to avoid using the very slow Pic1.point method which would slow down the process a lot. (because my sub arrays are X,Y coords retrieved from a picturebox, loaded up with each of my sub-arrays one after the other).

    That might be confusing.

    One optimization that will need to be done is a technique I heard in one of my last posts on which I'll have to give more attention when my main "looping" code is up and running, optimized. It consists in turning the picturebox content in an array instantly - it sounded like a nice technique, but on the first read I didn't quite understood - will get back to it later.

    Ellis Dee: You are right. Once the X,Ys are in my DB, I could easily know how long I must create the coordinate array - avoiding redims..... Like I said, I don't need much optimization for THAT application portion but - it'll be done that way!

    Thank you's!
    Chris

  25. #25
    Super Moderator si_the_geek's Avatar
    Join Date
    Jul 2002
    Location
    Bristol, UK
    Posts
    41,974

    Re: Array optimization - String or Integer?

    The Point method (and similar ones) are painfully slow... it sounds like your future method is DIB Sections, which (once you've got your head around them!) will make a huge improvement to the speed of reading/writing pixels.

  26. #26
    Cumbrian Milk's Avatar
    Join Date
    Jan 2007
    Location
    0xDEADBEEF
    Posts
    2,448

    Re: Array optimization - String or Integer?

    Here's a quick way to get those pixels into an array using GetDIBits. There is a slight caveat extacting the data this way inverts the Y axis and alters the colours (they become BGRA as opposed to RGBA). I've included a conversion function to toggle between RGBA and BGRA. There is also an option to produce a two Dimensional array but you will find the single dimensional array performs better. If you want to use this with the two dimensional array you will have to invert the Y coordinates in your Database, much better would be to then convert each pair of X and inverted Y integers into a single Long and use a one dimensional array, this is easier than it sounds and can be done quickly.

    Also seeing as you are only interested in a few colours it's worth converting the image data from a long array and into a byte array that just holds the colours you are interested in, see the retByteData function.
    vb Code:
    1. 'Module code
    2. Option Explicit
    3.  
    4. Private Declare Function GetObjectA Lib "GDI32" (ByVal hObject As Long, ByVal nCount As Long, ByRef lpObject As Any) As Long
    5. Private Declare Function GetDIBits Lib "GDI32" (ByVal hDC As Long, ByVal hBitmap As Long, ByVal nStartScan As Long, ByVal nNumScans As Long, lpBits As Any, lpBI As BITMAPINFO, ByVal wUsage As Long) As Long
    6. Private Declare Sub RtlMoveMemory Lib "kernel32" (Destination As Any, Source As Any, ByVal Length As Long)
    7.  
    8. Private Type BITMAP '24 bytes
    9.  bmType As Long
    10.  bmWidth As Long
    11.  bmHeight As Long
    12.  bmWidthBytes As Long
    13.  bmPlanes As Integer
    14.  bmBitsPixel As Integer
    15.  bmBits As Long
    16. End Type
    17.  
    18. Private Type RGBQUAD
    19.  Blue As Byte
    20.  Green As Byte
    21.  Red As Byte
    22.  Alpha As Byte
    23. End Type
    24.  
    25. Private Type BITMAPINFOHEADER '40 bytes
    26.  bmSize As Long
    27.  bmWidth As Long
    28.  bmHeight As Long
    29.  bmPlanes As Integer
    30.  bmBitCount As Integer
    31.  bmCompression As Long
    32.  bmSizeImage As Long
    33.  bmXPelsPerMeter As Long
    34.  bmYPelsPerMeter As Long
    35.  bmClrUsed As Long
    36.  bmClrImportant As Long
    37. End Type
    38.  
    39. Private Type BITMAPINFO
    40.  bmHeader As BITMAPINFOHEADER
    41.  bmColors(0 To 255) As RGBQUAD
    42. End Type
    43.  
    44. Public Function RetDIBDataLong(PictureObject As Object, Optional Return2DArray As Boolean) As Long()
    45. Dim BM As BITMAP, bmi As BITMAPINFO, lngImageData() As Long
    46.    'The PictureObject must be an object with both a HDC and Image property
    47.    'such as a PictureBox, UserControl or Form
    48.    
    49.    GetObjectA PictureObject.Image, 24, BM
    50.    bmi.bmHeader.bmWidth = BM.bmWidth
    51.    bmi.bmHeader.bmHeight = BM.bmHeight
    52.    bmi.bmHeader.bmSize = 40
    53.    bmi.bmHeader.bmPlanes = 1
    54.    bmi.bmHeader.bmBitCount = 32
    55.    
    56.    If Return2DArray Then
    57.      ReDim lngImageData(BM.bmWidth - 1, BM.bmHeight - 1)
    58.      GetDIBits PictureObject.hDC, PictureObject.Image.Handle, 0, BM.bmHeight, lngImageData(0, 0), bmi, 0
    59.    Else
    60.      ReDim lngImageData(BM.bmWidth * BM.bmHeight - 1)
    61.      GetDIBits PictureObject.hDC, PictureObject.Image.Handle, 0, BM.bmHeight, lngImageData(0), bmi, 0
    62.    End If
    63.    
    64.    RetDIBDataLong = lngImageData
    65. End Function
    66.  
    67. Public Function retByteData(PictureObject As Object, SearchPalette() As Long) as Byte()
    68. 'The ImageObject must be an object with both a HDC and Image property
    69. 'such as a PictureBox, UserControl or Form
    70.  
    71. 'The searchpalette should contain no more than 255 colours and these
    72. 'colours must be in the form of DIBSection colours i.e. BGRA not RGBA see
    73. 'ConvertColour function below
    74.  
    75.  
    76. Dim i As Long, ii As Long, lPalLen As Long, lngImageData() As Long, bytImageData() As Byte
    77.   lPalLen = UBound(SearchPalette)
    78.   If lPalLen > 254 Then lPalLen = 254
    79.  
    80.   lngImageData = RetDIBDataLong(PictureObject)
    81.   i = UBound(lngImageData)
    82.   ReDim bytImageData(i)
    83.  
    84.   For i = 0 To i
    85.     For ii = 0 To lPalLen
    86.       If lngImageData(i) = SearchPalette(ii) Then
    87.         bytImageData(i) = ii + 1
    88.         Exit For
    89.       End If
    90.     Next ii
    91.   Next i
    92.  
    93.  'If you only want a couple of colours they might be better HardCoded here rather
    94.  'than in the passed SearchPalette, example loop would then be...
    95.   'For i = 0 To i
    96.       'Select Case lngImageData(i)
    97.         'Case Colour1
    98.           'bytImageData(i) = 1
    99.         'Case Colour2
    100.           'bytImageData(i) = 2
    101.       'End Select
    102.   'Next i
    103.  
    104.   retByteData = bytImageData
    105. End Function
    106.  
    107. Public Function ConvertColour(ByVal Colour As Long) As Long
    108. Dim uRGBA As RGBQUAD, Swp As Byte
    109.   RtlMoveMemory uRGBA, Colour, 4&
    110.   With uRGBA
    111.      Swp = .Red
    112.     .Red = .Blue
    113.     .Blue = Swp
    114.   End With
    115.   RtlMoveMemory Colour, uRGBA, 4&
    116.   ConvertColour = Colour
    117. End Function
    vb Code:
    1. 'Example calling code for a form with two pictureboxes and two command buttons
    2. Option Explicit
    3. Private Declare Function SetPixelV Lib "GDI32" (ByVal hDC As Long, ByVal X As Long, ByVal Y As Long, ByVal crColor As Long) As Byte
    4.  
    5. Private Sub Command1_Click()
    6. Dim PicData() As Byte, pal() As Long, i As Long, W As Long
    7.   ReDim pal(3)
    8.   'First fill the pal array with the colours we want to capture, up to 255
    9.   'RGB can be used to generate 32bpp DIB Colours by swaping Red for Blue and visa versa
    10.   pal(0) = RGB(0, 3, 1) 'same as ConvertColour(RGB(1, 3, 0))
    11.   pal(1) = RGB(3, 0, 15)
    12.   pal(2) = RGB(33, 0, 206)
    13.   pal(3) = RGB(249, 252, 250)
    14.   PicData = retByteData(Picture1, pal)
    15.  
    16.   'This next bit is slow, it is just to show the data we have just gained visualy
    17.   With Picture1
    18.     W = Picture1.ScaleX(.ScaleWidth, .ScaleMode, vbPixels)
    19.   End With
    20.  
    21.   Picture2.Cls
    22.   For i = 0 To UBound(PicData)
    23.     If PicData(i) Then SetPixelV Picture2.hDC, i Mod W, i \ W, QBColor(PicData(i))
    24.   Next i
    25.   'As you can see the Y axis has been inverted
    26. End Sub
    27.  
    28.  
    29. Private Sub Command2_Click()
    30.  
    31. Dim PicData() As Long, X As Long, Y As Long, UBY As Long
    32.   'Get the pixel data very quickly
    33.   PicData = RetDIBDataLong(Picture1, True)
    34.  
    35.   'Then a slow method to show how the Y axis is inverted and the Red and Blue bytes are swapped
    36.   Picture2.Cls
    37.   UBY = UBound(PicData, 2)
    38.   For X = 0 To UBound(PicData, 1)
    39.     For Y = 0 To UBY
    40.       SetPixelV Picture2.hDC, X, Y, PicData(X, Y)
    41.     Next Y
    42.   Next X
    43. End Sub
    To copy the code, quote the post and copy from there.
    Attached is the image I tested this with.
    Attached Images Attached Images  
    Last edited by Milk; Sep 17th, 2007 at 04:51 PM. Reason: errors, errors

  27. #27

    Thread Starter
    Hyperactive Member Krass's Avatar
    Join Date
    Aug 2000
    Location
    Montreal
    Posts
    489

    Re: Array optimization - String or Integer?

    Hello.

    I think I'm done optimizing my main loop. Using the method you guys suggested (user defined types) - and avoiding strings - significantly speeds up the process.

    I don't think the code can be done better, below is an idea of what it looks like... It's designed to find matching pixels (same X,Y from my sub-array (from 1 millions record array - about 500 records each times) as the X,Y from the small image I'm comparing it to).

    Code:
    Do While xSmall <= intSmallUBound - 1 And xHuge <= HugeType(i).Length - 1
        If HugeType(i).Coords(xHuge).x < (arrSmallSubArray(0, xSmall) + xAdd) Then
            xHuge = xHuge + 1
        ElseIf HugeType(i).Coords(xHuge).x > (arrSmallSubArray(0, xSmall) + xAdd) Then
            xSmall = xSmall + 1
        ElseIf HugeType(i).Coords(xHuge).y < (arrSmallSubArray(1, xSmall) + yAdd) Then
            xHuge = xHuge + 1
        ElseIf HugeType(i).Coords(xHuge).y > (arrSmallSubArray(1, xSmall) + yAdd) Then
            xSmall = xSmall + 1
        Else
            xSmall = xSmall + 1
            xHuge = xHuge + 1
            MatchCount = MatchCount + 1
        End If
    Loop
    My next step is to read, understand and implement Milk's piece of code. Btw thank you, that seems to be pretty complete. That's the last portion slowing down my application with those .pset and .point calls. I'm hoping to have time testing this next week.

    I've got a (maybe a little off-topic) question. When populating a recordset, why must I use .movelast to be able to retrieve .recordcount? If I just populate it and check the .recordcount it will always show "0". Not a big problem, but I find it weird to have to use .movelast and .movefirst to retrieve that info.

    Thank you!
    Chris

  28. #28
    PowerPoster Ellis Dee's Avatar
    Join Date
    Mar 2007
    Location
    New England
    Posts
    3,530

    Re: Array optimization - String or Integer?

    Quote Originally Posted by Krass
    When populating a recordset, why must I use .movelast to be able to retrieve .recordcount? If I just populate it and check the .recordcount it will always show "0". Not a big problem, but I find it weird to have to use .movelast and .movefirst to retrieve that info.
    It's an optimization; the server doesn't send the entire recordset until it has to.

    If you have some time, I've always been curious if the With operator speeds up UDT array access. If you change the code you posted to the following, is it any faster?
    Code:
    With HugeType(i)
        Do While xSmall <= intSmallUBound - 1 And xHuge <= .Length - 1
            If .Coords(xHuge).x < (arrSmallSubArray(0, xSmall) + xAdd) Then
                xHuge = xHuge + 1
            ElseIf .Coords(xHuge).x > (arrSmallSubArray(0, xSmall) + xAdd) Then
                xSmall = xSmall + 1
            ElseIf .Coords(xHuge).y < (arrSmallSubArray(1, xSmall) + yAdd) Then
                xHuge = xHuge + 1
            ElseIf .Coords(xHuge).y > (arrSmallSubArray(1, xSmall) + yAdd) Then
                xSmall = xSmall + 1
            Else
                xSmall = xSmall + 1
                xHuge = xHuge + 1
                MatchCount = MatchCount + 1
            End If
        Loop
    End With
    Also, I see couple tweaks you could do to squeeze a little more speed out of the posted code.
    Code:
    With HugeType(i)
        Do While xSmall < intSmallUBound And xHuge < .Length ' removing the two subtractions should help a bit
            Select Case arrSmallSubArray(0, xSmall) + xAdd
                Case Is > .Coords(xHuge).x: xHuge = xHuge + 1
                Case Is < .Coords(xHuge).x: xSmall = xSmall + 1
                Case Else
                    Select Case arrSmallSubArray(1, xSmall) + yAdd
                        Case Is > .Coords(xHuge).y: xHuge = xHuge + 1
                        Case Is < .Coords(xHuge).y: xSmall = xSmall + 1
                        Case Else
                            xSmall = xSmall + 1
                            xHuge = xHuge + 1
                            MatchCount = MatchCount + 1
                    End Select
            End Select
        Loop
    End With
    While I concede that this logic is much less readable, it should be perceptibly more efficient. Every iteration of the Do...Loop has at least 2 fewer arithmetic operations, and each match saves another two operations. Given the huge number of passes this loop is making, this could add up to a fairly decent speed boost.

  29. #29
    Super Moderator si_the_geek's Avatar
    Join Date
    Jul 2002
    Location
    Bristol, UK
    Posts
    41,974

    Re: Array optimization - String or Integer?

    I don't quite understand what the code is supposed to achieve, but there are a few things you could do that may improve the speed a bit.

    The With block as Ellis suggested should give an improvement, as should the changes on the Do line.


    Over the life of the loop you are repeatedly checking the same values which involve array access (slightly slower than reading a variable), and some of them also involve calculations too (which again take time).

    I would recommend storing the result of (arrSmallSubArray(0, xSmall) + xAdd) (and the Y equivalent into variables and using them instead - of course re-calculating the value whenever xSmall changes.

    You could do similar for HugeType(i).Coords(xHuge) , as that also takes time (two array accesses, and one member lookup), resetting it whenever xHuge changes. If you use a With block, this may not get much benefit.

    Ellis's use of Select Case is a reasonable alternative to these variables, but I think the variables will be faster... although the Select Case method can be improved by using Sgn function, eg:
    Code:
            Select Case Sgn((arrSmallSubArray(0, xSmall) + xAdd) - (.Coords(xHuge).x))
                Case 1: xHuge = xHuge + 1
                Case -1: xSmall = xSmall + 1
                case Else
    ..whether this beats the variables depends on various factors, so would need to be tested.


    There is another possible improvement which is highly dependent on the data, and may not make a big difference.. if the final Else condition is a regular occurrence, you would find speed gains by re-ordering the If's (as an = comparison is faster than a < one, and it would mean a maximum of 3 If's instead of 4).


    As to the recordset issue, you can get a RecordCount without a MoveLast if set the CursorLocation to clientside, and change the CursorType. But.. that is slow, and for speed you should run a "SELECT Count(*)" type query instead.

  30. #30
    PowerPoster Ellis Dee's Avatar
    Join Date
    Mar 2007
    Location
    New England
    Posts
    3,530

    Re: Array optimization - String or Integer?

    Quote Originally Posted by si_the_geek
    ... although the Select Case method can be improved by using Sgn function, eg:
    Code:
            Select Case Sgn((arrSmallSubArray(0, xSmall) + xAdd) - (.Coords(xHuge).x))
                Case 1: xHuge = xHuge + 1
                Case -1: xSmall = xSmall + 1
                case Else
    This benchmarks much slower on my machine:
    vb Code:
    1. Private Sub Sample()
    2.     Const Iterations = 10000000
    3.     Dim sngStart As Single
    4.     Dim i As Long
    5.     Dim x As Long
    6.     Dim y As Long
    7.    
    8.     x = 32
    9.     y = 57
    10.     sngStart = Timer
    11.     For i = 1 To Iterations
    12.         Select Case x
    13.             Case Is < y
    14.         End Select
    15.     Next
    16.     MsgBox Format(Timer - sngStart, "0.000")
    17.     sngStart = Timer
    18.     For i = 1 To Iterations
    19.         Select Case Sgn(x - y)
    20.             Case -1
    21.         End Select
    22.     Next
    23. End Sub
    I get 0.062 and 0.230 respectively. It effectively adds a function call and an operation, though four times slower is more extreme than I expected.

    Your other suggestions will almost certainly speed things up a bit despite the code sprawl and extra assignments:
    Code:
    Dim lngHugeX As Long
    Dim lngHugeY As Long
    Dim lngSmallX As Long
    Dim lngSmallY As Long
    Dim lngLength As Long
    
    With HugeType(i)
        lngLength = .Length
        With .Coords(xHuge)
            lngHugeX = .x
            lngHugeY = .y
        End With
        lngSmallX = arrSmallSubArray(0, xSmall) + xAdd
        lngSmallY = arrSmallSubArray(1, xSmall) + yAdd
        Do While xSmall < intSmallUBound And xHuge < lngLength
            Select Case lngHugeX
                Case Is < lngSmallX
                    xHuge = xHuge + 1
                    With .Coords(xHuge)
                        lngHugeX = .x
                        lngHugeY = .y
                    End With
                Case Is > lngSmallX
                    xSmall = xSmall + 1
                    lngSmallX = arrSmallSubArray(0, xSmall) + xAdd
                    lngSmallY = arrSmallSubArray(1, xSmall) + yAdd
                Case Else
                    Select Case lngHugeY
                        Case Is < lngSmallY
                            xHuge = xHuge + 1
                            With .Coords(xHuge)
                                lngHugeX = .x
                                lngHugeY = .y
                            End With
                        Case Is > lngSmallY
                            xSmall = xSmall + 1
                            lngSmallX = arrSmallSubArray(0, xSmall) + xAdd
                            lngSmallY = arrSmallSubArray(1, xSmall) + yAdd
                        Case Else
                            xSmall = xSmall + 1
                            xHuge = xHuge + 1
                            MatchCount = MatchCount + 1
                            With .Coords(xHuge)
                                lngHugeX = .x
                                lngHugeY = .y
                            End With
                            lngSmallX = arrSmallSubArray(0, xSmall) + xAdd
                            lngSmallY = arrSmallSubArray(1, xSmall) + yAdd
                    End Select
            End Select
        Loop
    End With
    If you are comparing arrSmallSubArray() to all 500 HugeType() subarrays, then you could definitely optimize that by adding xAdd and yAdd to the values in a single loop once before you begin the million comparisons. Even if you then went through and subtracted the offsets back out at the end, the speed savings should be significant.

    Of course, doing that would reduce the speed improvement of the above code, since there would be fewer operations that get avoided.

    Now that I'm thinking about it, I think it will be as fast or faster to read an array value twice than it is to read it once and assign it to another variable, so I'm not sure how effective the above code will be. I'll craft yet another version and put it in a new post.

  31. #31
    PowerPoster Ellis Dee's Avatar
    Join Date
    Mar 2007
    Location
    New England
    Posts
    3,530

    Re: Array optimization - String or Integer?

    Code:
    For i = 0 To UBound(arrSmallSubArray, 2)
        arrSmallSubArray(0, i) = arrSmallSubArray(0, i) + xAdd
        arrSmallSubArray(1, i) = arrSmallSubArray(1, i) + yAdd
    Next
    '....code you didn't post goes here
    For i = 0 To UBound(HugeType)
        '....code you didn't post goes here
        With HugeType(i)
            Do While xSmall < intSmallUBound And xHuge < .Length ' removing the two subtractions should help a bit
                With .Coords(xHuge)
                    Select Case arrSmallSubArray(0, xSmall)
                        Case Is > .x: xHuge = xHuge + 1
                        Case Is < .x: xSmall = xSmall + 1
                        Case Else
                            Select Case arrSmallSubArray(1, xSmall)
                                Case Is > .y: xHuge = xHuge + 1
                                Case Is < .y: xSmall = xSmall + 1
                                Case Else
                                    xSmall = xSmall + 1
                                    xHuge = xHuge + 1
                                    MatchCount = MatchCount + 1
                            End Select
                    End Select
                End With
            Loop
        End With
        '....code you didn't post goes here
    Next
    '....code you didn't post goes here
    For i = 0 To UBound(arrSmallSubArray, 2)
        arrSmallSubArray(0, i) = arrSmallSubArray(0, i) - xAdd
        arrSmallSubArray(1, i) = arrSmallSubArray(1, i) - yAdd
    Next
    Note the highlighted interior With block. That should make the interior loop as fast or faster than the method of assigning the values to local variables, which will help keep the number of local variables down to a manageable level.

    EDIT: I'm waffling. While I stand by the code in this post, I think si's technique may help if applied to just the arrSmallSubArray values. By how much I can't even guess.

  32. #32

    Thread Starter
    Hyperactive Member Krass's Avatar
    Join Date
    Aug 2000
    Location
    Montreal
    Posts
    489

    Re: Array optimization - String or Integer?

    Hello. I was more than happy to benchmark some of your solutions, and here are the results (in seconds - this was done over a small set of records - of course using exactly the same for all tests, executed 3 times each):

    Exactly as I first posted it : 29, 29, 29
    Exactly as I first posted it (no -1 in do) : 29, 29, 29
    After Ellis's post 28 (without "with") : 29, 28, 29
    After Ellis's post 28 (with "with") : 25, 26, 26
    After geek's post 29 (without variable - using 2 sgn calls) : 26, 25, 26
    I am about to test the code using variable instead. My tests stops are post #29.

    Si_the_geek: "=" won't be the most regular occurence... Those < and > operators are used a lot to move my pointer in the arrays UNTIL they are "=".

    And also I was wondering if I should use the SELECT count(*) instead of using .movelast/.movefirst. Because after all, I need all the populated info in the recordset and loop it, so using count(*) would mean populating ANOTHER recordset just to know the recordcount.

    You guys are really into it. Devoted help - I like.
    Chris

  33. #33
    Super Moderator si_the_geek's Avatar
    Join Date
    Jul 2002
    Location
    Bristol, UK
    Posts
    41,974

    Re: Array optimization - String or Integer?

    Fair point on the sgn etc Ellis.. but your test was biased, as you only compared to one outcome rather than two, and there weren't array/property accesses on the cases either.

    Of course, the effectiveness of my method would depend on the actual data in use - and if there is a preference towards the first outcome then the extra function and subtraction (which I admittedly didn't account for fully) will make it slower.


    It's all academic tho, as your latest version using the extra variables eliminates the problem that the method was trying to solve!

  34. #34
    PowerPoster Ellis Dee's Avatar
    Join Date
    Mar 2007
    Location
    New England
    Posts
    3,530

    Re: Array optimization - String or Integer?

    Quote Originally Posted by si_the_geek
    Fair point on the sgn etc Ellis.. but your test was biased, as you only compared to one outcome rather than two, and there weren't array/property accesses on the cases either.
    Conceded.
    Quote Originally Posted by Krass
    Hello. I was more than happy to benchmark some of your solutions, and here are the results (in seconds - this was done over a small set of records - of course using exactly the same for all tests, executed 3 times each):
    Compiled exe, right? IDE rsults aren't meaningful...

    As you may have guessed, I (and several others on the boards) enjoy optimizing code for speed, so if there are other sections to your processing loop, I'd be happy to take a look at the whole routine.

  35. #35

    Thread Starter
    Hyperactive Member Krass's Avatar
    Join Date
    Aug 2000
    Location
    Montreal
    Posts
    489

    Re: Array optimization - String or Integer?

    No that was not on compiled exe. Only by executing it. Shouldn't that be meaningful if they were ALL tried that way? (conceded it may in fact run faster after compilation)...

    Strangely enough, using the same code (from my last test - 26, 25, 26) with an "interior with" have dropped me back to 29, 30, 29. (still using sgn)

    Based on those tests, the 2 sgn calls seems to give the same speed as not using them. I guess I can just use them anyway?..

    What seemed to really give a performance boost was the first global "with", without "interior with", clocking at "25, 25, 26"....

    I still havn't tested using a variable at any point (except for those already in my first post, of course)
    Chris

  36. #36
    Super Moderator si_the_geek's Avatar
    Join Date
    Jul 2002
    Location
    Bristol, UK
    Posts
    41,974

    Re: Array optimization - String or Integer?

    Testing speed in the IDE is virtually meaningless I'm afraid - code not only runs slower, but also in a different way completely.

    In the past I have seen two similar pieces of code that were compared, one of them was about twice as fast as the other in the IDE, but then several times slower than it when compiled!

  37. #37
    PowerPoster Ellis Dee's Avatar
    Join Date
    Mar 2007
    Location
    New England
    Posts
    3,530

    Re: Array optimization - String or Integer?

    Quote Originally Posted by Krass
    No that was not on compiled exe. Only by executing it. Shouldn't that be meaningful if they were ALL tried that way? (conceded it may in fact run faster after compilation)...
    No, the IDE will be slower on some things but not others. IDE results have no predictive value on compiled speed when comparing different methods.

    If you were comparing the same method with different data, the relative speeds in the IDE may give you rough idea, but even then the ratios will be all wrong. (28, 26 and 30 show much less variation than 7, 5, 6, for example.)

  38. #38

    Thread Starter
    Hyperactive Member Krass's Avatar
    Join Date
    Aug 2000
    Location
    Montreal
    Posts
    489

    Re: Array optimization - String or Integer?

    That thread will have learned me a couple of things.

    I think I'll be short on time today but hopefully I'll be able to re-do those timechecks with compiled IDE soon. And will post the results.

    I actually became very curious as to how it will differ!..

    I guess the compiled version will show a difference between using sgn calls or not. In IDE, it changed absolutely nothing.

    Also, that "interior with" was bad, adding an average of 5 seconds to the process. Do you think it has chances of improving when compiled? Only one way to know, I guess!
    Chris

  39. #39
    PowerPoster Ellis Dee's Avatar
    Join Date
    Mar 2007
    Location
    New England
    Posts
    3,530

    Re: Array optimization - String or Integer?

    Quote Originally Posted by Krass
    Also, that "interior with" was bad, adding an average of 5 seconds to the process. Do you think it has chances of improving when compiled?
    Almost certainly.

  40. #40

    Thread Starter
    Hyperactive Member Krass's Avatar
    Join Date
    Aug 2000
    Location
    Montreal
    Posts
    489

    Re: Array optimization - String or Integer?

    I was able to re-do those tests with compiled version and here are the results:

    Note that I still didn't even try to use more variables than there was in my original post. I guess that would be the next test.

    Test#1: Exactly as I first posted it : 14, 14, 13
    Test#2: Exactly as I first posted it (no -1 in do) : 14, 14, 14
    Test#3: After Ellis's post 28 (without "with") : 13, 13, 13
    Test#4: After Ellis's post 28 (with "with") : 13, 12, 13
    Test#5: After geek's post 29 (without variable - using 2 sgn calls) : 13, 12, 12
    Test#6: Added interior with : 14, 14, 13
    ...Looks to me that the best solutions is to use those sgn calls and avoid the "interior with" (Test #5).

    I am reposting what the code now looks like:
    Code:
    Do While xSmall < intSmallUBound And xHuge < .Length ' removing the two subtractions should help a bit
        Select Case Sgn((arrSmallSubArray(0, xSmall) + xAdd) - (.Coords(xHuge).x))
            Case 1: xHuge = xHuge + 1
            Case -1: xSmall = xSmall + 1
            Case Else
                Select Case Sgn((arrSmallSubArray(1, xSmall) + yAdd) - (.Coords(xHuge).y))
                    Case 1: xHuge = xHuge + 1
                    Case -1: xSmall = xSmall + 1
                    Case Else
                        xSmall = xSmall + 1
                        xHuge = xHuge + 1
                        MatchCount = MatchCount + 1
                End Select
        End Select
    Loop
    That looks good, doesn't it?
    Chris

Page 1 of 2 12 LastLast

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