Use this code to create a class called HiResTimer:
'The number is codified as HighPart*2^32+LowPartPrivate Type LARGE_INTEGER LowPart As Long HighPart As LongEnd TypePrivate Declare Function QueryPerformanceCounter Lib _ "kernel32" (lpPerformanceCount As LARGE_INTEGER) _ As LongPrivate Declare Function QueryPerformanceFrequency Lib _ "kernel32" (lpFrequency As LARGE_INTEGER) As LongPrivate m_TicksPerSecond As DoublePrivate m_LI0 As LARGE_INTEGERPrivate m_LI1 As LARGE_INTEGERFriend Sub Class_Initialize() Dim LI As LARGE_INTEGER If QueryPerformanceFrequency(LI) <> 0 Then m_TicksPerSecond = LI2Double(LI) Else m_TicksPerSecond = -1 End IfEnd SubFriend Property Get Resolution() As Double Resolution = 1# / m_TicksPerSecondEnd PropertyFriend Sub EnterBlock() QueryPerformanceCounter m_LI0End SubFriend Sub ExitBlock() QueryPerformanceCounter m_LI1End SubFriend Property Get ElapsedTime() As Double Dim EnterTime As Double, ExitTime As Double EnterTime = LI2Double(m_LI0) / m_TicksPerSecond ExitTime = LI2Double(m_LI1) / m_TicksPerSecond ElapsedTime = ExitTime - EnterTimeEnd PropertyFriend Function LI2Double(LI As LARGE_INTEGER) As Double Dim Low As Double Const TWO_32 = 4# * 1024# * 1024# * 1024# Low = LI.LowPart If Low < 0 Then Low = Low + TWO_32 'Now Low is in the range 0...2^32-1 LI2Double = LI.HighPart * TWO_32 + LowEnd Function
Here's an example of the HiResTimer in use:
Dim hrt As HiResTimer, d As DoubleSet hrt = New HiResTimerDebug.Assert hrt.Resolution > 0MsgBox "Resolution [usecs]:" & hrt.Resolution * 1000000#hrt.EnterBlockhrt.ExitBlockMsgBox "Call overhead [usecs]:" & hrt.ElapsedTime * _ 1000000#hrt.EnterBlockd = 355# / 113#hrt.ExitBlockMsgBox "Elapsed Time [usecs]:" & hrt.ElapsedTime * _ 1000000#
Believe it or not, you can time even native-compiled code division. For more information, look at the MSDN Library description of the kernel APIs used here. On x86 architectures, resolution is better that 1 microsecond. Be careful, however, of trusting single instance timings, as you'll find the "resolution" of this performance counter varies over time. In fact, the overhead of simply calling QueryPerformanceCounter in VB is quite a measurable time period itself.
Although you can time single operations, you're still better off averaging the time required for hundreds or thousands of similar operations.