App Notes

Contents[Hide]
Download zip archive

Key Ideas

  • How to use the Samraksh RealTime timer
  • How to compare the RealTime timer with the standard timer

Description

This app note compares the Samraksh RealTime timer with the standard timer under different load conditions. It shows that the jitter — the difference between when the timer should have fired vs. the time it actually did fire — is much lower for the RealTime timer. This means that the RealTime timer can be used for tasks that must be conducted with precise timing constraints.

Compatibility

eMote.NOW 1.0, eMote version 4.3.1.13+ and Visual Studio 2012+

Complexity Level

Moderately complex. The use of threads to simulate loads and the collection of performance data add some complexity.

Setup

You'll need just one .NOW.

Discussion

A timer lets you cause an event, with associated callback, after a specified interval of time. This can be done repeatedly if desired, producing a periodic timer. Our concern here is how accurate the timer is: that is, if you set the interval to 100 ms (10 times a second), how close to 100 ms will it be?

The Scheduler

First, a note on the eMote scheduler, which uses the underlying Micro Framework (MF) scheduler. A program can have multiple threads running — this is one of the benefits of MF — so to simulate simultaneous execution, each active thread gets a time slice called a quantum that is fixed at 20 ms. In general, threads are executed in a round-robin fashion with each getting its quantum in turn and then releasing back to the scheduler. If a thread blocks such as by sleeping or waiting on an event, it releases back to the scheduler right away.

RealTime and Standard Timers

Samraksh eMote, which is based on Microsoft's Micro Framework (MF), comes with the standard MF timer class. Suppose you have a timer defined in an eMote program. When the timer interval expires, the scheduler arranges for the event callback to be executed. If another thread is executing, the scheduler will wait until that thread's quantum has finished before executing the timer callback. Hence, the callback could be delayed up to about 20 ms. The scheduler can also choose to execute the callback early if it would expire in the next thread quantum. So the jitter can be up to a quantum of time.

This jitter can be too much for some applications such as high-precision environmental sensing where precise timing is important. To handle this, Samraksh has implemented a custom RealTime timer. When a RealTime timer interval has expired, any executing thread is interrupted and the timer callback is executed immediately. Hence jitter will be very low.

Testing for Jitter

We expect jitter to be affected by load; that is, how many other threads are running. This app note approaches this by launching make-work threads that simulate the load of an application program. As we're interested in worst-case jitter, we make sure each make-work thread is compute-bound so that it will not release its quantum early.

The app note runs as follows:

  • It runs a set of tests in which 0 through 4 make-work threads are running.
  • For each test it runs a RealTime timer for 2000 callbacks, then does the same for the standard timer. The callback intervals for each are 100 ms. (The RealTime timer intervals are in μs so it runs for 100,000 μs = 100 ms.) On each callback the time the callback occured is saved as a DateTime Tick value in an array.
  • After each timer runs the required number of callbacks descriptive stats are computed for mean error (the difference between desired interval and actual interval) and the mean, min, max, range and standard deviation of the actual interval length. The values are saved in an array.
  • After all the tests are run, the results are printed to the log in CSV format. This makes it easy to import into a spreadsheet or other program that handles CSV values.

Results

The results of a run of the app note are shown below. Result times are in μs. The timer interval is 100,000 μs. 2000 samples were taken for each time for each of the number of make-work threads. When you run this you will probably get somewhat different results but they should not be substantial.

    RealTime Timer   Standard Timer

Make-Work
Threads

 

MeanError 

Min 

Max 

Range 

Mean 

Std 

 

MeanError 

Min 

Max 

Range 

Mean 

Std 

0

 

10

99,919

100,010

91

100,010

5

   

281

99,019

100,832

1,812

100,000

386

1

 

8

99,918

100,037

119

100,006

7

 

4,247

82,267

103,121

20,854

100,006

6,530

2

 

8

99,949

100,007

59

100,006

7

 

4,262

82,247

103,139

20,892

100,003

6,545

3

 

8

99,942

100,043

101

100,006

7

 

4,296

82,256

103,205

20,948

100,008

6,567

4

 

8

99,913

100,043

130

100,006

9

 

4,325

82,251

103,201

20,950

100,004

6,594

The RealTime timer is not particularly affected by the number of make-work threads. The largest range is about 119 μs and the largest standard deviation is about 9 μs. It has high precision under all loads.

By contrast, the standard timer shows substantial variation. When there are no make-work threads the range is about 1,812 μs and the standard deviation is about 386 μs. This is more than for the RealTime timer. But things get much worse for the standard timer if there is at least one make-work thread running. The range is about 21,000 μs and the standard deviation is about 6,600 μs. These results for the standard timer are in line with what we'd expect given our understanding of how the MF scheduler handles timer callbacks.

Running the App Note

Use Visual Studio as usual to build and deploy the app note to your .NOW. Open MF Deploy and connect to the .NOW (Target →Connect, or press F5). Restart the .NOW by pressing the reset button. You should see progress on the MF Deploy log, and you'll see sample counts on the .NOW's LCD display.

Using the RealTime Timer

The callback to the RealTime timer should

  • Be short so as minimize conflict with other threads and events.
  • Manage heap objects so as to minimize the possibility of interference with the garbage collector.

See the article on Realtime Performance for more details.

Remarks on the Program

There are points of interest in the app note program itself.

Timer Callbacks

The interfaces to the timer callbacks are different but the logic for handling them is mostly the same. Hence the for the RealTime timer the callback is specified as

_realTimeTimer.OnInterrupt += (data1, data2, time) => TimerCommon.OnTick(time, _realTimeTimer);

For the standard time the callback is specified as

_dotNetTimer = new Timer(_ => TimerCommon.OnTick(DateTime.Now, _dotNetTimer), null, 0, TimerIntervalMilliSec);

Both invoke the method TimerCommon. The RealTime callback includes a DateTime value that gives the time the callback occurred so it is given as the first argument. The standard timer does not, so an anonymous method is used that passes the DateTime.Now value as the first argument. The timer objects them selves are passed as the second arguments since the way they are disposed varies.

Thread Management

Each thread is created with this code:

makeWorkThreads[i] = new Thread(() =>
{
     Debug.Print("  Starting Makework thread " + i1);
    var cntr = 0;
    while (true)
    {
        if (_makeWorkThreadStop) { return; }    // If time to stop, return
        cntr++;
    }
});

The threads when running run a loop that checks if it's time to stop. If so, it returns, ending the thread. If not, in increments a counter and repeats.

When the required number of timer samples have been collected, the semaphore NextStep is raised so that the analysis part of the program can calculate the statistics. Finally, the threads are stopped by setting _makeWorkThreadStop true, and the program waits until the threads have finished via the Thread.Join method:

// Stop the threads and wait till stopped

_makeWorkThreadStop = true;

for (var i = 0; i < numThreads; i++)

{

       makeWorkThreads[i].Join();

       Debug.Print(" Joined MakeWork thread " + i);

}