DEMO - A Real-World Application of the SRMS Service

So how can the SRMS service actually work for you?  The following scenario describes how one would go about setting up and using the SRMS service in the Windows NT 4.0 environment.

Joe Shmo is an ambitious graduate student who is a research assistant in the Engineering department at State University.  As part of one of his experiments, Joe requires the use of highly technological equipment to measure and record his data.   The experiment calls for a constant rate of water to flow through one of the pipes in a closed system. He also needs to visually record some of the changes of the system through the digital camera and maintain a constant water temperature throughout the system.

This particular lab is only supplied with desktop machines running Windows NT 4.0.   He sets up the equipment and configures them to the ports on the machine.   Since the equipment operates in real-time and the execution times of the tasks are not uniform for each period, he decides to use NT's SRMS service designed specifically for firm real-time tasks with variable rate requirements.

Installation:

Joe's first step towards using the SRMS service is to install the program on the lab computer.  Since there is no batch installer for the service yet, Joe unfortunately needs to install it manually.  He needs to untar the the srms_nt.tar file (links to this file are not available yet) on to his desktop and that will expand the srms files and directory structure.  Next, he selects the srms.exe file in the srms\debug directory and that starts the SRMS service and displays the interface window.

Joe is going to have three firm real-time tasks executing at once in the system.   The first task operates the digital camera and directs it to record one frame every 30 milliseconds and write it to the video frame buffer.  The second task will monitor a water flow sensor five times every second and check if the flow is within an acceptable range.   The third task records tempertature readings every half second and performs a recovery algorithm if necessary.

Creating the task executables:

Next, Joe needs to write the task interface programs that will allow the devices to properly communicate with the SRMS service and vice-versa.  After referring to the real-time task model description on this site, Joe learns how he should structure the task programs and how to correctly make SRMS API function calls.  To create the program, Joe uses Microsoft's Visual Studio.  He opens a new Win32 Console Application workspace and includes the taskapi.c, taskapi.h, and rt_task.h files.  Next, he creates a new task1.c file and copies the sample task model code shown in the real-time task model section to that file.  To make life a little easier, Joe creates a header file (task1.h) which gives values to all of the definitions in the model code, and includes the header in task1.c.  The header file looks like this:

// TASK1.H

#define MY_PERIOD             30
#define MY_MINIMUM_QOS        90.0
#define NUM_OF_SAMPLE_EXECS   100

BOOL my_rt_work(VOID);
VOID read_sample_exec_file(LPTSTR, ULONG *); 

The values in this header file indicate the digital camera has periodic work to perform every 30 milliseconds, and that this work must be guaranteed to run before its deadline at least a minimum of 90% of the time.    It also indicates the Joe will provide a text file with 100 samples of the execution time of the periodic work.

Since the SRMS service calculates quality of service values based on sample execution times, Joe needs to also create a text file with a list of sample execution times from the device.  The file can be created in any format, but Joe chooses a comma delimited format.  Earlier, he had tested the total time that the device required to perform its periodic work. In this case, the periodic work only consists of writing the image from the device buffer to disk.  To get an accurate set of test data, he ran the device 100 times and recorded it in a text file.  The text file, task1.txt, looks like this:

2,1,1,1,1,1,1,1,2,1,1,1,2,1,1,1,1,2,1,1,1,2,1,1,1,1,1,1,1,1,2,1,1,1,1,1,1,1,1,2,1,1,1,1,1,1,1,1,2,1,
1,1,1,1,1,1,1,2,1,1,1,1,1,1,1,1,2,1,1,1,1,1,1,1,1,2,1,1,1,2,1,1,1,1,2,1,1,1,2,1,1,1,1,1,1,1,1,2,1,1

