Realtime Computing

Realtime computing is, to say the least, very different from general-purpose computing. It is generally found in embedded applications in which we don't have a ``user'' of the system per se; instead, the developers are creating software to be used to drive the particular product.

The most important characteristic of real-time programming is that operations have to occur in ``real time'' -- there is a fixed time by which a process has to have completed its work. This includes a number of different aspects: maximum time for I/O operations to occur, maximum time for computation to occur....

Consider the problem of interrupt handling in a realtime system: we need to set a bound on the time that can occur between a sensor input and when an actuator responds. This includes:

  1. Time to respond to an interrupt for the sensor input. What is the maximum time that might elapse between when the external device requests the interrupt, and when the interrupt service routine begins executing. Note that this includes questions of how long interrupts might be disabled, questions of how long interrupts at a given level might be disabled due to higher-priority interrupts being executed....

  2. Time to execute the interrupt service routine. Note that, in addition to the time we spend in the interrupt handler, we may need to consider the possibility that this ISR is interrupted due to a higher-priority interrupt occurring.

  3. Time that may elapse before a process is scheduled to handle the input.

  4. Time to execute the process handling the input. Note that this may be extended by interrupts...

It will come as no surprise that many realtime systems don't do interrupts, so it will be easier to analyze the time delays!

So, while we are discussing scheduling here, that's far from the only consideration in realtime systems!

A Running Example

Let's assume we have an environment in which we have three realtime processes that we need to schedule. We'll let them all be periodic:

ProcessesPeriodExecution Time
P141
P252
P362

The situation is shown in the following figure. This figure shows the processes, the time they require (represented with the square U-shaped lines), and their periods (represented by the vertical lines). We assume that a process can be scheduled any time within its slice. In the figure, the processes have not been scheduled yet; that's why on cycle 1, for instance, all three processes appear to be shown as if they're running. In an actual solution, we can only have one process running at a time.

Unscheduled processes

In all the following, I'll use "avoid context switches" as a tiebreaker: if there are two processes that have equal merit according to the algorithm, and one of them is already running, I'll leave that one running. As a second tiebreaker, I'll use whichever process has been waiting longer.

Table-driven Scheduling

We can conduct an off-line analysis, and determine a frequency with which every process has to execute. The we can just put them in order, and execute each of them in turn. This technique is most appropriate to periodic tasks; it is sometimes called static cyclic scheduling.

This has the advantage that we have a guarantee that our real-time constraints are met, but the disadvantage that it is very inflexible. What if the various processes need different amounts of the CPU at different times? There is no way to allow for this.

This should seem familiar to people who've seen telemetry systems that multiplex the bandwidth.

A possible table-driven schedule for the example tasks might be 1223312233122311223322112233122331221332213312233122133221: that is, on cycle 1 run process 1, then 2 for two cycles, then 3 for two cycles, and so forth. The scheduled processes now look like this:

table-driven scheduling

I generated this schedule by simply moving cycles around until they fit, by hand.

Fixed Priority Scheduling

We can order the processes according to how tight their deadlines normally are, and assign priorities based on that. Now we use a priority-based scheduling method.

One particular example of a fixed priority scheduling algorithm is "rate monotic scheduling" for perodic processes. In RMS, each process is assigned a fixed priority equal to the frequency of occurrence of its triggering event.

In this example, the priorities of the three processes would be 1/4, 1/5, and 1/6. In order to have integral priorities it's probably worth while to multiply them all by sixty, in which case the priorities become 15, 12, and 10 respectively. Here's how RMS schedules the processes:

Rate-Monotonic Scheduling

Notice that it fails! The red box marks a missed deadline for P3.

Earliest Deadline First

The first, and most obvious approach to deadline-scheduling is to use an ``earliest deadline'' algorithm: sort the processes by deadline, and run the one with the earliest deadline.

Earliest Deadline First

Least Slack

A second deadline algorithm is the ``least slack'' algorithm. A process's slack is defined to be how long it can be delayed and still meet its deadline. So instead of sorting by the actual deadline, we sort by slack and run the process with the least slack. This algorithm is more robust if new processes become ready as a result of external inputs.

Least Slack

Latency

A third deadline-based algorithm is ``latency'' scheduling. This is appropriate in a system in which we have a bit more information: there is communication between the processes, and one's termination may make another one ready. We can represent the dependencies as a graph, and schedule the processes based on that (in effect, we are discovering that some of the processes' deadlines are actually earlier than we thought they were).


Last modified: Wed Nov 9 08:54:57 MST 2005