aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGlenn Elliott <gelliott@cs.unc.edu>2010-11-26 17:04:08 -0500
committerGlenn Elliott <gelliott@cs.unc.edu>2010-11-26 17:04:08 -0500
commit4c5c517602f595092979716bacf565fc333ad5fe (patch)
tree8d4234fd01a0f517d3583d75fb6a3a8e528b32f3
parentfcdaecd7621fb9debb8595eb827198c2a97a7b4f (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.h37
-rw-r--r--include/litmus/litmus.h5
-rw-r--r--include/litmus/rt_param.h13
-rw-r--r--litmus/litmus.c11
-rw-r--r--litmus/sched_aedzl.c22
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
10static const fp_t FP_ZERO = {.val = 0}; 12
11static const fp_t FP_ONE = {.val = (1 << FP_SHIFT)}; 13static const fp_t LITMUS_FP_ZERO = {.val = 0};
14static const fp_t LITMUS_FP_ONE = {.val = (1 << FP_SHIFT)};
15
16static 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 */
22static 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
13static inline fpbuf_t _point(fp_t x) 29static 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
23static inline fp_t FP(fpbuf_t x)
24{
25 return _fp(((fpbuf_t) x) << FP_SHIFT);
26}
27
28static inline fpbuf_t _floor(fp_t x) 39static 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 */
40static 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 */
46static inline fp_t _mul(fp_t a, fp_t b) 51static 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 */
81static inline fpbuf_t _fp_to_integer(fp_t x) 86static 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
86static inline fp_t _integer_to_fp(fpbuf_t x) 91static 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
105inline static lt_t get_exec_cost_est(struct task_struct* t) 108inline 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
37typedef long fpbuf_t; 36typedef long fpbuf_t;
38typedef struct 37typedef struct
39{ 38{
40 fpbuf_t val; 39 fpbuf_t val;
41} fp_t; 40} fp_t;
42#endif
43 41
44struct rt_task { 42struct 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}