All the values here are in milliseconds.  As you can see, the total time to execute the job usually takes no more than 1 millisecond, but it can sometimes take a little more.  (Since all time measurements used by SRMS are in millisecond intervals, all measurements, including those in Joe's sample execution text file, are rounded up to the next highest millisecond.)  Joe will use this file later when he executes the task program.  The task program will call the read_sample_exec_file() function, which Joe must also write, to read in the task1.txt file into an array in heap memory.  Therefore, the Joe must write the function specifically to read the format of the sample execution times file that he created.

Next, Joe needs to create the task's periodic work function.  This function is essentially the task's periodic "job".  Code for the worker function for the digital camera's periodic job might look something like this:

BOOL my_rt_work( VOID )
{
    extern UINT WM_RTJobFailedMsg;
    MSG msg;
    device_ptr buffer;

    buffer = device_open();

    while ( (buffer != END_OF_DEVICE_BUFFER) && (msg.message != WM_RTJobFailedMsg) )
    {
        disk_write ( from_buffer, to_disk, sizeof(buffer));
        buffer += sizeof(buffer));
       
        // check to see if a job failed message was posted from scheduler,
        // but don't remove the message

        if (PeekMessage ( &msg, NULL, 0, 0, PM_NOREMOVE))
            TranslateMessage( &msg );   
    }

    return have_work();        // returns true if there is still more work to do
}

Once Joe finishes with the task1.c file, he is ready to compile the executable.   Before doing so, he needs to set some preprocessor definitions and add the winmm.lib library to the list of linked libraries.  For a better description, Joe refers to the more specific information in the file description section of this site.  Finally he is ready to compile the five files (task1.c, task1.h, taskapi.c, taskapi.h, rt_task.h) into one executable called task1.exe.  Although this process of including extra library files and headers is cumbersome, it is the only solution available until a dynamically linked library can be created to share the SRMS API library.  In all consideration, however, the only code Joe needs to write is relatively small, and he does not mind at all since most of the code is already written for him and adapted from the real-time task model.

Creating the second task executable:

After the executable compiles successfully and without errors, Joe needs to create the executables and sample test files for the other two tasks.  He needs to follow the same exact procedure as above for all of the tasks that he needs to run in real-time.

Joe's second task requires controlling a valve which will maintain an even flow of water in a pipe.  On detecting an increase in the flow of water, the computer must respond by altering the valve angle.  This response must occur within a finite period so that the equipment at the receiving end of the pipe does not become overloaded.   The computer will read the flow meter in the pipe five times a second and must perform some complex calculations in order to recompute the proper valve angle.  One hundred preliminary tests peformed in Joe's lab produced the following results, which he put in the text file, task2.txt:

26,30,35,41,48,6,6,6,8,6,7,7,7,8,7,7,7,7,7,8,8,8,8,8,8,8,9,9,9,9,9,9,9,10,10,
10,10,10,10,11,11,11,11,12,11,12,12,12,12,12,13,13,13,14,14,14,14,14,14,15,15,
15,15,16,17,16,17,17,17,17,18,18,18,18,19,19,19,21,20,20,21,21,22,22,22,23,23,
23,24,24,24,25,25,27,26,28,27,27,28,28

Notice that the sample execution times in this sample set are much more variable than those for the digital camera.  This is due to the fact that sometimes the computer must take more time to recompute the valve angle and other times it does not.  Just as he did for the previous task executable, Joe opens up another Win32 console applicaiton workspace in Visual Studio and includes the taskapi.c, taskapi.h, and rt_task.h files.   He also creates the files task2.h and task2.c.  In task2.h, Joe sets the period to 200 and a minimum quality of service of 80%.  Again, he copies the real-time task model code into task.c and adds the following worker function to task2.c:

