diff options
author | Glenn Elliott <gelliott@cs.unc.edu> | 2010-11-26 17:04:08 -0500 |
---|---|---|
committer | Glenn Elliott <gelliott@cs.unc.edu> | 2010-11-26 17:04:08 -0500 |
commit | 4c5c517602f595092979716bacf565fc333ad5fe (patch) | |
tree | 8d4234fd01a0f517d3583d75fb6a3a8e528b32f3 | |
parent | fcdaecd7621fb9debb8595eb827198c2a97a7b4f (diff) |
Per-task feedback control.
Allow tasks to specify unique feedback control parameters.
If no parameters are specified (LITMUS_FP_ZERO), then default
parameters of a = .102 and b = .303 are used, a critically-
damped feedback control system.
-rw-r--r-- | include/litmus/fpmath.h | 37 | ||||
-rw-r--r-- | include/litmus/litmus.h | 5 | ||||
-rw-r--r-- | include/litmus/rt_param.h | 13 | ||||
-rw-r--r-- | litmus/litmus.c | 11 | ||||
-rw-r--r-- | litmus/sched_aedzl.c | 22 |
5 files changed, 54 insertions, 34 deletions
diff --git a/include/litmus/fpmath.h b/include/litmus/fpmath.h index 0ad1927e2261..9564d4529387 100644 --- a/include/litmus/fpmath.h +++ b/include/litmus/fpmath.h | |||
@@ -1,14 +1,30 @@ | |||
1 | #ifndef __FP_MATH_H__ | 1 | #ifndef __FP_MATH_H__ |
2 | #define __FP_MATH_H__ | 2 | #define __FP_MATH_H__ |
3 | 3 | ||
4 | #include <litmus/rt_param.h> | ||
5 | |||
4 | #define FP_SHIFT 10 | 6 | #define FP_SHIFT 10 |
5 | #define ROUND_BIT (FP_SHIFT - 1) | 7 | #define ROUND_BIT (FP_SHIFT - 1) |
6 | #define ONE FP(1) | 8 | #define ONE FP(1) |
7 | 9 | ||
8 | #define _fp(x) ((fp_t) {x}) | 10 | #define _fp(x) ((fp_t) {x}) |
9 | 11 | ||
10 | static const fp_t FP_ZERO = {.val = 0}; | 12 | |
11 | static const fp_t FP_ONE = {.val = (1 << FP_SHIFT)}; | 13 | static const fp_t LITMUS_FP_ZERO = {.val = 0}; |
14 | static const fp_t LITMUS_FP_ONE = {.val = (1 << FP_SHIFT)}; | ||
15 | |||
16 | static inline fp_t FP(fpbuf_t x) | ||
17 | { | ||
18 | return _fp(((fpbuf_t) x) << FP_SHIFT); | ||
19 | } | ||
20 | |||
21 | /* divide two integers to obtain a fixed point value */ | ||
22 | static inline fp_t _frac(fpbuf_t a, fpbuf_t b) | ||
23 | { | ||
24 | return _fp(FP(a).val / (b)); | ||
25 | } | ||
26 | |||
27 | #ifdef __KERNEL__ | ||
12 | 28 | ||
13 | static inline fpbuf_t _point(fp_t x) | 29 | static inline fpbuf_t _point(fp_t x) |
14 | { | 30 | { |
@@ -20,11 +36,6 @@ static inline fpbuf_t _point(fp_t x) | |||
20 | /*(x.val >> FP_SHIFT), (x.val % (1 << FP_SHIFT)) */ | 36 | /*(x.val >> FP_SHIFT), (x.val % (1 << FP_SHIFT)) */ |
21 | #define _FP_ "%ld/1024" | 37 | #define _FP_ "%ld/1024" |
22 | 38 | ||
23 | static inline fp_t FP(fpbuf_t x) | ||
24 | { | ||
25 | return _fp(((fpbuf_t) x) << FP_SHIFT); | ||
26 | } | ||
27 | |||
28 | static inline fpbuf_t _floor(fp_t x) | 39 | static inline fpbuf_t _floor(fp_t x) |
29 | { | 40 | { |
30 | return x.val >> FP_SHIFT; | 41 | return x.val >> FP_SHIFT; |
@@ -36,12 +47,6 @@ static inline fpbuf_t _round(fp_t x) | |||
36 | return _floor(x) + ((x.val >> ROUND_BIT) & 1); | 47 | return _floor(x) + ((x.val >> ROUND_BIT) & 1); |
37 | } | 48 | } |
38 | 49 | ||
39 | /* divide two integers to obtain a fixed point value */ | ||
40 | static inline fp_t _frac(fpbuf_t a, fpbuf_t b) | ||
41 | { | ||
42 | return _fp(FP(a).val / (b)); | ||
43 | } | ||
44 | |||
45 | /* multiply two fixed point values */ | 50 | /* multiply two fixed point values */ |
46 | static inline fp_t _mul(fp_t a, fp_t b) | 51 | static inline fp_t _mul(fp_t a, fp_t b) |
47 | { | 52 | { |
@@ -77,10 +82,10 @@ static inline fp_t _abs(fp_t x) | |||
77 | return _fp(abs(x.val)); | 82 | return _fp(abs(x.val)); |
78 | } | 83 | } |
79 | 84 | ||
80 | /* equiv. to casting float/double to integer */ | 85 | /* works the same as casting float/double to integer */ |
81 | static inline fpbuf_t _fp_to_integer(fp_t x) | 86 | static inline fpbuf_t _fp_to_integer(fp_t x) |
82 | { | 87 | { |
83 | return _floor(_abs(x)) * ((x.val > 0) ? 1 : -1); | 88 | return _floor(_abs(x)) * ((x.val > 0) ? 1 : -1); |
84 | } | 89 | } |
85 | 90 | ||
86 | static inline fp_t _integer_to_fp(fpbuf_t x) | 91 | static inline fp_t _integer_to_fp(fpbuf_t x) |
@@ -120,5 +125,5 @@ static inline fp_t _max(fp_t a, fp_t b) | |||
120 | else | 125 | else |
121 | return a; | 126 | return a; |
122 | } | 127 | } |
123 | 128 | #endif | |
124 | #endif | 129 | #endif |
diff --git a/include/litmus/litmus.h b/include/litmus/litmus.h index 95125d23c458..1d50efa2aee3 100644 --- a/include/litmus/litmus.h +++ b/include/litmus/litmus.h | |||
@@ -102,6 +102,9 @@ inline static lt_t budget_remaining(struct task_struct* t) | |||
102 | #define set_zerolaxity(t,s) (tsk_rt(t)->job_params.zero_laxity=(s)) | 102 | #define set_zerolaxity(t,s) (tsk_rt(t)->job_params.zero_laxity=(s)) |
103 | 103 | ||
104 | #ifdef CONFIG_PLUGIN_AEDZL | 104 | #ifdef CONFIG_PLUGIN_AEDZL |
105 | #define get_feedback_a(t) (tsk_rt(t)->task_params.a) | ||
106 | #define get_feedback_b(t) (tsk_rt(t)->task_params.b) | ||
107 | |||
105 | inline static lt_t get_exec_cost_est(struct task_struct* t) | 108 | inline static lt_t get_exec_cost_est(struct task_struct* t) |
106 | { | 109 | { |
107 | return (lt_t)( /* express cost in terms of lt_t */ | 110 | return (lt_t)( /* express cost in terms of lt_t */ |
@@ -109,7 +112,7 @@ inline static lt_t get_exec_cost_est(struct task_struct* t) | |||
109 | assume fraction is not negative and take abs()*/ | 112 | assume fraction is not negative and take abs()*/ |
110 | _fp_to_integer( /* truncate off fractional part */ | 113 | _fp_to_integer( /* truncate off fractional part */ |
111 | _mul( /* exe = util * period */ | 114 | _mul( /* exe = util * period */ |
112 | tsk_rt(t)->task_params.util_est, _frac(get_rt_period(t), 1) | 115 | tsk_rt(t)->zl_util_est, _frac(get_rt_period(t), 1) |
113 | ) | 116 | ) |
114 | ) | 117 | ) |
115 | ) | 118 | ) |
diff --git a/include/litmus/rt_param.h b/include/litmus/rt_param.h index d1a1f6ab523a..d2ef9ed02349 100644 --- a/include/litmus/rt_param.h +++ b/include/litmus/rt_param.h | |||
@@ -33,13 +33,11 @@ typedef enum { | |||
33 | PRECISE_ENFORCEMENT /* NOT IMPLEMENTED - enforced with hrtimers */ | 33 | PRECISE_ENFORCEMENT /* NOT IMPLEMENTED - enforced with hrtimers */ |
34 | } budget_policy_t; | 34 | } budget_policy_t; |
35 | 35 | ||
36 | #ifdef CONFIG_PLUGIN_AEDZL | ||
37 | typedef long fpbuf_t; | 36 | typedef long fpbuf_t; |
38 | typedef struct | 37 | typedef struct |
39 | { | 38 | { |
40 | fpbuf_t val; | 39 | fpbuf_t val; |
41 | } fp_t; | 40 | } fp_t; |
42 | #endif | ||
43 | 41 | ||
44 | struct rt_task { | 42 | struct rt_task { |
45 | lt_t exec_cost; | 43 | lt_t exec_cost; |
@@ -49,10 +47,9 @@ struct rt_task { | |||
49 | task_class_t cls; | 47 | task_class_t cls; |
50 | budget_policy_t budget_policy; /* ignored by pfair */ | 48 | budget_policy_t budget_policy; /* ignored by pfair */ |
51 | 49 | ||
52 | #ifdef CONFIG_PLUGIN_AEDZL | 50 | /* AEDZL - feedback control parameters set by user */ |
53 | fp_t util_est; | 51 | fp_t a; |
54 | fp_t accum_err; | 52 | fp_t b; |
55 | #endif | ||
56 | }; | 53 | }; |
57 | 54 | ||
58 | /* The definition of the data that is shared between the kernel and real-time | 55 | /* The definition of the data that is shared between the kernel and real-time |
@@ -139,6 +136,10 @@ struct rt_param { | |||
139 | unsigned int zl_timer_armed:1; | 136 | unsigned int zl_timer_armed:1; |
140 | /* used to trigger zero-laxity detection */ | 137 | /* used to trigger zero-laxity detection */ |
141 | struct hrtimer zl_timer; | 138 | struct hrtimer zl_timer; |
139 | #ifdef CONFIG_PLUGIN_AEDZL | ||
140 | fp_t zl_util_est; | ||
141 | fp_t zl_accum_err; | ||
142 | #endif | ||
142 | #endif | 143 | #endif |
143 | 144 | ||
144 | /* task representing the current "inherited" task | 145 | /* task representing the current "inherited" task |
diff --git a/litmus/litmus.c b/litmus/litmus.c index b04a42b0da9c..e71cf99201f6 100644 --- a/litmus/litmus.c +++ b/litmus/litmus.c | |||
@@ -127,6 +127,17 @@ asmlinkage long sys_set_rt_task_param(pid_t pid, struct rt_task __user * param) | |||
127 | 127 | ||
128 | target->rt_param.task_params = tp; | 128 | target->rt_param.task_params = tp; |
129 | 129 | ||
130 | #ifdef CONFIG_PLUGIN_AEDZL | ||
131 | /* default feedback parameters if not specified */ | ||
132 | if(target->rt_param.task_params.a.val == LITMUS_FP_ZERO.val) | ||
133 | target->rt_param.task_params.a.val = 104; /* 0.102 -- 102/1000 */ | ||
134 | if(target->rt_param.task_params.b.val == LITMUS_FP_ZERO.val) | ||
135 | target->rt_param.task_params.b.val = 310; /* 0.303 -- 303/1000 */ | ||
136 | |||
137 | target->rt_param.zl_util_est = _frac(tp.exec_cost, tp.period); | ||
138 | target->rt_param.zl_accum_err = LITMUS_FP_ZERO; | ||
139 | #endif | ||
140 | |||
130 | retval = 0; | 141 | retval = 0; |
131 | out_unlock: | 142 | out_unlock: |
132 | read_unlock_irq(&tasklist_lock); | 143 | read_unlock_irq(&tasklist_lock); |
diff --git a/litmus/sched_aedzl.c b/litmus/sched_aedzl.c index d521a6497677..4943e1ed7616 100644 --- a/litmus/sched_aedzl.c +++ b/litmus/sched_aedzl.c | |||
@@ -248,20 +248,20 @@ static inline void update_exe_estimate(struct task_struct *t, lt_t actual_cost) | |||
248 | TRACE_TASK(t, "OLD cost: %llu, est cost: %llu, est util: %d.%d, est err: %d.%d\n", | 248 | TRACE_TASK(t, "OLD cost: %llu, est cost: %llu, est util: %d.%d, est err: %d.%d\n", |
249 | tsk_rt(t)->task_params.exec_cost, | 249 | tsk_rt(t)->task_params.exec_cost, |
250 | get_exec_cost_est(t), | 250 | get_exec_cost_est(t), |
251 | _fp_to_integer(tsk_rt(t)->task_params.util_est), _point(tsk_rt(t)->task_params.util_est), | 251 | _fp_to_integer(tsk_rt(t)->zl_util_est), _point(tsk_rt(t)->zl_util_est), |
252 | _fp_to_integer(tsk_rt(t)->task_params.accum_err), _point(tsk_rt(t)->task_params.accum_err)); | 252 | _fp_to_integer(tsk_rt(t)->zl_accum_err), _point(tsk_rt(t)->zl_accum_err)); |
253 | 253 | ||
254 | err = _sub(actual_util, tsk_rt(t)->task_params.util_est); | 254 | err = _sub(actual_util, tsk_rt(t)->zl_util_est); |
255 | /* | 255 | /* |
256 | TRACE_TASK(t, "delta err = actual - est\n" | 256 | TRACE_TASK(t, "delta err = actual - est\n" |
257 | "\t%d.%d = %d.%d - %d.%d\n", | 257 | "\t%d.%d = %d.%d - %d.%d\n", |
258 | _fp_to_integer(err), _point(err), | 258 | _fp_to_integer(err), _point(err), |
259 | _fp_to_integer(actual_util), _point(actual_util), | 259 | _fp_to_integer(actual_util), _point(actual_util), |
260 | _fp_to_integer(tsk_rt(t)->task_params.util_est), _point(tsk_rt(t)->task_params.util_est)); | 260 | _fp_to_integer(tsk_rt(t)->zl_util_est), _point(tsk_rt(t)->zl_util_est)); |
261 | */ | 261 | */ |
262 | 262 | ||
263 | new = _add(_mul(a_fp, err), | 263 | new = _add(_mul(get_feedback_a(t), err), |
264 | _mul(b_fp, tsk_rt(t)->task_params.accum_err)); | 264 | _mul(get_feedback_b(t), tsk_rt(t)->zl_accum_err)); |
265 | /* | 265 | /* |
266 | TRACE_TASK(t, "util est = a*(delta error) + b*(accum error)\n" | 266 | TRACE_TASK(t, "util est = a*(delta error) + b*(accum error)\n" |
267 | "\t%d.%d = %d.%d * %d.%d + %d.%d * %d.%d\n", | 267 | "\t%d.%d = %d.%d * %d.%d + %d.%d * %d.%d\n", |
@@ -269,17 +269,17 @@ static inline void update_exe_estimate(struct task_struct *t, lt_t actual_cost) | |||
269 | _fp_to_integer(a_fp), _point(a_fp), | 269 | _fp_to_integer(a_fp), _point(a_fp), |
270 | _fp_to_integer(err), _point(err), | 270 | _fp_to_integer(err), _point(err), |
271 | _fp_to_integer(b_fp), _point(b_fp), | 271 | _fp_to_integer(b_fp), _point(b_fp), |
272 | _fp_to_integer(tsk_rt(t)->task_params.accum_err), _point(tsk_rt(t)->task_params.accum_err)); | 272 | _fp_to_integer(tsk_rt(t)->zl_accum_err), _point(tsk_rt(t)->zl_accum_err)); |
273 | */ | 273 | */ |
274 | 274 | ||
275 | tsk_rt(t)->task_params.util_est = new; | 275 | tsk_rt(t)->zl_util_est = new; |
276 | tsk_rt(t)->task_params.accum_err = _add(tsk_rt(t)->task_params.accum_err, err); | 276 | tsk_rt(t)->zl_accum_err = _add(tsk_rt(t)->zl_accum_err, err); |
277 | 277 | ||
278 | TRACE_TASK(t, "cost: %llu, est cost: %llu, est util: %d.%d, est err: %d.%d, (delta cost: %d.%d, delta err: %d.%d)\n", | 278 | TRACE_TASK(t, "cost: %llu, est cost: %llu, est util: %d.%d, est err: %d.%d, (delta cost: %d.%d, delta err: %d.%d)\n", |
279 | tsk_rt(t)->task_params.exec_cost, | 279 | tsk_rt(t)->task_params.exec_cost, |
280 | get_exec_cost_est(t), | 280 | get_exec_cost_est(t), |
281 | _fp_to_integer(tsk_rt(t)->task_params.util_est), _point(tsk_rt(t)->task_params.util_est), | 281 | _fp_to_integer(tsk_rt(t)->zl_util_est), _point(tsk_rt(t)->zl_util_est), |
282 | _fp_to_integer(tsk_rt(t)->task_params.accum_err), _point(tsk_rt(t)->task_params.accum_err), | 282 | _fp_to_integer(tsk_rt(t)->zl_accum_err), _point(tsk_rt(t)->zl_accum_err), |
283 | _fp_to_integer(new), _point(new), | 283 | _fp_to_integer(new), _point(new), |
284 | _fp_to_integer(err), _point(err)); | 284 | _fp_to_integer(err), _point(err)); |
285 | } | 285 | } |