Hiya,
I'm the author of a website called "VB Fibre". This website showed how to increase your performance by simple changes in VB programs.
Unfortunatly the website is down, since the provider (DigitalRice.com) is undergoing heavy changes.
Therefore, I'm now copying all my website content to one big HTML file.
It has graphs and tables showing you the performance.

Everything has been tested on my AMD 500, 128MB RAM, Windows2K.
The QueryPerFormancecounter API call has been used to get the duration of every call, since other methods (Like Timer, GetTickCount) are just not precise enough for this stuff.

If I update my website when it comes online, I'll (probably) update this article too. (I have to add the new articles to a database, and currently I do not have anything installed that could do that for me...)

I hope you enjoy reading it! Please vote if you like it (I'm sure you do =-)
(Best viewed with IE5 @ 1024x768, because of some un-orthodox solved table problems :-)

Note: My site has been online and contains MANY new optimizations, not found here. Please check it out at http://vbfibre.digitalrice.com
(every now and then it says something about an "RPC" server..just refresh!)

Strings

 

StrComp vs 'String1=String2' [5/2/2001]

StrComp() is 100+% faster than using Ucase, for capital unsensitive strings. I actually never knew that strComp() existed. But I think I'm going to try to implent it now where possible. This test was based on the standard method: 500.000 iterations, 5 times.

Used Code:
Public Sub TestOne()
 Dim strTest1 As String, strTest2 As String
 strTest1 = UCase$("all j00r b453 r b3l0nG 70 U5")
 strTest2 = UCase$("ALL J00r base R Bel0NG 70 U5")
 If strTest1 = strTest2 Then
 End If
End Sub

Public Sub TestTwo()>BR?  Dim strTest1 As String, strTest2 As String
 strTest1 = "all j00r b453 r b3l0nG 70 U5"
 strTest2 = "ALL J00r base R Bel0NG 70 U5"
 If StrComp(strTest1$, strTest2$, vbTextCompare) = 0 Then
 End If
End Sub

2,641376
0
2,491938 1,224882 2,549374 1,219513 2,536725 1,222509 2,532701 1,246868 2,641376 1,231344

Blue=UCase$ Red=Text compare
The lower the better

Text compare % faster than UCase$ Text compare (sec) UCase$ (sec)
103,4% 1,224882 2,491938
109% 1,219513 2,549374
107,5% 1,222509 2,536725
103,1% 1,246868 2,532701
114,5% 1,231344 2,641376






 


$ Saves you…time [5/2/2001]

So much effect for so little change of code. These are only the statistics of the "Left" function, but I've also done some tests using "Ucase", "Lcase" and "Trim". All these functions are much faster using the "$" sign after the function. This happens for a simple reason: The functions return a variant without the $ sign. And variants are very slow, you should never use them.

Code Used:
Public Sub TestOne()
 Dim strReturn As String
 strReturn = Left("This is a test", 4)
End Sub

Public Sub TestTwo()
 Dim strReturn As String
 strReturn = Left$("This is a test", 4)
End Sub

0,704659
0
0,665861 0,268978 0,658749 0,268580 0,658076 0,264406 0,704659 0,269836 0,647323 0,267963

Blue=Without $ Red=With $
The lower the better

With $ % faster than Without $ With $ (sec) Without $ (sec)
147,6% 0,268978 0,665861
145,3% 0,268580 0,658749
148,9% 0,264406 0,658076
161,1% 0,269836 0,704659
141,6% 0,267963 0,647323









Math

 

Use "X \ 1" instead of "Cint(x)" [5/2/2001]

"X \ 1" is a lot faster, and the end result is the same. The speed increase is actually more than I would have expected. But as with many other optimizations, this test has been done with 500.000 iterations. So for small loops you might not notice it.

Code used:
Public Sub TestOne()
 Dim lngReturn As Long
 lngReturn = CInt(100.543253)
End Sub

Public Sub TestTwo()
 Dim lngReturn As Long
 lngReturn = 100.543253 \ 1
End Sub

0,035031
0
0,035031 0,024938 0,027812 0,023638 0,026613 0,023351 0,034486 0,023985 0,026673 0,024821

Blue=CInt(x) Red=x \ 1
The lower the better

x \ 1 % faster than CInt(x) x \ 1 (sec) CInt(x) (sec)
40,5% 0,024938 0,035031
17,7% 0,023638 0,027812
14% 0,023351 0,026613
43,8% 0,023985 0,034486
7,5% 0,024821 0,026673







 


Always use "\" instead of "/" [5/1/2001]

Major performance gain here! For integer calculations you should always use "\" instead of "/" Using "\" is faster because f you divide by "/" the values will first be converted to singles. So for Sin/Cos/Tan operation you should still use "/" if you want to have precision. code used:

Public Sub TestOne()
 Dim intResult As Integer
 intResult = 100 / 50
End Sub

Public Sub TestTwo()
 Dim intResult As Integer
 intResult = 100 \ 50
End Sub

0,050495
0
0,045475 0,007018 0,046955 0,007027 0,046190 0,007114 0,050495 0,007328 0,045453 0,008064

Blue=100 / 50 Red=100 \ 50
The lower the better

100 \ 50 % faster than 100 / 50 100 \ 50 (sec) 100 / 50 (sec)
548% 0,007018 0,045475
568,2% 0,007027 0,046955
549,3% 0,007114 0,046190
589% 0,007328 0,050495
463,6% 0,008064 0,045453







 


Use "x * x" instead of "x ^ 2" [4/30/2001]

You can use "x * x" instead of "x ^ 2". The end result will be the same. Well, I think the statistics prove themself, it's definetly worth to change your code to the optimized method! But As you can see the time for the calculations is very low anyways. Not even a second for 500.000 iterations Maybe with very large iterations you might notice it. Still I recommend to change the code since we want to have our programs running at the maximal speed possible, don't we? I'm not sure but maybe for larger quadratic calculations the routine might become faster. For example "x ^ 5" can also be done using "x * x * x * x * x"

Public Sub TestOne()
 Dim dblResult As Double
 dblResult = 4 ^ 2
End Sub

Public Sub TestTwo()
 Dim dblResult As Double
 dblResult = 4 * 4
End Sub

0,623485
0
0,623485 0,007162 0,609830 0,007151 0,610351 0,013844 0,609783 0,007201 0,608305 0,007018

Blue=x^2 Red=x*x
The lower the better

x*x % faster than x^2 x*x (sec) x^2 (sec)
8606% 0,007162 0,623485
8427,3% 0,007151 0,609830
4308,6% 0,013844 0,610351
8368,1% 0,007201 0,609783
8567,5% 0,007018 0,608305









General

 

Always remove "Debug.Print" [5/3/2001]

Well, the results speak for themself. Always remove "Debug.Print" in final compilations. The speed increase is easy to explain: VB will still call the function, even if it's a Debug.Print in a compiled exe. Standard test:500.000 iterations, and that 5 times.

Used Code:
Public Sub TestOne()
 Debug.Print CallTestFunction
End Sub

Public Sub TestTwo()
 'debug.print CallTestFunction 'commented out
End Sub

Public Function CallTestFunction() As Byte
 CallTestFunction = CByte(10 + 20 / 3 * 5)
End Function

0,047021
0
0,046117 0,007114 0,045286 0,007103 0,045348 0,007239 0,047021 0,007132 0,045459 0,007018

Blue=Debug Red=No debug
The lower the better

No debug % faster than Debug No debug (sec) Debug (sec)
548,3% 0,007114 0,046117
537,6% 0,007103 0,045286
526,4% 0,007239 0,045348
559,3% 0,007132 0,047021
547,7% 0,007018 0,045459







 


Arrays: Temporary variables [5/2/2001]

Well no doubt about it. Temporary variables are going to speed up your program. I have to say that I had to wait longer than expect to complete this routine. Anyway, if you're often pointing to an array, you've definetly got to use temporary values. Check the source code for an example. Note that I've done the test 5 times, but there was only 1 main iteration, cause the For...Next loops where long enough. Also note that in the first test without the temporary variable, I didn't declare the "lngTemp" variable. We didn't use it there, so no extra variable declaration.

Used code: Public Sub TestOne()
 Dim I As Long, J As Long
 Dim myArray(1 To 50000) As Long

 For I = 1 To 50000
  For J = I + 1 To 50000
   If myArray(I) = myArray(J) Then
   End If
  Next
 Next
 Erase myArray
End Sub

Public Sub TestTwo()
 Dim I As Long, J As Long
 Dim myArray(1 To 50000) As Long
 Dim lngTmp As Long

 For I = 1 To 50000
  lngTmp = myArray(I)
  For J = I + 1 To 50000
   If lngTmp = myArray(J) Then
   End If
  Next
 Next
 Erase myArray
End Sub

23,946439
0
23,928901 15,979177 23,919381 15,963122 23,946439 16,122013 23,893372 16,103921 23,896261 16,050374

Blue=No temp var Red=Temp var
The lower the better

Temp var % faster than No temp var Temp var (sec) No temp var (sec)
49,8% 15,979177 23,928901
49,8% 15,963122 23,919381
48,5% 16,122013 23,946439
48,4% 16,103921 23,893372
48,9% 16,050374 23,896261







 


For…Each vs. For...Next [5/2/2001]

Using For...Next in arrays is a lot faster than For...Each. I'm not sure why this is caused, but probably also because you've got to use a variant as loop index for the "For...Each". And any serious programmer doesn't use a variant in his/her applications. I've used Lbound() and Ubound() in the For...Next loop, cause we do not have to worry about those two values, like in For...Each. No 500.000 iterations this time. I've done 1 iteration, the array was large enough to be precise enough. The test has been done 5 times though.

Used Code:
Public Sub TestOne()
 Dim MyArray(1 To 100000)
 Dim I As Variant

 For Each I In MyArray
  Next
End Sub

Public Sub TestTwo()
 Dim MyArray(1 To 100000)
 Dim I As Long

 For I = LBound(MyArray) To UBound(MyArray)
 Next
End Sub

0,070230
0
0,070230 0,041363 0,062214 0,044772 0,062389 0,041175 0,062814 0,047993 0,061905 0,040924

Blue=For...Each Red=For...Next
The lower the better

For...Next % faster than For...Each For...Next (sec) For...Each (sec)
% faster 69,8% 0,041363 0,070230
39% 0,044772 0,062214
51,5% 0,041175 0,062389
30,9% 0,047993 0,062814
51,3% 0,040924 0,061905







 


For…Next: Always use longs [5/2/2001]

Never use anything else than longs in loops. Longs are the fastest variable type in Visual Basic. It's easy to explain why: They are 32bit, your processor is 32 bit, and every other type that isn't 32 bit needs to be converted to 32 bit (which takes time). Okay, now I could have used integers for this test. Integers are slower than longs, but just running an test between a long and integer, without anything between For...Next, will not really matter. But in larger loops, you'll always see that the Long variable type will win in performance.

So that's why I decided to use a single. And you can see the difference between it, definetly. I might add that I haven't used the normal test system for this test: 1 iteration, done 5 times. But the long and single test both contained 100000 iterations, so it should be all right.

Code used:
Public Sub TestOne()
  Dim I As Single
  For I = 0 To 100000
  Next I
End Sub

Public Sub TestTwo()
 Dim I As Long
 For I = 0 To 100000
 Next I
End Sub

0,004279
0
0,004279 0,000405 0,003412 0,000406 0,003412 0,000406 0,003433 0,000405 0,003413 0,000406

Blue=Single Red=Long
The lower the better

Long % faster than Single Long (sec) Single (sec)
957,1% 0,000405 0,004279
741,1% 0,000406 0,003412
741,1% 0,000406 0,003412
748% 0,000405 0,003433
741,3% 0,000406 0,003413







 


'With' vs.' No With' [5/2/2001]

The results of this test are very irregular. Sometimes "With" wins and some "No with" wins. I've done this test 10 times, but everytime the same results... I'm not sure why this happens. I always thought that "With" would be (much) faster anyway. It could be the form I've used for this test, but it's highly unlikely. For this test I've done 5000 iterations, and done the test 5 times. Changing properties take so much time in VB. I have limitted the form calls to properties that are not graphical depending on something.

Used code:
Public Sub TestOne()
 frmTest.Caption = "test"
 frmTest.Enabled = True
 frmTest.CurrentX = 10
 frmTest.ScaleMode = vbPixels
 frmTest.Tag = "test"
 frmTest.Tag = "test1"
 frmTest.Tag = "test2"
 frmTest.Tag = "test3"
 frmTest.Tag = "test4"
End Sub

Public Sub TestTwo()
 With frmTest
  .Caption = "test"
  .Enabled = True
  .CurrentX = 10
  .ScaleMode = vbPixels
  .Tag = "test"
  .Tag = "test1"
  .Tag = "test2"
  .Tag = "test3"
  .Tag = "test4"
 End With
End Sub

0,532967
0
0,498539 0,498938 0,496477 0,492082 0,492939 0,498628 0,487473 0,499922 0,532967 0,490634

Blue='No With' Red='With'
The lower the better

'With' % faster than 'No With' 'With' (sec) 'No With' (sec)
-0,1% 0,498938 0,498539
0,9% 0,492082 0,496477
-1,1% 0,498628 0,492939
-2,5% 0,499922 0,487473
8,6% 0,490634 0,532967









Memory

 

Static vs. Public variables [5/3/2001]

Sometimes I use Static variables, but I think I'm going for public now. Not that it really matters that much, but any performance increase is welcome for me. I've used the standard method for this test: 500.000 iterations, 5 times.

Used Code:
Declaration section: Private Var1 As Long

Public Sub TestOne()
 Static Var2 As Long
 Var2 = Var2 + 1
End Sub

Public Sub TestTwo()
 Var1 = Var1 + 1
End Sub

0,009499
0
0,009235 0,008050 0,009499 0,007136 0,008341 0,007291 0,008427 0,007508 0,008130 0,008218

Blue=Static Red=Public var
The lower the better

Public var % faster than Static Public var (sec) Static (sec)
14,7% 0,008050 0,009235
33,1% 0,007136 0,009499
14,4% 0,007291 0,008341
12,2% 0,007508 0,008427
-1,1% 0,008218 0,008130









Methods

 

Use Byref or Byval? [5/2/2001]

ByRef arguments are 1/3 faster than Byval. If you do not explcitly declare arguments as Byval or Byref, VB will use ByRef as default. So if you never specify ByVal, there won't be any speed gain for you here. Except that you can specify ByRef explicit (see other VB Fibre article)

Code used:
Public Sub TestOne(ByVal lngValue1 As Long, ByVal strString1 As String, ByVal bByte1 As Byte)
 'empty
End Sub

Public Sub TestTwo(ByRef ngValue1 As Long, ByRef strString1 As String, ByRef bByte1 As Byte)
 'empty
End Sub

0,264883
0
0,257264 0,201177 0,264654 0,198650 0,257305 0,200032 0,264883 0,197073 0,261864 0,198252

Blue=With ByVal Red=With ByRef
The lower the better

With ByRef % faster than With ByVal With ByRef (sec) With ByVal (sec)
27,9% 0,201177 0,257264
33,2% 0,198650 0,264654
28,6% 0,200032 0,257305
34,4% 0,197073 0,264883
32,1% 0,198252 0,261864







 


Specify ByRef explictly [5/2/2001]

A very little speed increase. I expected a larger increase... Anyway, it's always better to declare arguments byval or byref explicitly. You can then see how values are passed, and see if it returns anything directly. I'm not sure if it's worthy to change all your subs and functions to Byref, because the speed increase ain't that much.

Code used:
Public Sub TestOne(lngValue1 As Long, strString1 As String, bByte1 As Byte)
 'empty
End Sub

Public Sub TestTwo(ByRef ngValue1 As Long, ByRef strString1 As String, ByRef bByte1 As Byte)
 'empty
End Sub

0,196016
0
0,196016 0,191442 0,193253 0,191196 0,193553 0,189785 0,192911 0,191511 0,192012 0,190801

Blue=Without Byref Red=With Byref
The lower the better

With Byref % faster than Without Byref With Byref (sec) Without Byref (sec)
2,4% 0,191442 0,196016
1,1% 0,191196 0,193253
2% 0,189785 0,193553
0,7% 0,191511 0,192911
0,6% 0,190801 0,192012







 


To call or not to call? [5/1/2001]

The difference between call or no call is very small. The funny thing is that there's a difference if you call a sub or a function. That's why I'm probably going to add another test to check if "no call" is faster for subs. The results of this test are based on a function, the function returns a string.

Public Function TestOne() As String
 TestOne = "empty"
End Function

This was function was called 500.000 times using "Call Testone" and "Testone", and done 5 times

0,267618
0
0,261654 0,267618 0,256037 0,256384 0,259373 0,256454 0,260969 0,255651 0,258496 0,259254

Blue=call Red=no call
The lower the better

no call % faster than call no call (sec) call (sec)
-2,2% 0,267618 0,261654
-0,1% 0,256384 0,256037
1,1% 0,256454 0,259373
2,1% 0,255651 0,260969
-0,3% 0,259254 0,258496









That were all the optimization tricks I've got so far... Glad you kept reading till the end. Hope you enjoyed it!
Almar Joling
Programmer QuadrantWars
Author of VB Fibre (Down at the moment)