Fix summary table. Thanks to leith <eleith@stanford.edu>.
[pintos-anon] / doc / 44bsd.texi
1 @node 4.4BSD Scheduler, Coding Standards, References, Top
2 @appendix 4.4@acronym{BSD} Scheduler
3
4 @iftex
5 @macro tm{TEX}
6 @math{\TEX\}
7 @end macro
8 @macro nm{TXT}
9 @end macro
10 @macro am{TEX, TXT}
11 @math{\TEX\}
12 @end macro
13 @end iftex
14
15 @ifnottex
16 @macro tm{TEX}
17 @end macro
18 @macro nm{TXT}
19 @w{\TXT\}
20 @end macro
21 @macro am{TEX, TXT}
22 @w{\TXT\}
23 @end macro
24 @end ifnottex
25
26 @ifhtml
27 @macro math{TXT}
28 \TXT\
29 @end macro
30 @end ifhtml
31
32 @macro m{MATH}
33 @am{\MATH\, \MATH\}
34 @end macro
35
36 The goal of a general-purpose scheduler is to balance threads' different
37 scheduling needs.  Threads that perform a lot of I/O require a fast
38 response time to keep input and output devices busy, but need little CPU
39 time.  On the other hand, compute-bound threads need to receive a lot of
40 CPU time to finish their work, but have no requirement for fast response
41 time.  Other threads lie somewhere in between, with periods of I/O
42 punctuated by periods of computation, and thus have requirements that
43 vary over time.  A well-designed scheduler can often accommodate threads
44 with all these requirements simultaneously.
45
46 For project 1, you must implement the scheduler described in this
47 appendix.  Our scheduler resembles the one described in @bibref{4.4BSD},
48 which is one example of a @dfn{multilevel feedback queue} scheduler.
49 This type of scheduler maintains several queues of ready-to-run threads,
50 where each queue holds threads with a different priority.  At any given
51 time, the scheduler chooses a thread from the highest-priority non-empty
52 queue.  If the highest-priority queue contains multiple threads, then
53 they run in ``round robin'' order.
54
55 @menu
56 * Thread Niceness::             
57 * Calculating Priority::        
58 * Calculating recent_cpu::      
59 * Calculating load_avg::        
60 * Fixed-Point Real Arithmetic::  
61 @end menu
62
63 @node Thread Niceness
64 @section Niceness
65
66 Thread priority is dynamically determined by the scheduler using a
67 formula given below.  However, each thread also has an integer
68 @dfn{nice} value that determines how ``nice'' the thread should be to
69 other threads.  A @var{nice} of zero does not affect thread priority.  A
70 positive @var{nice}, to the maximum of 20, increases the numeric
71 priority of a thread, decreasing its effective priority, and causes it
72 to give up some CPU time it would otherwise receive.  On the other hand,
73 a negative @var{nice}, to the minimum of -20, tends to take away CPU
74 time from other threads.
75
76 The initial thread starts with a @var{nice} value of zero.  Other
77 threads start with a @var{nice} value inherited from their parent
78 thread.  You
79 must implement these functions, for which we have provided skeleton
80 definitions in @file{threads/thread.c}.
81
82 @deftypefun int thread_get_nice (void)
83 Returns the current thread's @var{nice} value.
84 @end deftypefun
85
86 @deftypefun void thread_set_nice (int @var{new_nice})
87 Sets the current thread's @var{nice} value to @var{new_nice} and
88 recalculates the thread's priority based on the new value
89 (@pxref{Calculating Priority}).  If the running thread no longer has the
90 highest priority, yields.
91 @end deftypefun
92
93 @node Calculating Priority
94 @section Calculating Priority
95
96 Our scheduler has 64 priorities and thus 64 ready queues, numbered 0
97 (@code{PRI_MIN}) through 63 (@code{PRI_MAX}).  Lower numbers correspond
98 to @emph{higher} priorities, so that priority 0 is the highest priority
99 and priority 63 is the lowest.  Thread priority is calculated initially
100 at thread initialization.  It is also recalculated once every fourth
101 clock tick, for every thread.  In either case, it is determined by
102 the formula
103
104 @center @t{@var{priority} = (@var{recent_cpu} / 4) + (@var{nice} * 2)},
105
106 @noindent where @var{recent_cpu} is an estimate of the CPU time the
107 thread has used recently (see below) and @var{nice} is the thread's
108 @var{nice} value.  The coefficients @math{1/4} and 2 on @var{recent_cpu}
109 and @var{nice}, respectively, have been found to work well in practice
110 but lack deeper meaning.  The calculated @var{priority} is always
111 adjusted to lie in the valid range @code{PRI_MIN} to @code{PRI_MAX}.
112
113 This formula gives a thread that has received CPU
114 time recently lower priority for being reassigned the CPU the next
115 time the scheduler runs.  This is key to preventing starvation: a
116 thread that has not received any CPU time recently will have a
117 @var{recent_cpu} of 0, which barring a high @var{nice} value should
118 ensure that it receives CPU time soon.
119
120 @node Calculating recent_cpu
121 @section Calculating @var{recent_cpu}
122
123 We wish @var{recent_cpu} to measure how much CPU time each process has
124 received ``recently.'' Furthermore, as a refinement, more recent CPU
125 time should be weighted more heavily than less recent CPU time.  One
126 approach would use an array of @var{n} elements to
127 track the CPU time received in each of the last @var{n} seconds.
128 However, this approach requires O(@var{n}) space per thread and
129 O(@var{n}) time per calculation of a new weighted average.
130
131 Instead, we use a @dfn{exponentially weighted moving average}, which
132 takes this general form:
133
134 @center @tm{x(0) = f(0),}@nm{x(0) = f(0),}
135 @center @tm{x(t) = ax(t-1) + (1-a)f(t),}@nm{x(t) = a*x(t-1) + f(t),}
136 @center @tm{a = k/(k+1),}@nm{a = k/(k+1),}
137
138 @noindent where @math{x(t)} is the moving average at integer time @am{t
139 \ge 0, t >= 0}, @math{f(t)} is the function being averaged, and @math{k
140 > 0} controls the rate of decay.  We can iterate the formula over a few
141 steps as follows:
142
143 @center @math{x(1) = f(1)},
144 @center @am{x(2) = af(1) + f(2), x(2) = a*f(1) + f(2)},
145 @center @am{\vdots, ...}
146 @center @am{x(5) = a^4f(1) + a^3f(2) + a^2f(3) + af(4) + f(5), x(5) = a**4*f(1) + a**3*f(2) + a**2*f(3) + a*f(4) + f(5)}.
147
148 @noindent The value of @math{f(t)} has a weight of 1 at time @math{t}, a
149 weight of @math{a} at time @math{t+1}, @am{a^2, a**2} at time
150 @math{t+2}, and so on.  We can also relate @math{x(t)} to @math{k}:
151 @math{f(t)} has a weight of approximately @math{1/e} at time @math{t+k},
152 approximately @am{1/e^2, 1/e**2} at time @am{t+2k, t+2*k}, and so on.
153 From the opposite direction, @math{f(t)} decays to weight @math{w} at
154 @am{t = \log_aw, t = ln(w)/ln(a)}.
155
156 The initial value of @var{recent_cpu} is 0 in the first thread
157 created, or the parent's value in other new threads.  Each time a timer
158 interrupt occurs, @var{recent_cpu} is incremented by 1 for the running
159 thread only.  In addition, once per second the value of @var{recent_cpu}
160 is recalculated for every thread (whether running, ready, or blocked),
161 using this formula:
162
163 @center @t{@var{recent_cpu} = (2*@var{load_avg})/(2*@var{load_avg} + 1) * @var{recent_cpu} + @var{nice}},
164
165 @noindent where @var{load_avg} is a moving average of the number of
166 threads ready to run (see below).  If @var{load_avg} is 1, indicating
167 that a single thread, on average, is competing for the CPU, then the
168 current value of @var{recent_cpu} decays to a weight of .1 in
169 @am{\log_{2/3}.1 \approx 6, ln(2/3)/ln(.1) = approx. 6} seconds; if
170 @var{load_avg} is 2, then decay to a weight of .1 takes @am{\log_{3/4}.1
171 \approx 8, ln(3/4)/ln(.1) = approx. 8} seconds.  The effect is that
172 @var{recent_cpu} estimates the amount of CPU time the thread has
173 received ``recently,'' with the rate of decay inversely proportional to
174 the number of threads competing for the CPU.
175
176 Because of assumptions made by some of the tests, @var{recent_cpu} must
177 be updated exactly when the system tick counter reaches a multiple of a
178 second, that is, when @code{timer_ticks () % TIMER_FREQ == 0}, and not
179 at any other time.
180
181 Take note that @var{recent_cpu} can be a negative quantity for a thread
182 with a negative @var{nice} value.  Negative values of @var{recent_cpu}
183 are not changed to 0.
184
185 You must implement @func{thread_get_recent_cpu}, for which there is a
186 skeleton in @file{threads/thread.c}.
187
188 @deftypefun int thread_get_recent_cpu (void)
189 Returns 100 times the current thread's @var{recent_cpu} value, rounded
190 to the nearest integer.
191 @end deftypefun
192
193 @node Calculating load_avg
194 @section Calculating @var{load_avg}
195
196 Finally, @var{load_avg}, often known as the system load average,
197 estimates the average number of threads ready to run over the past
198 minute.  Like @var{recent_cpu}, it is an exponentially weighted moving
199 average.  Unlike @var{priority} and @var{recent_cpu}, @var{load_avg} is
200 system-wide, not thread-specific.  At system boot, it is initialized to
201 0.  Once per second thereafter, it is updated according to the following
202 formula:
203
204 @center @t{@var{load_avg} = (59/60)*@var{load_avg} + (1/60)*@var{ready_threads}},
205
206 @noindent where @var{ready_threads} is the number of threads that are
207 either running or ready to run at time of update (not including the idle
208 thread).
209
210 Because of assumptions made by some of the tests, @var{load_avg} must be
211 updated exactly when the system tick counter reaches a multiple of a
212 second, that is, when @code{timer_ticks () % TIMER_FREQ == 0}, and not
213 at any other time.
214
215 You must implement @func{thread_get_load_avg}, for which there is a
216 skeleton in @file{threads/thread.c}.
217
218 @deftypefun int thread_get_load_avg (void)
219 Returns 100 times the current system load average, rounded to the
220 nearest integer.
221 @end deftypefun
222
223 @menu
224 * Fixed-Point Real Arithmetic::  
225 @end menu
226
227 @node Fixed-Point Real Arithmetic
228 @section Fixed-Point Real Arithmetic
229
230 In the formulas above, @var{priority}, @var{nice}, and
231 @var{ready_threads} are integers, but @var{recent_cpu} and @var{load_avg}
232 are real numbers.  Unfortunately, Pintos does not support floating-point
233 arithmetic in the kernel, because it would
234 complicate and slow the kernel.  Real kernels often have the same
235 limitation, for the same reason.  This means that calculations on real
236 quantities must be simulated using integers.  This is not
237 difficult, but many students do not know how to do it.  This
238 section explains the basics.
239
240 The fundamental idea is to treat the rightmost bits of an integer as
241 representing a fraction.  For example, we can designate the lowest 10
242 bits of a signed 32-bit integer as fractional bits, so that an integer
243 @var{x} represents the real number
244 @iftex
245 @m{x/2^{10}}.
246 @end iftex
247 @ifnottex
248 @m{x/(2**10)}, where ** represents exponentiation.
249 @end ifnottex
250 This is called a 21.10 fixed-point number representation, because there
251 are 21 bits before the decimal point, 10 bits after it, and one sign
252 bit.@footnote{Because we are working in binary, the ``decimal'' point
253 might more correctly be called the ``binary'' point, but the meaning
254 should be clear.} A number in 21.10 format represents, at maximum, a
255 value of @am{(2^{31} - 1) / 2^{10} \approx, (2**31 - 1)/(2**10) =
256 approx.} 2,097,151.999.
257
258 Suppose that we are using a @m{p.q} fixed-point format, and let @am{f =
259 2^q, f = 2**q}.  By the definition above, we can convert an integer or
260 real number into @m{p.q} format by multiplying with @m{f}.  For example,
261 in 21.10 format the fraction 59/60 used in the calculation of
262 @var{load_avg}, above, is @am{(59/60)2^{10}, 59/60*(2**10)} = 1,007
263 (rounded to nearest).  To convert a fixed-point value back to an
264 integer, divide by @m{f}.  (The normal @samp{/} operator in C rounds
265 down.  To round to nearest, add @m{f / 2} before dividing.)
266
267 Many operations on fixed-point numbers are straightforward.  Let
268 @code{x} and @code{y} be fixed-point numbers, and let @code{n} be an
269 integer.  Then the sum of @code{x} and @code{y} is @code{x + y} and
270 their difference is @code{x - y}.  The sum of @code{x} and @code{n} is
271 @code{x + n * f}; difference, @code{x - n * f}; product, @code{x * n};
272 quotient, @code{x / n}.
273
274 Multiplying two fixed-point values has two complications.  First, the
275 decimal point of the result is @m{q} bits too far to the left.  Consider
276 that @am{(59/60)(59/60), (59/60)*(59/60)} should be slightly less than
277 1, but @tm{1,007\times 1,007}@nm{1,007*1,007} = 1,014,049 is much
278 greater than @am{2^{10},2**10} = 1,024.  Shifting @m{q} bits right, we
279 get @tm{1,014,049/2^{10}}@nm{1,014,049/(2**10)} = 990, or about 0.97,
280 the correct answer.  Second, the multiplication can overflow even though
281 the answer is representable.  For example, 128 in 21.10 format is
282 @am{128 \times 2^{10}, 128*(2**10)} = 131,072 and its square @am{128^2,
283 128**2} = 16,384 is well within the 21.10 range, but @tm{131,072^2 =
284 2^{34}}@nm{131,072**2 = 2**34}, greater than the maximum signed 32-bit
285 integer value @am{2^{31} - 1, 2**31 - 1}.  An easy solution is to do the
286 multiplication as a 64-bit operation.  The product of @code{x} and
287 @code{y} is then @code{((int64_t) x) * y / f}.
288
289 Dividing two fixed-point values has the opposite complications.  The
290 decimal point will be too far to the right, which we fix by shifting the
291 dividend @m{q} bits to the left before the division.  The left shift
292 discards the top @m{q} bits of the dividend, which we can again fix by
293 doing the division in 64 bits.  Thus, the quotient when @code{x} is
294 divided by @code{y} is @code{((int64_t) x) * f / y}.
295
296 This section has consistently used multiplication or division by @m{f},
297 instead of @m{q}-bit shifts, for two reasons.  First, multiplication and
298 division do not have the surprising operator precedence of the C shift
299 operators.  Second, multiplication and division are well-defined on
300 negative operands, but the C shift operators are not.  Take care with
301 these issues in your implementation.
302
303 The following table summarizes how fixed-point arithmetic operations can
304 be implemented in C.  In the table, @code{x} and @code{y} are
305 fixed-point numbers, @code{n} is an integer, fixed-point numbers are in
306 signed @m{p.q} format where @m{p + q = 31}, and @code{f} is @code{1 <<
307 q}:
308
309 @html
310 <CENTER>
311 @end html
312 @multitable @columnfractions .5 .5
313 @item Convert @code{n} to fixed point:
314 @tab @code{n * f}
315
316 @item Convert @code{x} to integer (rounding down):
317 @tab @code{x / f}
318
319 @item Convert @code{x} to integer (rounding to nearest):
320 @tab @code{(x + f / 2) / f}
321
322 @item Add @code{x} and @code{y}:
323 @tab @code{x + y}
324
325 @item Subtract @code{y} from @code{x}:
326 @tab @code{x - y}
327
328 @item Add @code{x} and @code{n}:
329 @tab @code{x + n * f}
330
331 @item Subtract @code{n} from @code{x}:
332 @tab @code{x - n * f}
333
334 @item Multiply @code{x} by @code{y}:
335 @tab @code{((int64_t) x) * y / f}
336
337 @item Multiply @code{x} by @code{n}:
338 @tab @code{x * n}
339
340 @item Divide @code{x} by @code{y}:
341 @tab @code{((int64_t) x) * f / y}
342
343 @item Divide @code{x} by @code{n}:
344 @tab @code{x / n}
345 @end multitable
346 @html
347 </CENTER>
348 @end html