Topic: Timing Part II
Timing Part II: Timers in VB.NET
In a previous article, we talked about different timers available to VB6. With the move to .NET, this needs to be updated...or does it. In this article, we'll take a look at timing options in VB.NET.VB.NET exposes some new timing methods: Environment.TickCount and System.DateTime.Now.Ticks.
TickCount is a virtual clone of the old GetTickCount API call and returns the "amount of time in milliseconds that has passed since the last time the computer was started."
Ticks gives you "the number of 100-nanosecond intervals that have elapsed since 12:00 A.M., January 1, 0001."
One could also use the old favorites QueryPerformanceCounter and timeGetTime via the standard "Declare Function x Lib y" format, but we like to do things .NET-style.
TickCount has millisecond resolution, while Ticks has 0.0001 millisecond resolution. One would think, therefore, that Ticks would be a wonderfully accurate way to go. But it, like every other timer except QPC, doesn't have the accuracy to match its resolution. That is to say, while Ticks specifies nanoseconds, its value is actually only updated every 15 to 30 milliseconds. Thus it really isn't any better. (Whidbey will include the System.Diagnostics.Stopwatch class, which looks promising.)
The way around this pitfall in VB6 was to call timeBeginPeriod and timeEndPeriod. With those, you could specify an accuracy of 1 ms to match the 1 ms resolution of timeGetTime. Interestingly, this article at Microsoft mentions that D3DPRESENT_INTERVAL_ONE actually sets timeBeginPeriod(1) "to enhance timer resolution". The catch is, timeBeginPeriod doesn't seem to affect TickCount or Ticks accuracy at all.
Our solution? We added these lines to our engine:
Private Declare Function timeGetTime Lib "winmm.dll" () As Integer
Private Declare Function timeBeginPeriod Lib "winmm.dll" (ByVal uPeriod As Integer) As Integer
Private Declare Function timeEndPeriod Lib "winmm.dll" (ByVal uPeriod As Integer) As IntegerThat's right, we're using the old multimedia API calls for our timing, and they're working like a charm. timeBeginPeriod(1) is called in the engine's New, and timeEndPeriod(1) in the Finalize. timeGetTime is used for timing in between.
Anybody else have other experiences with timing in .NET? Drop a comment.