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!)
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 SubPublic 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
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 SubPublic Sub TestTwo()
Dim strReturn As String
strReturn = Left$("This is a test", 4)
End Sub
0,704659 0
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 SubPublic Sub TestTwo()
Dim lngReturn As Long
lngReturn = 100.543253 \ 1
End Sub
0,035031 0
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 SubPublic Sub TestTwo()
Dim intResult As Integer
intResult = 100 \ 50
End Sub
0,050495 0
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 SubPublic Sub TestTwo()
Dim dblResult As Double
dblResult = 4 * 4
End Sub
0,623485 0
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 SubPublic Sub TestTwo()
'debug.print CallTestFunction 'commented out
End SubPublic Function CallTestFunction() As Byte
CallTestFunction = CByte(10 + 20 / 3 * 5)
End Function
0,047021 0
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 LongFor I = 1 To 50000
For J = I + 1 To 50000
If myArray(I) = myArray(J) Then
End If
Next
Next
Erase myArray
End SubPublic Sub TestTwo()
Dim I As Long, J As Long
Dim myArray(1 To 50000) As Long
Dim lngTmp As LongFor 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
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 VariantFor Each I In MyArray
Next
End SubPublic Sub TestTwo()
Dim MyArray(1 To 100000)
Dim I As LongFor I = LBound(MyArray) To UBound(MyArray)
Next
End Sub
0,070230 0
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 SubPublic Sub TestTwo()
Dim I As Long
For I = 0 To 100000
Next I
End Sub
0,004279 0
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 SubPublic 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
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 SubPublic Sub TestTwo()
Var1 = Var1 + 1
End Sub
0,009499 0
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 SubPublic Sub TestTwo(ByRef ngValue1 As Long, ByRef strString1 As String, ByRef bByte1 As Byte)
'empty
End Sub
0,264883 0
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 SubPublic Sub TestTwo(ByRef ngValue1 As Long, ByRef strString1 As String, ByRef bByte1 As Byte)
'empty
End Sub
0,196016 0
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
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)