Real-Time Java for the Rest of Us
- “Let him who would enjoy a good future waste none of his present.”
- —Roger Babson
There are many misunderstandings about what real-time is, even amongst seasoned enterprise Java developers. Some confuse it with high-performance, or fast, computing; others think of dynamic applications such as instant messaging. Neither one is necessarily an example of a real-time system. Therefore real-time does not always equal “real fast,” although good performance is often desirable and achievable. In fact, real-time is often orthogonal with high-throughput systems; there’s a trade-off in throughput in many cases. The best way to avoid all of this confusion is to think of it this way: application performance and throughput requirements can be solved with faster, or additional, hardware; real-time requirements, in general, cannot.
This chapter will define real-time computing, and will explain why throwing hardware at a real-time requirement will almost never do any good. We’ll discuss the qualities of a real-time system, define key terms used in the discipline, and examine tools, languages, and environments available to real-time developers outside of the Java world. By the end of this chapter, you’ll have a good real-time foundation to build upon.
Qualities of Real-Time Systems
The goal of a real-time system is to respond to real-world events before a measurable deadline, or within a bounded time frame. However, a real-time system is also about precision. The measured speed of a system’s response to an event is important, but what’s also important is the system’s ability to respond at precisely the right moment in time. Access to a high-resolution timer to perform actions on precise time periods is often a requirement. These two qualities together best define a real-time application’s acceptable behavior: the ability to respond to an event before a deadline, and accurately perform periodic processing, regardless of overall system load. Before we go any further, it’s important to examine the term deadline a little more closely, as well as some other terms often used in the context of real-time systems.
The term deadline can have one of two meanings. First, it can be a deadline relative to an event, such as a notification or message in some form. In this case, the system must respond to that event within a certain amount of time of receiving that event, or from when that event originally occurred. One example of a relative deadline is an elevator as it passes over a sensor indicating that it’s almost at the floor it’s meant to stop at. The real-time software within the elevator must respond to that event within milliseconds of passing the sensor, or it won’t be able to stop at the intended floor. The occupants of an elevator that skips stops are certain to consider this an error.
- Relative Deadline (Di): the amount of time after a request is made that the system needs to respond.
- Absolute Deadline (di): the precise point in time that a task must be completed, regardless of task start time, or request arrival.
Often, with an absolute deadline, a real-time system checks for a particular system state on a regular interval. Some examples of this are an aircraft flight control system, or a nuclear power plant’s core temperature monitoring system. In both of these cases, critical data is continuously polled, such as altitude, or core temperature. Failing to monitor these values at precise points in time can cause these systems to go into a bad state with potentially catastrophic results.
Regardless of the type of deadline, relative or absolute, time is still a main component in proper system behavior. It’s not enough that an elevator’s software knows and responds to a floor sensor; it must do so within a deadline in order to behave correctly. Also, a flight control system must be able to move an aircraft’s control surfaces at the precise time, in reaction to the most recent and accurate set of data, in order to fly the aircraft correctly (without crashing!).
For example, let’s say we have a system requirement to send a response to a request within one millisecond. If the system responds within 500 microseconds every time, you may think the requirement has been met. However, if the request is delayed, outside the system under measurement, the response will not have been sent at the right moment in time (even if it’s sent within one millisecond). Remember, we’re talking about “real” time here; the one-millisecond requirement applies to when the originating system sent the original request.
Figure 1-1 illustrates the problem. Here you see that the system in question has responded to the request within one millisecond, but it was at the wrong time because the request was delayed in delivery. A real-time system must adhere to the end-to-end deadline.
Figure 1-1 The response time was good, but the deadline was missed. This is not a real-time system.
In a real-time system, the time delay from when a real-world event occurs (such as an object passing over a sensor, or the arrival of a stock market data-feed tick) to the time some code finishes processing that event should be reasonably bounded. The ability to meet this deadline must be predictable and guaranteed, all the time, in order to provide the determinism needed for a real-time system.
When discussing real-time systems, the basic element of execution is often referred to as a job, or task. (For a more accurate definition of jobs and tasks in real-time systems, see the note on Jobs and Tasks in Real-Time Systems). There can be one or more tasks in a given system, and therefore tasks can either be running or waiting. On a uniprocessor machine, only one task can be running at a single point in time, as opposed to multiprocessor machines that can execute more than one task at a time.
Regardless, discussions often revolve around the arrival of a system event, or the start of task execution, which can sometimes be one and the same. To clarify, we say that a task can be in one of the three main states:
- Eligible-for-Execution: the task is eligible (ready) to execute.
- Executing: the task is currently executing (running) on a processor.
- Blocked: the task is neither executing, nor eligible to begin executing. It’s blocked for some reason, and this reason is usually stated as part of the state; i.e., blocked-for-IO, blocked-for-release-event, and so on.
With these task states defined, we can begin to discuss how tasks are scheduled in a real-time system. First, the following definitions must be stated:
- Release Time (ri): sometimes called arrival time, or request time, this is the time that a task becomes ready to execute.
- Start Time (si): the time that a task begins executing. As stated above, these concepts may be combined for simplification in many discussions. For example, a task may be started because of a request, or it may be started as part of a predefined schedule. This book shall attempt to separate these concepts when necessary to avoid confusion.
- Finish Time (fi): the time when a task is complete.
- Task Completion Time (Ci = fi – ri): the amount of time a particular task takes to complete its processing by subtracting the task’s arrival time from its finish time. This is also referred to as the cost of task execution.
- Lateness (Li): the difference between the task finish time and its deadline; note that this value is negative if a task completes before its deadline, zero if it completes at its deadline, and positive if it completes after its deadline.
These terms and their associated abbreviations will be used throughout the book. To further clarify them, and to gain a better understanding of real-time systems, let’s explore the factors that affect a system’s ability to meet its deadlines.