XNA Timing Bug

Update - 12/24/07: This issue has been fixed in XNA Game Studio 2.0.  Woo hoo!

While working on my game for Maker Faire (which you’ll be able to download in about a month), I came across a timing bug on the Xbox 360 using XNA.  For an application that requires very accurate timing (millisecond precision), one can use the StopWatch object in .NET 2.0.  This was working quite well in my PC build, but on the Xbox 360 build, I would notice that time would drift with no explanation.  After digging around for a couple days and writing a simple sample to prove the point, I determined that the time value returned by the StopWatch object would drift by about 150ms/minute, which is considerable when precision within a few milliseconds is required (and considerable when it should be accurate to begin with).

I eventually found a workaround:  DateTime.UtcNow.Ticks is perfectly accurate on both platforms.  So a quick rewrite to use this property in all locations requiring accurate timing fixed everything quite nicely.

The item is bugged and confirmed as such by the XNA folks, sample code is sent to the XNA team and it will hopefully be fixed in a future version.  But, for now, if you’re looking for accurate timing on the 360, DateTime.UtcNow.Ticks is your friend.

Update: After Chad’s comment on CodeBetter.com, just wanted to clarify a few things…

  1. DateTime.UtcNow.Ticks may in fact not be precise on any given platform.  As stated below, sitting in a tight loop may not see the Ticks value increase for several milliseconds.
  2. StopWatch internally actually uses DateTime.UtcNow.Ticks if the QueryPerformanceCounter doesn’t give back the results the StopWatch wants (precision information).  On the 360 side of things, QPC does return the valid information to the StopWatch so QPC is what gets used.
  3. The issue above is not one of precision, it’s one of accuracy.  The length of a millisecond on the 360 according to StopWatch/QPC is just plain wrong.  Updates to the StopWatch value are certainly quite fast (millisecond precision) yet over time, comparing the time to “wall time” or DateTime.UtcNow.Ticks shows that the StopWatch runs slower than real-world time by about 150ms per minute.  It never catches up and in fact, just drifts further and further behind.  After about 10 minutes, StopWatch is one second in the past.  But again, only on the 360.  On the tested PCs, there was a drift of only 2 or 3 milliseconds in that same ten minute timeframe.