Tuesday, August 3, 2010

The Ticker Class - Ready for Production?

My "Introduction to XAML" code samples -- both the WPF and Silverlight versions -- include a Ticker class that does the work behind the scenes.  (You can find the walkthroughs and code samples here: http://www.jeremybytes.com/Downloads.aspx.)  The Ticker.cs file contains the following comment at the top:
// This class is a simple time ticker class. Note: this
// class is for the included demo only and would require
// modifications before using in a production application
I recently received an e-mail from Tim M. asking about this comment.  Let's take a closer look to see why this class may or may not be "Ready for Production."

No Guarantees
This class uses a DispatchTimer that fires a Tick event based on a specified interval.  Our sample application uses a 100 millisecond interval.  But here's the trick: the Tick event is not guaranteed to fire at exactly the interval specified.  The only guarantee that we have is that the Tick event will never fire *before* the interval has elapsed.  And depending on what else your computer is doing at the time, the discrepancies may be quite significant.

Let's Experiment
So let's take a look at the completed code sample from "Introduction to XAML with WPF".  (This will work the same with the Silverlight version.)

1. Navigate to the Ticker.cs file in the WPFStopWatch project.
2. Modify the "UpdateValues" method so it looks like the following:

We've modified the last line to include milliseconds in our display.  Now, if you run the app and click the Start and Stop buttons repeatedly, you will notice that the display doesn't stop at exactly a 100 millisecond interval.  Here's a screenshot from my run:


But it's still hard to see exactly what's going on here.  Let's add each "tick" to an output that we can look at more closely.

3. Add one more line to the "UpdateValues" method to output the value to the Console:

4. Open the "Output" window in Visual Studio -- on the "View" menu if you don't already have it showing.
5. Run the application in "Debug" mode.

Now when you click the Start / Stop buttons, each interval value is recorded in the Output window.  (The Output window is the standard output for "Console" when running a WPF application.).  Here's a screenshot of the output from one my application runs:


What you can see here is that the "1 second" tick occurs a full 1/10th of a second after the 1 second mark.  The time drift on my machine is between 4 and 12 milliseconds for this run.  But this is based on my computer/processor (a 2.66 GHz Core2Duo) and what was happening at the time.  If my machine was busy doing something else, then the tick events would fire further apart.  The good news is that the time reported (the DisplayInterval property of the class) is correct.  So, the "00:01.100" value itself is accurate.

You can do further experimentation by changing the DispatchTimer interval to 10 milliseconds or even 1 millisecond.  By doing this, you can see the minimum time resolution that you can get on your computer with the Ticker class as it currently exists.  On my machine, it varies between 10 and 20 milliseconds with only Visual Studio and this application running.

Is This Really So Bad?
For a simple timer (like we created in the sample), this behavior really isn't a big deal. I keep a timer such as this on my desktop to get a rough idea how long other processes take (such as running a report or fetching data from a web service). It works great for that. But if I wanted to do a "real" stop watch that could be used for high resolution timing (such as millisecond), then I would want to approach this a little differently.

I haven't had to create a high-resolution timer, so I don't have a recommendation on exactly what to do.  A first step may be looking at the DispatcherPriority (an optional parameter in the constructor).  The default DispatcherPriority for the DispatchTimer is Background, which according to the documentation means "Operations are processed after all other non-idle operations are completed."  You can find a complete listing of values on MSDN here: http://msdn.microsoft.com/en-us/library/system.windows.threading.dispatcherpriority.aspx.

Also, we need to consider the limitations of the .NET Framework and the underlying operating system.  Desktop PCs just weren't designed for ultra-high resolution timing purposes.  People who do have time-critical activities, such as complex music sequencing, often have specialized hardware and software (although software-only solutions have become more practical with the increase in processor speed and number of cores).

Ready for Production?
So what we see is that the Ticker class will work perfectly well for a simple timer (which is what we created in the sample project).  But we can also see that there are limitations in the timer resolution.  The good news is that the DisplayInterval value is always correct -- this value does not drift; the drift is in the times between the Tick event firing.

So whether this class is ready for production depends on your needs.  I added the caveat in the comments since there are quirks that need to be considered.

Happy Coding!

1 comment:

  1. The built-in class System.Diagnostics.Stopwatch uses a high precision timer if available.

    http://msdn.microsoft.com/en-us/library/system.diagnostics.stopwatch.aspx

    Stopwatch doesn't give you events to redraw the screen though, so I guess you'd want to keep using a timer like your existing one for this.

    -Nick

    ReplyDelete