BOOL my_rt_work( VOID )
{
    extern UINT WM_RTJobFailedMsg;
    MSG msg;
    float new_angle, old_angle;

    while ( msg.message != WM_RTJobFailedMsg )
    {   
        flow = read_flow_meter()

        if (( flow < MIN_FLOW ) || ( flow > MAX_FLOW ))
        {
            new_angle = recompute_valve_angle( old_angle );
            if (PeekMessage ( &msg, NULL, 0, 0, PM_NOREMOVE))
            {
                TranslateMessage( &msg );   
                if ( msg.message == WM_RTJobFailedMsg )
                    break;
            }
            adjust_valve_angle( new_angle );
        }

        if (PeekMessage ( &msg, NULL, 0, 0, PM_NOREMOVE))
            TranslateMessage( &msg );   
    }

    return have_work();        // returns true if there is still more work to do
}

Notice that Joe is extra careful when checking for job failed message from the scheduler.  He knows that his task worker funciton must always poll its message queue for job failed messages with Win32's PeekMessage() function.  He also realizes that the more frequently he checks the queue, the faster his task will be able to reset itself after finding a cleanup message and that will increase the task's likelihood of achieving its quality of service guarantee from the SRMS service.  Once Joe is sure that his code is error free, he sets all necessary preprocessor and linker settings and compiles task2's executable into task2.exe.

Creating the third task executable:

Joe's last order of business is to create the third task executable.  The third task reads a thermometer to gage a temperature of the water in the pipes at various locations along the water's path.  Every half second, the computer is responsible for logging all of the temperature readings and carrying out a recovery procedure any time a thermometer drops below a certain temperature.  Just as with the previous task's valve actuator, the computer also needs to calculate the appropriate amount of heat to restore the water to the correct temperature. 

Joe creates another set of 100 sample execution times with the same comma delimited format and places it in task3.txt.

14,14,14,14,13,14,14,14,13,14,14,14,16,13,15,14,14,13,14,14,14,13,14,14,14,13,
14,14,14,13,17,13,14,14,14,13,15,14,14,13,14,14,14,13,14,14,14,14,16,13,14,14,
14,13,14,14,14,13,14,15,14,13,14,14,14,13,16,13,14,14,14,13,14,14,14,13,14,14,
14,13,14,14,15,13,16,14,14,14,13,14,14,14,13,14,14,14,13,14,14,14, 

This task's periodic work varies even more than the other tasks' ranging from 1-20 milliseconds in total CPU time.  Also, Joe creates the task's header file with the period set to 500 milliseconds and a minimum quality of service set to 70%.  He again follows the same procedure for creating task3.c, and this time, the task's worker function looks like this:

BOOL my_rt_work( VOID )
{
    extern UINT WM_RTJobFailedMsg;
    MSG msg;
   
    while ( msg.message != WM_RTJobFailedMsg )
    {
        for each thermometer in the experiment...
        {   
            temperature = read_thermometer();
           
            if (PeekMessage ( &msg, NULL, 0, 0, PM_NOREMOVE))
            {
                TranslateMessage( &msg );   
                if ( msg.message == WM_RTJobFailedMsg )
                    break;
            }
           
            store( temperature, &log );
           
            if (( temperature < MIN_TEMP ) || ( temperature > MAX_TEMP ) )
                perform_temperature_recovery();
           
            if (PeekMessage ( &msg, NULL, 0, 0, PM_NOREMOVE))
                 TranslateMessage( &msg );   
        }
    }
    return have_work();        // returns true if there is still more work to do
}

Notice again how Joe frequently checks for job failed messages from the scheduler.   In order to be sure that the message queue does not go unchecked for relatively long periods of time, Joe should also check the queue inside any functions that require significant processing power.  Therefore, he should also check for messages periodically throughout the perform_temperature_recovery() function since that function requires a significant amount of processing power.  Once all task3.c is complete, he compiles the five files into task3's executable: task3.exe.

Running the tasks:

