Results 1 to 2 of 2

Thread: Classic VB - How do I optimize my code?

  1. #1

    Thread Starter
    VB6, XHTML & CSS hobbyist Merri's Avatar
    Join Date
    Oct 2002
    Location
    Finland
    Posts
    6,654

    Classic VB - How do I optimize my code?

    This question is very large as a lot of it depends on the situatation. However, it is good to begin with some facts about the VB6 and how it works.

    Beginner phase

    VB6 does a lot for you automatically. You don't need to think about the "hidden" background stuff, such as memory allocation, datatype conversions and coercion and so on, unless you want to. If you want to make your code efficient and fast, you need to know about the background stuff and how to let you have more control of the things that happen. Many have the image that VB6 is really slow, when they really haven't ever tried to code in the "traditional" way with it. For example, many C/C++ coders tend to use the "easy" VB style of coding and forget completely about what they know of speed and efficiency from the C/C++ world.


    Variants

    By default, all variables are declared as variants unless you explicitly define a different datatype. Variants are very handy and easy to use as you can do almost anything to them and they still work, but there are times when they don't work as expected. And from optimization point of view, variants are very, very slow. This is why you should always use the correct datatype.

    Below is a common mistake related to variants in VB6:
    VB Code:
    1. ' the wrong way:
    2. Dim A, B C As Long
    3. ' only C is declared as long, A and B are variants
    4.  
    5. ' the correct way:
    6. Dim A As Long, B As Long, C As Long
    7. ' this behavior has been changed in VB.NET

    Long story short: avoid using variants unless you really need them. And you rarely do.


    Strings

    Strings in Visual Basic are easy to handle as well. VB does a lot for you to make your life easier, but this makes strings slow as a lot of automatical processing is done in the background code. If you need to handle a lot of data, consider using an array instead. Without using any API, you can use byte arrays to convert back and forth between a string and an array:

    VB Code:
    1. Dim barTemp() As Byte, strTemp As String
    2. ' set something to the string
    3. strTemp = "I am funny."
    4. ' copy string contents to a byte array
    5. barTemp = strTemp
    6. ' show some interesting stuff in the immediate window
    7. Debug.Print "First byte:" & barTemp(0)
    8. Debug.Print "Second byte: " & barTemp(1)
    9. Debug.Print "Third byte: " & barTemp(2)
    10. Debug.Print "Lower bound: " & LBound(barTemp) & ", upper bound: " & UBound(barTemp)
    11. ' (if you do not understand how Debug.Print works, replace Debug.Print with MsgBox)
    12. ' (or View > Immediate Window to make the Debug visible)
    13.  
    14. ' convert byte array to string:
    15. strTemp = CStr(barTemp)

    As you see from the example above, there is an interesting fact behind the strings: each character is actually two bytes long! However, when you read a file using Input and Output, or pass a string to API, the strings are automatically converted back to ANSI. Thus if you're handling Unicode, you want to use a byte array or an integer array.


    Datatype coercion

    As told before, VB does a lot of automatical stuff for you. One of these features is datatype coercion: VB automatically changes datatype to appropriate one if you pass a wrong datatype. It doesn't allow this everywhere (as with custom built procedures), but it is a problem never-the-less. Whenever possible, to gain the most speed, you should use the appropriate datatype against another similar datatype. If you need to compare or use different datatypes together, you can (and should) use the inbuilt conversion routines:

    CBool, CByte, CInt, CLng, CCur, CSng, CDbl, CStr

    There are more, but these are what you probably need the most. On some cases, coercion can cause unexpected errors, such as when numbers in string format are combined, they add up in a string form and not as numbers (ie. 1 + 2 = 12 and not 3). This is a problem with variants as well.

    To help you use the correct datatypes and avoid many bugs and problems related to datatypes and coercion, use Option Explicit in the beginning of each form, module etc. You can make this automatical by ticking Tools > Options... > Require Variable Declaration. This will make sure you have Option Explicit in any new code element you add to your project. You have to add Option Explicit manually to any existing


    Arrays

    There isn't much to actually optimize in the arrays, but it is very important that you check for the bounds of the arrays when you use them. This allows you to use Advanced Optimizations. And due to popular unknowledge, this is how you can check if a variable size array is declared or not:

    VB Code:
    1. Dim barTemp() As Byte
    2.  
    3. If (Not barTemp) = True Then MsgBox "The array is empty!"
    4. If Not ((Not barTemp) = True) Then MsgBox "The array contains something!"

    Another important note about arrays is that they work remarkably faster when the code is compiled and even more so if you enable Advanced Optimizations.


    One imporant side note about arrays: one dimensional arrays are way faster than multidimendional arrays. So if you need speed, you better use a one dimensional array. Also, zero based arrays are faster than one based arrays. You should never use Option Base 1 unless you have a very good reason for it.


    Advanced Optimizations

    These are compilation options that affect the compiled code. By enabling these options (actually you are ripping off features), you can speed up your compiled code a whole lot. This requires, however, you to avoid the use of "easy" coding style VB provides. Many aspects of compiled VB code speed up close or equal to their C/C++ version of the code. VB6 compiler is actually a hacked C compiler. Please note that VB6 compiler can't of course compete with more advanced highly optimized compilers, but you do get most stuff done just as fast as you need it to.

    To use the advanced optimizations, see Project > (Project name) Properties... > Compile, Advanced Optimizations...

    A note about the other compile options: Favor Pentium Pro makes no difference in modern processors. The effect to speed is near to zero. It may actually slow down your code. However, you can't really see any difference be it ticked or not.


    After the beginner phase: General optimizations

    Advancing to the next level and getting to the general optimization stuff that isn't only VB related. The same things can apply to other languages as well.

    About the IDE

    One of the important things to note about is that when you are testing the speed of your code, you better compare the compiled code. P-Code is very different to compiled code and thus doing speed testing in the IDE is not worth of anything. P-Code code is faster when there is less commands to process, but compiled code can be much faster even when the amount of code increases. Basic math is also much faster when it is compiled, thus a complex mathematical algorithm can be really slow in the IDE, but very fast when compiled.


    What to optimize?

    You don't need to optimize everything. You don't need to optimize showing of a message box; you rarely need to optimize anything that relates to showing information to the user. What you should optimize is the heavy stuff that works in the background and stuff that are used often. For example, if you draw a custom mouse pointer in the game, you better do it as fast as possible, because it can dramatically effect to the Frames Per Second you can get: you have to draw the mouse pointer to each frame, so if it is slow to draw the mouse pointer, it does affect the overall speed of the end result.

    For heavy stuff example, a processing of a 100 MB file should be optimized. What to consider? First of all, the amount of available RAM is important. Most computers have 256 to 1 GB of memory. You should always note the lower end and optimize so that your code works faster on the lower end computer. Thus you shouldn't read the complete file at once, but a small piece at a time and then process that.


    Is API a solution?

    Yes and no. If API allows you to handle a lot of data at once or makes it possible to do it using regular code, then the answer is yes. If it makes something that is complex to do using regular code, the answer is yes (for example, converting character codepage to another).

    The answer is no if you have to call the API a lot. The classic example could be SetPixel: setting a single pixel using an API call, which has an overhead by calling a lot of stuff to set a single pixel, is nothing but slow. This function is only faster than PSet only because PSet has VB runtime overhead included in it: it actually calls the very same SetPixel.

    API isn't a complete magical wand that does everything for you and fast. You should use API sparingly and only when there is no other way or it isn't worth reinventing a wheel. Calling API often is slow due to some overhead required for the call, so you shouldn't use it for small stuff.

    Interesting fact about CopyMemory aka RtlMoveMemory: it is faster when compared to array handling when you are copying data forward. However, if you are copying data "backwards" in memory, moving it using VB code is slightly faster. Anyone is welcome to prove me wrong, this was the last result after thinking and testing it over a few weeks ago.


    Comments and feedback

    Send me a private message, this is a FAQ section so you would only get your message deleted. I didn't cover everything here as I wrote this all only off my head without peeking any other sources, so I'll probably write more stuff when I get into it again.


    Updates
    First update:
    - additional information about one dimensional arrays and Option Base
    - the order of your code (in a reply)
    - the math (in a reply)
    Last edited by Merri; Oct 13th, 2005 at 06:37 PM.

  2. #2

    Thread Starter
    VB6, XHTML & CSS hobbyist Merri's Avatar
    Join Date
    Oct 2002
    Location
    Finland
    Posts
    6,654

    Re: Classic VB - How do I optimize my code?

    As everything doesn't fit in the first post

    I don't see a point posting more threads as this is all basically still the same stuff. Thus here we go again:


    The order of your code

    One thing that is often left unnoticed are the loops inside loops. There are cases when a lot of calculation is done unnecessarily many times within a loop. It is important to do any calculation that can be done outside a loop before the loop. There is no point calculating the same thing many times within the loop. Thus: check out your loops and see if you have calculations that could be done in advance.


    The math

    Math works as fast in VB6 as it does in any other programming language. VB does lack some important features, such as bitshifting, that can be used to speed up code as bitshifting for one is a very lightweight process. As a general rule, it is wise to use a lightweight counterpart if possible.

    One of the sillier codes I've seen often is as follows:
    VB Code:
    1. Variable = Int(Number / 5)
    A lot of unrequired datatype coercion happens here as division is done in floating point mode. A simple and faster method is to use backslash:
    VB Code:
    1. Variable = Number \ 5
    It gives exactly the same result, though often about two-three times faster. If you don't require decimals to a Single or Double or Currency variable, use the backslash to divide.

    For other things, adding up is faster than multiplication. Yet another often seen calculation:
    VB Code:
    1. Variable = Variable * 2
    While this works faster and gives the exact same result:
    VB Code:
    1. Variable = Variable + Variable

    You can even think about this within loops:
    VB Code:
    1. Dim lngX As Long, lngY As Long, lngXY As Long
    2. For lngY = 0 To 99999
    3.     For lngX = 0 To 9999
    4.         Array(lngXY + lngX) = Calculation
    5.     Next lngX
    6.     lngXY = lngXY + lngX
    7. Next lngY
    There are two small and important things: a temporary variable, lngXY, is used to lessen the amount of calculation. Often more variables are required to optimize for speed and this is one of the most common ways to do it. The use of lngXY replaces the following code (again, seen too often):
    VB Code:
    1. Array(lngY * 10000 + lngX) = Calculation
    Needless to say: you're saving 10000 multiplications by using an extra variable.

    The another thing that requires attention is the value of lngX after the loop: it is indeed 10000 after the For...Next loop has passed. Thus you can use this to save the trouble of figuring out where the number 10000 is coming of again as you can remember a general rule about the result of the For ... Next loop.
    Last edited by si_the_geek; Oct 13th, 2005 at 07:31 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