Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations bkrike on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

Time in milliseconds

Status
Not open for further replies.

GlynA

Programmer
May 1, 2002
77
GB
I would like to be able to determine how long a process takes in milliseconds. The time functions in VB only appear to deal with times down to seconds. Are there API functions I can use to compare two times in milliseconds?
 
Yes, the GetTickCount API call should work well in this functionality.

Private Declare Function GetTickCount Lib "kernel32" () As Long

then in your routine

fLng_Start = GetTickCount
<The Code you Wish to Time>
fLng_End = GetTickCount

Elapsed Time is then (fLng_End - fLng_Start)

Good Luck
--------------
As a circle of light increases so does the circumference of darkness around it. - Albert Einstein


 
Hi,

The Timer Statement with return time in fractions of a second

dblStart = Timer
<code>
dblFinish = Timer
Print.Debug dblFinish - dblStart

Jon
 
The timer is much easier to work with and why write all that extra API.

The Timer() function also is based on the 1 clock tick which is equal to 55 milliseconds.
You just need to make sure you define your variables as doubles, as the above from Jon4747 applies, in order to get the correct decimal value returned.

The same with the Now() function. To get a fraction of a second using now()
Dim s As Double 'Start
Dim e As Double 'End
Dim i As Long

s=now
'<Some Code>
For i = 1 To 10000000
Next i
e=now
Debug.Print e-s

 
All that extra API code is the one line of function declaration.

I think it all boils down to the degree of precision. Running the following code:

For Index = 1 To 1000
TimerValue(Index) = Timer
TickValue(Index) = GetTickCount
Next Index

Set TimerChanges = New Collection
Set TickChanges = New Collection

TimerChanges.Add &quot;1:&quot; & TimerValue(1)
TickChanges.Add &quot;1:&quot; & TickValue(1)

For Index = 2 To 1000
If (TimerValue(Index) <> TimerValue(Index - 1)) Then
TimerChanges.Add Trim(Index) & &quot;:&quot; & TimerValue(Index)
End If
If (TickValue(Index) <> TickValue(Index - 1)) Then
TickChanges.Add Trim(Index) & &quot;:&quot; & TickValue(Index)
End If
Next Index


I then recorded when the result changed. The following chart show when the changes occurred for the first three runs.


Timer Changes Timer Changes Timer Changes
1:47080.81 1:47165.28 1:47203.13
197:47080.86 534:47165.34 475:47203.18
761:47080.92

Tick Changes Tick Changes Tick Changes
1:9852738 1:9937193 1:9975050
43:9852743 42:9937198 8:9975053
96:9852748 94:9937203 60:9975059
149:9852754 145:9937208 111:9975063
197:9852758 196:9937213 163:9975068
249:9852763 248:9937219 215:9975073
302:9852768 249:9937220 266:9975078
356:9852773 282:9937223 319:9975083
409:9852778 334:9937228 371:9975088
462:9852783 385:9937234 423:9975093
515:9852788 434:9937238 475:9975098
568:9852794 435:9937239 526:9975103
569:9852795 482:9937243 578:9975108
605:9852798 534:9937248 630:9975113
658:9852803 585:9937253 683:9975118
711:9852809 637:9937259 736:9975124
761:9852814 686:9937263 785:9975129
809:9852818 738:9937268 835:9975133
862:9852823 790:9937273 886:9975138
915:9852828 842:9937278 938:9975144
968:9852833 894:9937283 986:9975148
946:9937288
997:9937293

I then reversed the order of calling for the next three runs

For Index = 1 To 1000
TickValue(Index) = GetTickCount
TimerValue(Index) = Timer
Next Index

for these results.

Timer Changes Timer Changes Timer Changes
1:47258.6 1:47295.9 1:47329.84
69:47258.66 433:47295.95 444:47329.9
637:47258.71 992:47296.01 986:47329.95

