From 4c5c517602f595092979716bacf565fc333ad5fe Mon Sep 17 00:00:00 2001 From: Glenn Elliott Date: Fri, 26 Nov 2010 17:04:08 -0500 Subject: 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. --- include/litmus/fpmath.h | 37 +++++++++++++++++++++---------------- include/litmus/litmus.h | 5 ++++- include/litmus/rt_param.h | 13 +++++++------ litmus/litmus.c | 11 +++++++++++ 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 @@ #ifndef __FP_MATH_H__ #define __FP_MATH_H__ +#include + #define FP_SHIFT 10 #define ROUND_BIT (FP_SHIFT - 1) #define ONE FP(1) #define _fp(x) ((fp_t) {x}) -static const fp_t FP_ZERO = {.val = 0}; -static const fp_t FP_ONE = {.val = (1 << FP_SHIFT)}; + +static const fp_t LITMUS_FP_ZERO = {.val = 0}; +static const fp_t LITMUS_FP_ONE = {.val = (1 << FP_SHIFT)}; + +static inline fp_t FP(fpbuf_t x) +{ + return _fp(((fpbuf_t) x) << FP_SHIFT); +} + +/* divide two integers to obtain a fixed point value */ +static inline fp_t _frac(fpbuf_t a, fpbuf_t b) +{ + return _fp(FP(a).val / (b)); +} + +#ifdef __KERNEL__ static inline fpbuf_t _point(fp_t x) { @@ -20,11 +36,6 @@ static inline fpbuf_t _point(fp_t x) /*(x.val >> FP_SHIFT), (x.val % (1 << FP_SHIFT)) */ #define _FP_ "%ld/1024" -static inline fp_t FP(fpbuf_t x) -{ - return _fp(((fpbuf_t) x) << FP_SHIFT); -} - static inline fpbuf_t _floor(fp_t x) { return x.val >> FP_SHIFT; @@ -36,12 +47,6 @@ static inline fpbuf_t _round(fp_t x) return _floor(x) + ((x.val >> ROUND_BIT) & 1); } -/* divide two integers to obtain a fixed point value */ -static inline fp_t _frac(fpbuf_t a, fpbuf_t b) -{ - return _fp(FP(a).val / (b)); -} - /* multiply two fixed point values */ static inline fp_t _mul(fp_t a, fp_t b) { @@ -77,10 +82,10 @@ static inline fp_t _abs(fp_t x) return _fp(abs(x.val)); } -/* equiv. to casting float/double to integer */ +/* works the same as casting float/double to integer */ static inline fpbuf_t _fp_to_integer(fp_t x) { - return _floor(_abs(x)) * ((x.val > 0) ? 1 : -1); + return _floor(_abs(x)) * ((x.val > 0) ? 1 : -1); } 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) else return a; } - +#endif #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) #define set_zerolaxity(t,s) (tsk_rt(t)->job_params.zero_laxity=(s)) #ifdef CONFIG_PLUGIN_AEDZL +#define get_feedback_a(t) (tsk_rt(t)->task_params.a) +#define get_feedback_b(t) (tsk_rt(t)->task_params.b) + inline static lt_t get_exec_cost_est(struct task_struct* t) { 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) assume fraction is not negative and take abs()*/ _fp_to_integer( /* truncate off fractional part */ _mul( /* exe = util * period */ - tsk_rt(t)->task_params.util_est, _frac(get_rt_period(t), 1) + tsk_rt(t)->zl_util_est, _frac(get_rt_period(t), 1) ) ) ) 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 { PRECISE_ENFORCEMENT /* NOT IMPLEMENTED - enforced with hrtimers */ } budget_policy_t; -#ifdef CONFIG_PLUGIN_AEDZL typedef long fpbuf_t; typedef struct { fpbuf_t val; } fp_t; -#endif struct rt_task { lt_t exec_cost; @@ -49,10 +47,9 @@ struct rt_task { task_class_t cls; budget_policy_t budget_policy; /* ignored by pfair */ -#ifdef CONFIG_PLUGIN_AEDZL - fp_t util_est; - fp_t accum_err; -#endif + /* AEDZL - feedback control parameters set by user */ + fp_t a; + fp_t b; }; /* The definition of the data that is shared between the kernel and real-time @@ -139,6 +136,10 @@ struct rt_param { unsigned int zl_timer_armed:1; /* used to trigger zero-laxity detection */ struct hrtimer zl_timer; +#ifdef CONFIG_PLUGIN_AEDZL + fp_t zl_util_est; + fp_t zl_accum_err; +#endif #endif /* 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) target->rt_param.task_params = tp; +#ifdef CONFIG_PLUGIN_AEDZL + /* default feedback parameters if not specified */ + if(target->rt_param.task_params.a.val == LITMUS_FP_ZERO.val) + target->rt_param.task_params.a.val = 104; /* 0.102 -- 102/1000 */ + if(target->rt_param.task_params.b.val == LITMUS_FP_ZERO.val) + target->rt_param.task_params.b.val = 310; /* 0.303 -- 303/1000 */ + + target->rt_param.zl_util_est = _frac(tp.exec_cost, tp.period); + target->rt_param.zl_accum_err = LITMUS_FP_ZERO; +#endif + retval = 0; out_unlock: 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) TRACE_TASK(t, "OLD cost: %llu, est cost: %llu, est util: %d.%d, est err: %d.%d\n", tsk_rt(t)->task_params.exec_cost, get_exec_cost_est(t), - _fp_to_integer(tsk_rt(t)->task_params.util_est), _point(tsk_rt(t)->task_params.util_est), - _fp_to_integer(tsk_rt(t)->task_params.accum_err), _point(tsk_rt(t)->task_params.accum_err)); + _fp_to_integer(tsk_rt(t)->zl_util_est), _point(tsk_rt(t)->zl_util_est), + _fp_to_integer(tsk_rt(t)->zl_accum_err), _point(tsk_rt(t)->zl_accum_err)); - err = _sub(actual_util, tsk_rt(t)->task_params.util_est); + err = _sub(actual_util, tsk_rt(t)->zl_util_est); /* TRACE_TASK(t, "delta err = actual - est\n" "\t%d.%d = %d.%d - %d.%d\n", _fp_to_integer(err), _point(err), _fp_to_integer(actual_util), _point(actual_util), - _fp_to_integer(tsk_rt(t)->task_params.util_est), _point(tsk_rt(t)->task_params.util_est)); + _fp_to_integer(tsk_rt(t)->zl_util_est), _point(tsk_rt(t)->zl_util_est)); */ - new = _add(_mul(a_fp, err), - _mul(b_fp, tsk_rt(t)->task_params.accum_err)); + new = _add(_mul(get_feedback_a(t), err), + _mul(get_feedback_b(t), tsk_rt(t)->zl_accum_err)); /* TRACE_TASK(t, "util est = a*(delta error) + b*(accum error)\n" "\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) _fp_to_integer(a_fp), _point(a_fp), _fp_to_integer(err), _point(err), _fp_to_integer(b_fp), _point(b_fp), - _fp_to_integer(tsk_rt(t)->task_params.accum_err), _point(tsk_rt(t)->task_params.accum_err)); + _fp_to_integer(tsk_rt(t)->zl_accum_err), _point(tsk_rt(t)->zl_accum_err)); */ - tsk_rt(t)->task_params.util_est = new; - tsk_rt(t)->task_params.accum_err = _add(tsk_rt(t)->task_params.accum_err, err); + tsk_rt(t)->zl_util_est = new; + tsk_rt(t)->zl_accum_err = _add(tsk_rt(t)->zl_accum_err, err); 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", tsk_rt(t)->task_params.exec_cost, get_exec_cost_est(t), - _fp_to_integer(tsk_rt(t)->task_params.util_est), _point(tsk_rt(t)->task_params.util_est), - _fp_to_integer(tsk_rt(t)->task_params.accum_err), _point(tsk_rt(t)->task_params.accum_err), + _fp_to_integer(tsk_rt(t)->zl_util_est), _point(tsk_rt(t)->zl_util_est), + _fp_to_integer(tsk_rt(t)->zl_accum_err), _point(tsk_rt(t)->zl_accum_err), _fp_to_integer(new), _point(new), _fp_to_integer(err), _point(err)); } -- cgit v1.2.2