aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBjörn Brandenburg <bbb@mpi-sws.org>2016-07-19 19:17:34 -0400
committerBjoern Brandenburg <bbb@mpi-sws.org>2017-03-07 16:48:14 -0500
commit28d6d8657119dd1bd53a4018db31cc45a6e8e37b (patch)
tree271b4f4af0b7ba132c83dd0264fc298ab8c35c56
parent60dff237159485139955bfa20a8766e7ea9b45f9 (diff)
Edit description of table-driven scheduling
-rw-r--r--doc/table-driven-scheduling.md72
1 files changed, 41 insertions, 31 deletions
diff --git a/doc/table-driven-scheduling.md b/doc/table-driven-scheduling.md
index f677ea5..fdf0bf5 100644
--- a/doc/table-driven-scheduling.md
+++ b/doc/table-driven-scheduling.md
@@ -4,7 +4,7 @@ As of version 2016.1, LITMUS^RT supports *table-driven scheduling* (aka *time pa
4 4
5In a nutshell: 5In a nutshell:
6 6
7- The support for time-driven scheduling is realized as a *reservation type* in the `P-RES` plugin. 7- The support for table-driven scheduling is realized as a *reservation type* in the `P-RES` plugin.
8 8
9- Each such *table-driven reservation* is a *cyclically repeating* sequence of arbitrarily many, arbitrarily sized *scheduling slots*. 9- Each such *table-driven reservation* is a *cyclically repeating* sequence of arbitrarily many, arbitrarily sized *scheduling slots*.
10 10
@@ -14,29 +14,29 @@ In a nutshell:
14 14
15- On multiprocessors, table-driven reservations are *partitioned*: each reservation is restricted to have scheduling slots on only one processor, but there can be (and usually are) many different table-driven reservations on each core. 15- On multiprocessors, table-driven reservations are *partitioned*: each reservation is restricted to have scheduling slots on only one processor, but there can be (and usually are) many different table-driven reservations on each core.
16 16
17- Time-driven reservations can be freely combined with other reservation types supported by the `P-RES` plugin. 17- Table-driven reservations can be freely combined with other reservation types supported by the `P-RES` plugin.
18 18
19## Concepts and Design 19## Concepts and Design
20 20
21The basic idea behind table-driven scheduling is to define a *static scheduling table* that periodically repeats in time. For each point in time, the static scheduling table determines which entity each processor should be executing (if any), and whether any processors are free to execute a background workload (or idle). 21The basic idea behind table-driven scheduling is to define a *static scheduling table* that periodically repeats in time. For each point in time, the static scheduling table determines which entity each processor should be executing (if any), and whether any processors are free to execute a background workload (or to idle).
22 22
23### Table-Driven Reservations in LITMUS^RT 23### Table-Driven Reservations in LITMUS^RT
24 24
25In LITMUS^RT, the scheduling table does not directly reference specific tasks or threads. Instead, the static scheduling table references reservations (i.e., process *containers*). Within each reservation, contained processes are dispatched dynamically. This approach is conceptually very similar to time partitions as defined by ARINC 653. 25In LITMUS^RT^, the scheduling table does not directly reference specific tasks or threads. Instead, the static scheduling table references reservations (i.e., process *containers*). Within each reservation, contained processes are dispatched dynamically. This approach is conceptually very similar to *time partitions* as defined by [ARINC 653](https://en.wikipedia.org/wiki/ARINC_653).
26 26
27From a user’s point of view, this split makes it much easier to work with scheduling tables, as the to-be-scheduled real-time processes do not yet have to exist when the scheduling table is installed (i.e., during system initialization). Furthermore, the scheduling table does not have to reference ephemeral PIDs, which makes it possible to reuse a fixed table setup across many runs. Processes can be launched and associated with table-driven reservations (i.e., placed in time partitions) at any time *after* the scheduling table was installed. 27From a user’s point of view, this split makes it much easier to work with scheduling tables, as the to-be-scheduled real-time processes do not yet have to exist when the scheduling table is installed (i.e., during system initialization). Furthermore, the scheduling table does not have to reference ephemeral data such as PIDs, which makes it possible to reuse a static table setup across many runs. Processes can be launched and associated with table-driven reservations (i.e., placed in time partitions) at any time *after* the scheduling table has been installed.
28 28
29The reservation-based approach in LITMUS^RT results in a simple two-level scheduling scheme: whenever a table-driven reservation is selected for service (i.e., during one of its slots), it selects and dispatches one of its associated processes (if any), or yields the processor to background tasks (if the reservation is “empty” or if none of the associated processes are ready). 29The reservation-based approach in LITMUS^RT results in a simple two-level scheduling scheme: whenever a table-driven reservation is selected for service (i.e., during one of its slots), it selects and dispatches one of its associated processes (if any), or yields the processor to background tasks (if the reservation is “empty” or if none of the associated processes is ready).
30 30
31If there are multiple ready processes in a reservation, the current table-driven reservation implementation defaults to a simple round-robin scheme among all ready client processes. However, support for priority-arbitration among client processes would be trivial to add, if needed. 31If there are multiple ready processes in a reservation, the current reservation implementation defaults to a simple round-robin scheme among all ready client processes. However, support for priority-based arbitration among client processes would be trivial to add, if needed.
32 32
33### Key Parameters 33### Key Parameters
34 34
35The schedule created by a table-driven reservation is determined by two principal parameters: 35The schedule created by a table-driven reservation is determined by two principal parameters:
36 36
371. the **major cycle** *M*, which is the period of the scheduling table, and 371. the **major cycle** *M*, which is the period of the scheduling table (i.e., at runtime, the schedule repeats every *M* time units), and
382. a sequence of *non-overlapping* **scheduling intervals** (or **slots**), where each such scheduling slot *[S, E)* is defined by a 382. a sequence of *non-overlapping* **scheduling intervals** (or **slots**), where each such scheduling slot *[S, E)* is defined by a
39 - *start offset* *S* in the range [0, *M*) and a 39 - *start offset* *S* in the range [0, *M*) and an
40 - *end offset* *E* in the range (*S*, *M*). 40 - *end offset* *E* in the range (*S*, *M*).
41 41
42For example, suppose we are given a table-driven reservation with 42For example, suppose we are given a table-driven reservation with
@@ -44,36 +44,40 @@ For example, suppose we are given a table-driven reservation with
44- a major cycle of *M=250ms* and 44- a major cycle of *M=250ms* and
45- scheduling slots *[50ms, 60ms)*, *[100ms, 125ms)*, *[200ms, 205ms)*. 45- scheduling slots *[50ms, 60ms)*, *[100ms, 125ms)*, *[200ms, 205ms)*.
46 46
47At runtime, processes of this reservation are eligible to execute during all intervals, for *k = 0, 1, 2, 3, …*, 47At runtime, processes of this reservation are eligible to execute during all intervals
48 48
49- *[k ∙ M + 50, k ∙ M + 60)*, 49- *[k ∙ M + 50, k ∙ M + 60)*,
50- *[k ∙ M + 100, k ∙ M + 125)*, and 50- *[k ∙ M + 100, k ∙ M + 125)*, and
51- *[k ∙ M + 200, k ∙ M + 205),* 51- *[k ∙ M + 200, k ∙ M + 205),*
52 52
53relative to some reference time zero (i.e., usually the boot time of the system). 53for *k = 0, 1, 2, 3, …*, relative to some reference time zero (e.g., usually the boot time of the system).
54 54
55On a given processor, all scheduling slots must be disjoint. That is, in a correct scheduling table, at any point in time *t* and on each processor, there is at most one scheduling interval that contains *t*. 55On a given processor, all scheduling slots must be disjoint. That is, in a correct scheduling table, at any point in time *t* and for each processor, there is at most one scheduling interval that contains *t*.
56 56
57 57
58## Creating Table-Driven Reservations 58## Creating a Table-Driven Reservation
59 59
60Since time partitioning is realized with reservations in LITMUS^RT, a scheduling table is comprised of one or more table-driven reservations. Each such table-driven reservation must be explicitly created prior to use with the `resctl` utility. (For an introduction to `resctl`, see the guide [HOWTO: Working with Reservations](howto-use-resctl.md)). 60Since time partitioning is realized with reservations in LITMUS^RT^, a scheduling table is comprised of one or more table-driven reservations. Each such table-driven reservation must be explicitly created prior to use with the `resctl` utility. (For an introduction to `resctl`, see the guide [HOWTO: Working with Reservations](howto-use-resctl.md)).
61 61
62The general form of the command is: 62The general form of the command is:
63 63
64 resctl -n RID -c CPU -t table-driven -m MAJOR-CYCLE SLOT1 SLOT2 SLOT3… SLOT_N 64 resctl -n RID -c CPU -t table-driven -m MAJOR-CYCLE SLOT1 SLOT2 SLOT3… SLOT_N
65 65
66where RID denotes the reservation ID, and CPU denotes the processor on which the reservation is created. Each slot is simply a semi-open interval of the form `[START_TIME, END_TIME)`. 66where RID denotes the reservation ID, and CPU denotes the processor on which the reservation is created. Each slot is simply a semi-open interval of the form `[START_TIME, END_TIME)`. All times are specified in (possibly fractional) milliseconds.
67 67
68For example, the following command instructs `resctl` to allocate a new table-driven reservation (`-t table-driven`) with ID 123 (`-n 123`) on processor 2 (`-c 2`), with a major cycle of 250ms (`-m 250`) and scheduling slots as mentioned in the preceding example. 68For example, the following command instructs `resctl` to allocate a new table-driven reservation (`-t table-driven`) with ID 123 (`-n 123`) on processor 2 (`-c 2`), with a major cycle of 250ms (`-m 250`) and scheduling slots as mentioned in the preceding example.
69 69
70 resctl -n 123 -c 2 -t table-driven -m 250 '[50, 60)' '[100, 125)' '[200, 205)' 70 resctl -n 123 -c 2 -t table-driven -m 250 '[50, 60)' '[100, 125)' '[200, 205)'
71 71
72When using the `bash` shell, the slot specifications must be quoted to prevent the shell from interpreting the closing parentheses as shell syntax. 72When using `bash` or a similar shell, the slot specifications must be quoted to prevent the shell from interpreting the closing parentheses as shell syntax.
73 73
74If the command succeeds in creating the reservation, there is no output. Otherwise, an error message is shown. 74If the command succeeds in creating the reservation, there is no output. Otherwise, an error message is shown.
75 75
76To define an entire scheduling table comprised of many reservations on multiple cores, execute an appropriate `resctl` command for each reservation in the table. A typical approach is to store the system’s scheduling table as a simple shell script that enables the `P-RES` plugin and then runs the required `resctl` invocations. For example, a table-setup script such as the below example can be run as an init script during system boot, or when launching an experiment. 76## Installing a Scheduling Table
77
78To define an entire scheduling table comprised of many reservations on multiple cores, execute an appropriate `resctl` command for each reservation in the table.
79
80A typical approach is to store the system’s scheduling table as a simple shell script that enables the `P-RES` plugin and then runs the required `resctl` invocations. For example, a table-setup script such as the below example can be run as an init script during system boot, or when launching an experiment.
77 81
78 #!/bin/sh 82 #!/bin/sh
79 83
@@ -101,11 +105,11 @@ To define an entire scheduling table comprised of many reservations on multiple
101 resctl -c 2 -n 2003 -t table-driven -m $MAJOR_CYCLE … 105 resctl -c 2 -n 2003 -t table-driven -m $MAJOR_CYCLE …
102 106
103 107
104(Reservation IDs are arbitrary. As a simple convention, it is convenient to use a consistent reservation ID scheme such as *processor ID ∙ 1000 + index*.) 108While reservation IDs are arbitrary, it is often convenient to use a consistent reservation ID scheme such as *”processor ID” × 1000 + index*.
105 109
106**WARNING**: While `resctl` checks that each reservation’s slots do not overlap with other slots of the *same* reservation, it is possible to (accidentally) specify *multiple* reservations with overlapping slots. A table with such overlapping slots is erroneous and results in undefined behavior. *It is the responsibility of the user to install a scheduling table in which all slots are non-overlapping.* 110**WARNING**: While `resctl` checks that each reservation’s slots do not overlap with other slots of the *same* reservation, it is possible to (accidentally) specify *multiple* reservations with overlapping slots. A table with such overlapping slots is erroneous and results in undefined behavior, but not automatically detected. *It is the responsibility of the user to install a scheduling table in which all slots are non-overlapping.*
107 111
108Also note that it is possible to specify a *different* major cycle for each table-driven reservation. If used carefully, this offers some convenient flexibility and can for instance be used to more efficiently store large tables that would otherwise consume large amounts of memory. However, this is an advanced feature and requires some careful consideration to be used correctly (i.e., without accidentally creating overlapping slots). For simplicity, it’s best to use a uniform major cycle parameter for all table-driven reservations. 112Also note that it is possible to specify a *different* major cycle for each table-driven reservation. If used carefully, this offers some convenient flexibility. For instance, in some cases, it can be used to efficiently store tables that would otherwise consume large amounts of memory (e.g., if the workload’s hyper-period is large). However, this is an advanced feature and requires some careful consideration to be used correctly (i.e., without accidentally creating overlapping slots). For simplicity, it’s best to use a uniform major cycle parameter for all table-driven reservations.
109 113
110## Attaching Tasks to Table-Driven Reservations 114## Attaching Tasks to Table-Driven Reservations
111 115
@@ -117,31 +121,35 @@ For example, to insert the user’s shell into the reservation with ID 123 on pr
117 121
118 resctl -a $$ -r 123 -c 2 122 resctl -a $$ -r 123 -c 2
119 123
120See the guide [HOWTO: Working with Reservations](howto-use-resctl.md) for further details. 124All processes subsequently launched from the shell (i.e., all forked children) automatically become clients of the same reservation.
125
126See the guide [HOWTO: Working with Reservations](howto-use-resctl.md) for further details on attaching real-time tasks to reservations.
121 127
122## Coordinating Task Activations 128## Coordinating Task Activations
123 129
124It can be useful to ensure that a periodic task that is assigned to a table-driven reservation always wakes up at the beginning of each scheduling slot. While LITMUS^RT does not provide a custom interface for this purpose, it can be accomplished with stock Linux APIs. Specifically, appropriate task activations can be programmed with the `clock_nanosleep()` API. The reference *time zero* of the repeating table schedule is literally time zero on the timeline of `CLOCK_MONOTONIC`. 130It is often useful to ensure that a periodic task that is assigned to a table-driven reservation always wakes up at the beginning of each scheduling slot. While LITMUS^RT does not provide a custom interface for this purpose, it can be accomplished with stock Linux APIs.
131
132Specifically, appropriate task activations can be programmed with the [`clock_nanosleep()`](http://linux.die.net/man/2/clock_nanosleep) API. The reference *time zero* of the repeating table schedule is literally time zero on the timeline of `CLOCK_MONOTONIC`.
125 133
126 134
127## Combining Reservation Types 135## Combining Reservation Types
128 136
129It is possible to combine table-driven scheduling with other reservation types by assigning appropriate reservation priorities. There are two possible use cases: 137It is possible to combine table-driven scheduling with other reservation types by assigning appropriate reservation priorities. There are two possible use cases:
130 138
1311. event-driven reservations as lower-priority background reservations that are scheduled when the table is idle, and 1391. event-driven reservations that serve as lower-priority *background* reservations, which are scheduled only when the table is idle, and
1322. higher-priority, *rate-throttled* reservations that can preempt the tasks in the table-driven reservations. 1402. higher-priority, *throttled* reservations that can preempt any tasks in table-driven reservations.
133 141
134The first use case is the normal case (the table takes precedence at all times), but the second use case (the table can be *briefly* overruled) can also make sense to support low-latency applications. We briefly sketch both setups. 142The first use case is the normal scenario (the table takes precedence at all times), but the second use case (the table can be *briefly* overruled) can also make sense when there is a need support low-latency applications. We briefly sketch both setups.
135 143
136### Lower-Priority Background Reservations 144### Lower-Priority Background Reservations
137 145
138By default, table-driven reservations are given the highest-possible priority, which numerically is priority 1. This means that lower-priority event-driven reservations can be trivially added simply by giving them a lower priority (with `resctl`’s `-q` option). 146By default, table-driven reservations are given the highest-possible priority, which numerically is priority 1. This means that lower-priority, event-driven reservations can be trivially added simply by giving them any priority other than priority 1 (with `resctl`’s `-q` option).
139 147
140For example, to add a sporadic polling reservation on processor 2 with ID 9999, priority 99, a budget of 100ms, and a period of 500ms, execute the following command: 148For example, to add a sporadic polling reservation on processor 2 with ID 9999, priority 99, a budget of 100ms, and a period of 500ms, execute the following command:
141 149
142 resctl -n 9999 -c 2 -t polling-sporadic -q 99 -b 100 -p 500 150 resctl -n 9999 -c 2 -t polling-sporadic -q 99 -b 100 -p 500
143 151
144EDF priorities are even lower, so it is possible to combine table-driven reservations with EDF-scheduled background reservations. For instance, the command 152EDF priorities are even lower, so it is possible to combine table-driven reservations with EDF-scheduled background reservations. For instance, the command (which omits the `-q` option)
145 153
146 resctl -n 8888 -c 2 -t polling-sporadic -b 100 -p 500 154 resctl -n 8888 -c 2 -t polling-sporadic -b 100 -p 500
147 155
@@ -150,18 +158,20 @@ adds an EDF-scheduled background reservation.
150 158
151### Higher-Priority Foreground Reservations 159### Higher-Priority Foreground Reservations
152 160
153It is possible to define fixed-priority reservations that can preempt table-driven reservations at any and all times during table-driven scheduling slots. The primary use case for such a setup is to ensure timely processor service for *latency-sensitive* tasks (such as interrupt threads) that do not consume a lot of processor bandwidth, but that need to be scheduled *quickly* when new data arrives. This, of course, makes sense only if the higher-priority reservations are tightly limited to ensure that table allocations are not completely starved. 161It is possible to define fixed-priority reservations that can preempt table-driven reservations at any and all times during table-driven scheduling slots. The primary use case for such a setup is to ensure timely processor service for *latency-sensitive* tasks (such as certain interrupt threads) that do not consume a lot of processor bandwidth, but that need to be scheduled *quickly* when new data arrives. This, of course, makes sense only if the higher-priority reservations are tightly rate-limited to ensure that table allocations are not completely starved.
154 162
155To create a sporadic polling reservation that can preempt table-driven reservations, do the following. 163To create a sporadic polling reservation that can preempt table-driven reservations, do the following.
156 164
157- When creating table-driven reservations, explicitly specify a priority lower than 1 by providing the `-q` switch. 165- When creating table-driven reservations, explicitly specify a priority lower than 1 (i.e., numerically larger than 1) by providing the `-q` switch.
158 166
159 Example: `resctl -q 20 -n 123 -c 2 -t table-driven -m 250 '[50, 60)' '[100, 125)' '[200, 205)'` 167 Example: `resctl -q 20 -n 123 -c 2 -t table-driven -m 250 '[50, 60)' '[100, 125)' '[200, 205)'`
160 168
161- When creating the sporadic polling reservation, explicitly specify a priority higher than the one given to table-driven reservations. 169- When creating the sporadic polling reservation, explicitly specify a priority higher than (i.e., numerically smaller than) the one given to table-driven reservations.
162 170
163 Example: `resctl -q 19 -n 9999 -c 2 -t polling-sporadic -b 1 -p 500` 171 Example: `resctl -q 19 -n 9999 -c 2 -t polling-sporadic -b 1 -p 500`
164 172
165When preempted by a higher-priority reservation, the budget of table-driven reservations is *not* shifted: any cycles that cannot be used during a scheduling slot due to higher-priority interference are simply lost. 173When preempted by a higher-priority reservation, the budget of table-driven reservations is *not* shifted: any cycles that cannot be used during a scheduling slot due to higher-priority interference are simply lost.
166 174
167Note that it is possible to give each table-driven reservation a different priority. This allows for precise control over *which* table-driven reservations may be preempted by event-driven reservations. \ No newline at end of file 175Note that it is possible to give each table-driven reservation a different priority. This allows for precise control over *which* table-driven reservations may be preempted by event-driven reservations.
176
177In fact, it is even possible to install *multiple*, *intentionally overlapping* table-driven reservations at different priority levels. This could potentially be used to realize a notion of *mixed-criticality* tables such as those described by [Baruah and Fohler (2011)](http://ieeexplore.ieee.org/xpls/abs_all.jsp?arnumber=6121421). A detailed exploration of this approach is subject to future work.