Tick Changes Tick Changes Tick Count Changes
1:10030568 1:10067833 1:10101783
18:10030573 21:10067838 37:10101788
70:10030578 73:10067843 89:10101794
121:10030583 126:10067848 103:10101795
174:10030588 178:10067853 104:10101796
226:10030593 230:10067859 133:10101798
278:10030598 278:10067863 186:10101803
331:10030603 330:10067868 238:10101808
383:10030608 382:10067873 290:10101813
436:10030613 434:10067878 342:10101818
489:10030618 485:10067883 395:10101823
542:10030624 536:10067888 410:10101825
585:10030628 588:10067893 444:10101828
638:10030634 640:10067899 495:10101833
689:10030638 681:10067903 547:10101838
741:10030643 733:10067908 597:10101843
794:10030648 786:10067914 648:10101849
846:10030653 836:10067918 696:10101853
899:10030658 888:10067923 710:10101855
952:10030663 941:10067928 742:10101858
993:10067933 794:10101863
831:10101868
883:10101873
935:10101878
987:10101883
1000:10101885

Its faily clear to me that GetTickCount provides a greater degree of precision over the Timer function.


Good Luck
--------------
As a circle of light increases so does the circumference of darkness around it. - Albert Einstein


 
Don't waste all your time, people. The Timer function is only accurate to hundreths of a second. The apparant additional accuracy is actually caused by the casting from one floating type to another doesn't help either. Don't believe it? Let's illustrate:

Dim lp As Single

For lp = 0 To 0.99 Step 0.01
Debug.Print CDbl(lp)
Next

I'd go with CajunCenturion's solution (although, as stated you cannot guarantee better than about 55ms accuracy from it. If you want better resolution than this, consider using the QueryPerformanceFrequenncy and QueryPerformance counter API functions, which provide microsecond accuracy)
 
Thanks for your help.
I will use timer() for now. If I need more accuracy I will then I will change to use the tick count.
 
Here is the complete code for an accurate timer class using API functions. You can start, stop and reset the timer. It is accurate to about 10 microseconds (depending on processor). You can't use it like a timer control to generate interrupts, but it's far better than using the system tick timer for timing processes.
Once you've used this method for a bit you won't want to go back!
Put this in as a class module and then create as many independent timers as you need.

Private Declare Function QueryPerformanceFrequencyAny Lib &quot;kernel32&quot; Alias _
&quot;QueryPerformanceFrequency&quot; (lpFrequency As Any) As Long
Private Declare Function QueryPerformanceCounterAny Lib &quot;kernel32&quot; Alias _
&quot;QueryPerformanceCounter&quot; (lpPerformanceCount As Any) As Long

Private mStartTime As Currency
Private mEndTime As Currency
Private mTotalTime As Double
Private mFrequency As Currency
Private mRunning As Boolean
Private mDuration As Double

Private Sub Class_Initialize()
' measure the frequency of the counter-timer
' ensure the computer is compatible
If QueryPerformanceFrequencyAny(mFrequency) = 0 Then
Err.Raise 1001, , &quot;Hardware out of date!&quot;
mFrequency = 0
Exit Sub
End If
End Sub

Public Sub StartTimer()
QueryPerformanceCounterAny mStartTime
mRunning = True 'used in Duration property
End Sub


Public Sub StopTimer()
mTotalTime = mDuration 'transfer cumulative time so far to module-level variable
mRunning = False 'no longer running
End Sub


Public Sub ResetTimer()
If mRunning Then
StartTimer
End If
mTotalTime = 0# 'only used when in stopped condition
End Sub


Public Property Get Duration() As Double
Dim Interval As Double

If mFrequency = 0 Then
Err.Raise 1002, , &quot;Accurate timer object not initialised&quot;
Duration = 0
Exit Property
End If

If mRunning Then
QueryPerformanceCounterAny mEndTime 'get a new endtime
Interval = CDbl(mEndTime - mStartTime) / mFrequency
mDuration = mTotalTime + Interval 'the stored total so far plus the new addition
Else
mDuration = mTotalTime 'not running - return cumulative
End If

Duration = mDuration
End Property

 
Thanks for the code.
I will have a go with it.

Glyn.
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top