WEBVTT

00:00:00.520 --> 00:00:05.819
So far in constructing our timesharing system,
we've worked hard to build an execution environment

00:00:05.819 --> 00:00:11.490
that gives each process the illusion of running
on its own independent virtual machine.

00:00:11.490 --> 00:00:16.079
The processes appear to run concurrently although
we're really quickly switching between running

00:00:16.079 --> 00:00:22.250
processes on a single hardware system.
This often leads to better overall utilization

00:00:22.250 --> 00:00:27.780
since if a particular process is waiting for
an I/O event, we can devote the unneeded cycles

00:00:27.780 --> 00:00:33.190
to running other processes.
The downside of timesharing is that it can

00:00:33.190 --> 00:00:39.300
be hard to predict exactly how long a process
will take to complete since the CPU time it

00:00:39.300 --> 00:00:44.399
will receive depends on how much time the
other processes are using.

00:00:44.399 --> 00:00:48.739
So we'd need to know how many other processes
there are, whether they're waiting for I/O

00:00:48.739 --> 00:00:52.660
events, etc.
In a timesharing system we can't make any

00:00:52.660 --> 00:00:58.900
guarantees on completion times.
And we chose to have the OS play the intermediary

00:00:58.900 --> 00:01:03.579
between interrupt events triggered by the
outside world and the user-mode programs where

00:01:03.579 --> 00:01:08.810
the event processing occurs.
In other words, we've separated event handling

00:01:08.810 --> 00:01:14.249
(where the data is stored by the OS)
and event processing (where the data is passed

00:01:14.249 --> 00:01:20.829
to user-mode programs via SVCs).
This means that using a conventional timesharing

00:01:20.829 --> 00:01:27.270
system, it's hard to ensure that event processing
will be complete by a specified event deadline,

00:01:27.270 --> 00:01:33.658
i.e., before the end of a specified time period
after the event was triggered.

00:01:33.658 --> 00:01:38.679
Since modern CPU chips provide inexpensive,
high-performance, general-purpose computing,

00:01:38.679 --> 00:01:44.549
they are often used as the "brains" of control
systems where deadlines are a fact of life.

00:01:44.549 --> 00:01:49.908
For example, consider the electronic stability
control (ESC) system on modern cars.

00:01:49.908 --> 00:01:54.700
This system helps drivers maintain control
of their vehicle during steering and braking

00:01:54.700 --> 00:02:00.429
maneuvers by keeping the car headed in the
driver's intended direction.

00:02:00.429 --> 00:02:04.920
The computer at the heart of the system measures
the forces on the car, the direction of steering,

00:02:04.920 --> 00:02:08.560
and the rotation of the wheels
to determine if there's been a loss of control

00:02:08.560 --> 00:02:13.620
due to a loss of traction, i.e., is the car
"spinning out"?

00:02:13.620 --> 00:02:20.510
If so, the ESC uses rapid automatic braking
of individual wheels to prevent the car's

00:02:20.510 --> 00:02:24.310
heading from veering from the driver's intended
heading.

00:02:24.310 --> 00:02:31.020
With ESC you can slam on your brakes or swerve
to avoid an obstacle and not worry that the

00:02:31.020 --> 00:02:36.380
car will suddenly fishtail out of control.
You can feel the system working as a chatter

00:02:36.380 --> 00:02:42.840
in the brakes.
To be effective, the ESC system has to guarantee

00:02:42.840 --> 00:02:48.460
the correct braking action at each wheel within
a certain time of receiving dangerous sensor

00:02:48.460 --> 00:02:51.840
settings.
This means that it has to be able to guarantee

00:02:51.840 --> 00:02:56.960
that certain subroutines will run to completion
within some predetermined time of a sensor

00:02:56.960 --> 00:03:00.800
event.
To be able to make these guarantees we'll

00:03:00.800 --> 00:03:04.870
have to come up with a better way to schedule
process execution -

00:03:04.870 --> 00:03:10.570
round-robin scheduling won't get the job done!
Systems that can make such guarantees are

00:03:10.570 --> 00:03:15.200
called "real-time systems".
One measure of performance in a real-time

00:03:15.200 --> 00:03:20.300
system is the interrupt latency L, the amount
of time that elapses between a request to

00:03:20.300 --> 00:03:24.560
run some code and when that code actually
starts executing.

00:03:24.560 --> 00:03:29.880
If there's a deadline D associated with servicing
the request, we can compute the maximum allowable

00:03:29.880 --> 00:03:34.720
latency that still permits the service routine
to complete by the deadline.

00:03:34.720 --> 00:03:39.410
In other words, what's the largest L such
that L_max+S = D?

00:03:39.410 --> 00:03:45.160
Bad things can happen if we miss certain deadlines.
Maybe that's why we call them "dead"-lines

00:03:45.160 --> 00:03:48.310
:)
In those cases we want our real time system

00:03:48.310 --> 00:03:54.930
to guarantee that the actual latency is always
less than the maximum allowable latency.

00:03:54.930 --> 00:04:00.390
These critical deadlines give rise to what
we call "hard real-time constraints".

00:04:00.390 --> 00:04:05.880
What factors contribute to interrupt latency?
Well, while handling an interrupt it takes

00:04:05.880 --> 00:04:11.160
times to save the process state, switch to
the kernel context, and dispatch to the correct

00:04:11.160 --> 00:04:15.270
interrupt handler.
When writing our OS, we can work to minimize

00:04:15.270 --> 00:04:19.858
the amount of code involved in the setup phase
of an interrupt handler.

00:04:19.858 --> 00:04:24.270
We also have to avoid long periods of time
when the processor cannot be interrupted.

00:04:24.270 --> 00:04:30.490
Some ISAs have complex multi-cycle instructions,
e.g., block move instructions where a single

00:04:30.490 --> 00:04:35.870
instruction makes many memory accesses as
it moves a block of data from one location

00:04:35.870 --> 00:04:39.270
to another.
In designing the ISA, we need to avoid such

00:04:39.270 --> 00:04:43.520
instructions or design them so that they can
be interrupted and restarted.

00:04:43.520 --> 00:04:48.759
The biggest problem comes when we're executing
another interrupt handler in kernel mode.

00:04:48.759 --> 00:04:53.560
In kernel mode, interrupts are disabled, so
the actual latency will be determined by the

00:04:53.560 --> 00:04:58.230
time it takes to complete the current interrupt
handler in addition to the other costs mentioned

00:04:58.230 --> 00:05:02.490
above.
This latency is not under the control of the

00:05:02.490 --> 00:05:07.479
CPU designer and will depend on the particular
application.

00:05:07.479 --> 00:05:12.710
Writing programs with hard real-time constraints
can get complicated!

00:05:12.710 --> 00:05:15.960
Our goal is to bound and minimize interrupt
latency.

00:05:15.960 --> 00:05:20.650
We'll do this by optimizing the cost of taking
an interrupt and dispatching to the correct

00:05:20.650 --> 00:05:24.729
handler code.
We'll avoid instructions whose execution time

00:05:24.729 --> 00:05:28.389
is data dependent.
And we'll work to minimize the time spent

00:05:28.389 --> 00:05:32.490
in kernel mode.
But even with all these measures, we'll see

00:05:32.490 --> 00:05:37.460
that in some cases we'll have to modify our
system to allow interrupts even in kernel

00:05:37.460 --> 00:05:41.460
mode.
Next we'll look at some concrete examples

00:05:41.460 --> 00:05:46.819
and see what mechanisms are required to make
guarantees about hard real-time constraints.