Now Joe needs to get down to business.  He intends on starting the digital camera's periodic task to make sure it is working properly.  Following that, he plans on starting the flow regulator's periodic task and then the temperature regulator's periodic task. Although they can be started and stopped in any order and at any time, Joe chooses this sequence ahead of time so that he can be sure that each task is working properly.  Since the SRMS scheduler is still not started at this time, Joe uses this opportunity to activate any options that he wants like allowing overlapped jobs, passing on leftover time, and permitting dual priority.  All of these options are accessible through the 'Options' menu in the SRMS interface.  Also, Joe chooses to activate the progress window which allows him to view his progress step by step as the SRMS system operates.  The progress window is activated by selecting 'progress window' from the 'View' menu. 

To start the task threads, Joe needs to run the task's executable from a dos shell because the command line needs to include name of the sample execution times file.  So, to run task1, Joe opens up a dos shell, changes the current directory to the one with task1's executable, and at the command prompt types the task's path and executable name followed by a space and then the text file's full path and name, as shown below.

demo_fig1.jpg (10892 bytes)

Figure 1

After pressing return, the task attempts registration and QoS admission with the SRMS service, and the entire process is detailed in the progress window (figure 2 below).   Also, since Joe compiled task1's executable with the 'DEBUG' preprocessor definition (as described with the compilation settings), debugging information specific to task1 is printed to the dos shell (figure 3 below).   The debug information includes the time that QoS admission was attempted and the time that it was accepted.  It also inclues the quality of service that the task will be guaranteed by the SRMS service.  Notice that the digital camera required at least 90% QoS and it will receive at least 93%.

wpe3.jpg (19425 bytes)

Figure 2

demo_fig3.jpg (20043 bytes)
Figure 3

Notice that once task1 registers successfully with the SRMS service, the service begins to refer to the task by its real-time task identifier: 'task 222', which is just a unique randomly assigned number (figure 2).  After some time, Joe decides to register the flow regulator task.  He does this in the same manner as he did for the previous task, by opening up another dos shell and typing in the correct command line for task2:

demo_fig4.jpg (35133 bytes)

Figure 4

demo_fig5.jpg (20261 bytes)
Figure 5

Upon pressing return, task2 will attempt registration and QoS admission with all details listed in the SRMS progress window (figure 4).  When the SRMS service finally admits the task, it will choose a proper time to start executing its jobs and proceed automatically.  Since Joe also compiled task2 with the 'DEBUG' preprocessor definition, SRMS prints a more detailed description is to task2's dos shell (figure 5).   Next, Joe decides to register the temperature regulator task.  He does this in the same manner as he did for the previous two tasks, by opening up another dos shell and typing in the correct command line for task3 (figure 7).  The progress log (figure 6) reflects the registering of this third task, number 330:

demo_fig6.jpg (46887 bytes)

Figure 6

demo_fig7.jpg (20201 bytes)
Figure 7

Now Joe is ready to start the system so all three tasks can begin their periodic work.  He does this by selecting 'Start' from the File menu.  Upon doing so, a start message and timestamp appear in the progress window and more debugging information is printed to the dos shell (figures 8 and 9).  Each dotted line in the debugging script indicates the start of a new period.  For each period, the task's remaining budget and expected execution time are displayed, along with timestamps that indicate when particular moments occur in the execution history of the job.Finally, Joe starts the temperature regulator task a little while later by following the same exact procedure as he did for the other two tasks:

demo_fig8.jpg (61507 bytes)

Figure 8

demo_fig9.jpg (61708 bytes)
Figure 9

Now Joe has all three tasks operating smoothly in real-time under the SRMS system.   After five minutes of running, Joe wants to make sure that his tasks are receiving the quality of service that he requested.  To check this out, Joe opens up the 'View' menu and selects the 'Active Registered Tasks' option.  This option displays a dialog box which will allow Joe to view individual task statistics that reveal just how his tasks are performing.  In the upper-right hand corner of the dialog box, Joe selects the task whose details he wants to view; for now, he chooses task1:. 

demo_fig13.jpg (48934 bytes)

Figure 10

The readings in this dialog show that task1 (digital camera) met all of its 8293 deadlines and that all of those deadlines were guaranteed by the service.