Skip to content
Snippets Groups Projects
Commit 88c53c0a authored by Armin Luntzer's avatar Armin Luntzer
Browse files

EDF in working condition

parent 0ada692d
No related branches found
No related tags found
No related merge requests found
...@@ -12,7 +12,6 @@ ...@@ -12,7 +12,6 @@
#include <kernel/tick.h> #include <kernel/tick.h>
#if 1
void sched_print_edf_list_internal(struct task_queue *tq, ktime now) void sched_print_edf_list_internal(struct task_queue *tq, ktime now)
{ {
...@@ -62,13 +61,8 @@ void sched_print_edf_list_internal(struct task_queue *tq, ktime now) ...@@ -62,13 +61,8 @@ void sched_print_edf_list_internal(struct task_queue *tq, ktime now)
printk("\n\n"); printk("\n\n");
} }
ktime total;
ktime times;
void sched_print_edf_list(void)
{
printk("avg: %lld\n", ktime_to_us(total/times));
}
#endif
/** /**
* Our EDF task scheduling timeline: * Our EDF task scheduling timeline:
* *
...@@ -160,443 +154,8 @@ static inline void schedule_edf_reinit_task(struct task_struct *tsk, ktime now) ...@@ -160,443 +154,8 @@ static inline void schedule_edf_reinit_task(struct task_struct *tsk, ktime now)
tsk->runtime = tsk->attr.wcet; tsk->runtime = tsk->attr.wcet;
} }
#if 0
#define SOME_DEFAULT_TICK_PERIOD_FOR_SCHED_MODE 10000000LL
/* stupidly sort EDFs */
/*static*/ int64_t schedule_edf(ktime now)
{
// ktime now;
int64_t delta;
int64_t slot = SOME_DEFAULT_TICK_PERIOD_FOR_SCHED_MODE;
struct task_struct *tsk;
struct task_struct *tmp;
ktime wake;
list_for_each_entry_safe(tsk, tmp, &_kthreads.run, node) {
if (tsk->attr.policy != SCHED_EDF)
continue;
/* time to wake up yet? */
delta = ktime_delta(tsk->wakeup, now);
if (delta >= 0) {
/* nope, just update minimum runtime for this slot */
if (delta < slot)
slot = delta;
continue;
}
/* if it's already running, see if there is time remaining */
if (tsk->state == TASK_RUN) {
if (!schedule_edf_can_execute(tsk, now)) {
schedule_edf_reinit_task(tsk, now);
/* nope, update minimum runtime for this slot */
delta = ktime_delta(tsk->wakeup, now);
if (delta < slot)
slot = delta;
continue;
}
/* move to top */
list_move(&tsk->node, &_kthreads.run);
continue;
}
/* time to wake up */
if (tsk->state == TASK_IDLE) {
tsk->state = TASK_RUN;
/* move to top */
list_move(&tsk->node, &_kthreads.run);
}
}
/* now find the closest relative deadline */
wake = ktime_add(now, slot);
list_for_each_entry_safe(tsk, tmp, &_kthreads.run, node) {
if (tsk->attr.policy != SCHED_EDF)
break;
/* all currently runnable task are at the top of the list */
if (tsk->state != TASK_RUN)
break;
if (ktime_before(wake, tsk->deadline))
continue;
delta = ktime_delta(wake, tsk->deadline);
if (delta < 0) {
delta = ktime_delta(now, tsk->deadline);
printk("\n [%lld] %s deadline violated by %lld us\n", ktime_to_ms(now), tsk->name, ktime_to_us(delta));
}
if (delta < slot) {
if (delta)
slot = delta;
else
delta = tsk->runtime;
wake = ktime_add(now, slot); /* update next wakeup */
/* move to top */
list_move(&tsk->node, &_kthreads.run);
BUG_ON(slot <= 0);
}
}
#if 1
total = ktime_add(total, ktime_delta(ktime_get(), now));
times++;
#endif
#if 0
printk("%3.d %3.lld\n", cnt, ktime_to_us(total / times) );
#endif
BUG_ON(slot < 0);
return slot;
}
#endif
/**
*
* we allow online task admission, so we need to be able to determine
* schedulability on the fly:
*
* EDF schedulability
*
*
* # comp time
* | deadline (== unused slot)
* _ unused slot
* > wakeup (== deadline if D == P)
* o free slots (deadline - wcet)
*
* simplest case: one long period task, one or more short period tasks
*
* W D W
* >oooooooooo##########|_____________________________> (P=50, D=20, R=10) (T1)
* >o#|_> (P= 4, D= 2, R= 1) (T2)
* >o#> (P= 2, D= 2, R= 1) (T3)
* >#> (P= 1, D= 1, R= 1) (T4)
* >ooooooo#####|_______> (P=20, D=12, R= 5) (T5)
* >oooooooooooooooooooooooooo####|__> (P=33, D=30, R= 4) (T6)
* >oooooooooooooooooooooooooooooooooooooooo######|___> (P=50, D=46, R= 6) (T7)
*
* If we map the short period task into the long period tasks "free" slots,
* we see that tasks with periods shorter than the deadline of the task
* of the longest period can only be scheduled, if their utilisation
* or "time density" R / D is smaller that the utilisation of the longest
* period task
*
*
* easily schedulable:
* ____________________________________________________________________________________________________
* .... . .. ......... . . . . . . ..... . ... ....... . . . . . . .
* >o###oooooo#oo####o##|_____________________________###oooooo##oo##o###o|_____________________________
* >#o|_o#|_o#|_#o|_o#|_#o|_o#|_o#|_#o|_o#|_o#|_o#|_o#|_o#|_o#|_o#|_o#|_o#|_o#|_o#|_o#|_o#|_o#|_o#|_o#|_
*
*
* R/D R/P
* T1: (P=50, D=20, R=10) 10/20 = 1/2 10/50 = 20/100
* T2: (P= 4, D= 2, R= 1) 1/2 = 1/2 100% 1/4 = 25/100 45% (== number of used slots)
*
*
* correct analysis sum(R_i/P_i)
*
* T1 (D-R) / D = 1/2
* T1 (D-R) / P = 1/5
*
* T2 (D-R) / P = 1/4 T1DRD > T2DRP -> R/P (correct)
*
*
*
* just schedulable:
* ____________________________________________________________________________________________________
* .................... . . . . . . . . . . . . . . ..................... . . . . . . . . . . . . . . .
* >#o#o#o#o#o#o#o#o#o#o|_____________________________#o#o#o#o#o#o#o#o#o#o|_____________________________
* >o#o#o#o#o#o#o#o#o#o#o#o#o#o#o#o#o#o#o#o#o#o#o#o#o#o#o#o#o#o#o#o#o#o#o#o#o#o#o#o#o#o#o#o#o#o#o#o#o#o#
*
* R/D R/P
* T1: (P=50, D=20, R=10) 10/20 = 1/2 10/50 = 2/10
* T3: (P= 2, D= 2, R= 1) 1/2 = 1/2 100% 1/2 = 5/10 70% (== number of used slots)
*
* -> this must be 100%, impossible to fit more slots into relative deadline of
* long task
*
* correct analysis sum(R_i/D_i)
*
* T1 (D-R) / D = 1/2
* T1 (D-R) / P = 1/5
*
* T3 (D-R) / P = 1/2 T1DRD <= T3DRP -> R/D (correct)
*
* not schedulable:
* ____________________________________________________________________________________________________
* ..........::::::::::........................................::::::::::..............................
* >oooooooooo##########|_____________________________oooooooooo##########|_____________________________
* >####################################################################################################
*
* R/D R/P
* T1: (P=50, D=20, R=10) 10/20 = 1/2 10/50 = 1/5
* T4: (P= 1, D= 1, R= 1) 1/1 = 1/1 150% 1/1 = 1/1 120%
*
* both correct, but R/P "more correct" -> actual slot usage
*
* T1 (D-R) / D = 1/2
* T1 (D-R) / P = 1/5
*
* T4 (D-R) / P = 0 T1DRD > T4DRD -> R/P (correct)
*
*
* schedulable:
*
* ____________________________________________________________________________________________________
* .................................................................................................xxx
* >o###oooooo#oo###o###|_____________________________##o###o#ooooooo###o#|_____________________________
* >#o|_#o|_o#|_#o|_#o|_#o|_#o|_#o|_#o|_#o|_#o|_#o|_#o|_#o|_#o|_#o|_#o|_#o|_#o|_#o|_#o|_#o|_#o|_#o|_#o|_
* >ooooo####oo#|_______o###oooooo##|_______o#ooo###o#oo|_______o###oooooo##|_______o###oooooo##|_______
* >ooooooooooooooooooooooooo###o#|__ooooooooo##ooppoooooooooo##ooo|__ooooooooooooooooooo###o#oooooo|__x
* >ooooooooooooooooooooooooooooooooo###o###oooooo|___ooooooooooooooooooooooo###o###ooooooooooooo###|___
*
* R/D R/P
* T1: (P=50, D=20, R=10) 10/20 50% 10/50 20%
* T2: (P= 4, D= 2, R= 1) 1/2 100% 1/4 45%
* T5: (P=20, D=12, R= 5) 5/12 142% 5/20 70%
* T6: (P=33, D=30, R= 4) 4/30 155% 4/33 82%
* T7: (P=50, D=46, R= 6) 6/46 168% 6/50 94%
*
*
*
* sum(R_i/P_i) correct, sum(R_i/D_i) absolutely incorrect!
*
* thread(p_max):
* T1 (D-R) / D = 1/2
* T1 (D-R) / P = 1/5
* ------------------
* T2 (D-R) / P = 1/4 T1DRD > T2DRP -> R/P (correct)
* T5 (D-R) / P = 7/20 T1DRD > T5DRP -> R/P (correct)
* T6 (D-R) / P = 26/33 T1RD <= T6DRP -> R/D (correct? looks ok)
* T7 (D-R) / P = 40/50 T1RD <= T6DRP -> R/D (correct? looks ok)
*
* usage: 96.4%
*
*
*
*
*
* try 1:
*
* T1: (P=50, D=20, R=10) (20%) T1DRP = 0.2 (0.95)
* TX: (P=10, D= 8, R=6) -> (D-R)/P = 0.2 T1DRD > T2DRP -> R/P (incorrect, should be R/D at least) (0.75)
* ................::..
* >##oooooo####oooo####|_____________________________
* >oo######|_oo######|_
*
* 22/20 slots used = 110%
*
* free T1 slots before deadline: D-R = 10
*
* TX runtime slots cannot be larger than that!
*
* TX runtime slots for T1 deadline periods:
*
*
* (D_x - R_x) / D_x * D_1 = 12.5 < 10 -> not schedulable
*
* sum((D_i - R_i) / D_i) * D_1 < 10 -> schedulable?
*
*
*
* i != D_1 && P_i < D_1
* sum((D_1 / P_i) * R_i) < (D_1 - R_1) ?
*
* i != D1 && P_i >
*
* (T1: 4 < 10 ok)
*
* T2: 5
* T5: 5
* T6 2.42
*
*
*
*
* new test:
*
* if (P_x < D_1) :
* if ((R_x - D_x) > 0) // otherwise we are at 100% slot usage within deadline
* (D_x - R_x) / D_x * (D_1 - R_1) = 12.5 > (D_1 - R_1) -> not schedulable
* else ?
* R_x / P_x * D_1 < (D_1 - R_1)
*
* (schedulable):
* ____________________________________________________________________________________________________
* .................................................................................................xxx
* >o###oooooo#oo###o###|_____________________________##o###o#ooooooo###o#|_____________________________
* >#o|_#o|_o#|_#o|_#o|_#o|_#o|_#o|_#o|_#o|_#o|_#o|_#o|_#o|_#o|_#o|_#o|_#o|_#o|_#o|_#o|_#o|_#o|_#o|_#o|_
* >ooooo####oo#|_______o###oooooo##|_______o#ooo###o#oo|_______o###oooooo##|_______o###oooooo##|_______
* >ooooooooooooooooooooooooo###o#|__ooooooooo##ooppoooooooooo##ooo|__ooooooooooooooooooo###o#oooooo|__x
* >ooooooooooooooooooooooooooooooooo###o###oooooo|___ooooooooooooooooooooooo###o###oooooooooooooooo|___
*
*
* T1: (P=50, D=20, R=10) -> max P -> D_1 = 20, D_1 - R_1 = 10 = F_1
*
* T2: (P= 4, D= 2, R= 1) F2 = 1 F2D = 1/2
* T5: (P=20, D=12, R= 5) F5 = 7 F5D = 7/12
* T6: (P=33, D=30, R= 4) F6 = 26 F6D = 26/30
* T7: (P=50, D=46, R= 6) F7 = 40 F7D = 40/46
*
*
* Utilisation: U1 = D_1 - R_1 = 10; U2 = P_1 - D_1 = 30
*
* check T2:
* f2 > 0 -> f2d * F1 = 5 <= U1 -> schedulable
* f2d * U2 = 10
* -> U1 = 5, U2 = 20
*
* check t5:
* f5 > 0 -> int(f5d * F1) = 5; 5 <= U1 -> schedulable
* f5d * U2 = int(11) ->
* U1 = 0, U2 = 9
*
*
* 1) determine task with longest period
*
* T1: (P=50, D=20, R=10)
*
* 2) calculate unused head and tail (before and after deadline)
*
* UH = D1 - R1 (= 20) (Hyperperiod)
* UT = P1 - D1 (= 60)
*
* 3) loop over other tasks (Period < Deadline of Task 1)
*
* calculate slots usage before deadline of Task 1:
*
* H * Ri * D1 / Pi (T2: 10, T5: 10)
*
* update head slots UH = UH - 20 = 0 -> all used
*
*
* calculate slot usage after deadline of Task2:
*
* H * Ri * F1 / Pi (T2: 15, T5: 15)
*
* update tail slots: UT = UT - 30 = 30
*
* -> need hyperperiod factor H = 2
*
*
*
* if (DEADLINE >
* ____________________________________________________________________________________________________
* ......................... . ............ .............. ......................... . ... .
* >o###oooooo#oo###o###|_____________________________##o###o#ooooooo###o#|_____________________________
* >#o|_#o|_o#|_#o|_#o|_#o|_#o|_#o|_#o|_#o|_#o|_#o|_#o|_#o|_#o|_#o|_#o|_#o|_#o|_#o|_#o|_#o|_#o|_#o|_#o|_
* >ooooo####oo#|_______o###oooooo##|_______o#ooo###o#oo|_______o###oooooo##|_______o###oooooo##|_______
* >ooooooooooooooooooooooooooooooooo###o###oooooo|___ooooooooooooooooooooooo###o###oooooooooooooooo|___
*
*
*
*/
static ktime edf_hyperperiod(struct task_queue *tq)
{
ktime lcm = 0;
ktime a,b;
struct task_struct *t0;
struct task_struct *tsk;
struct task_struct *tmp;
if (list_empty(&tq->new))
return 0;
t0 = list_entry(tq->new.next, struct task_struct, node);
lcm = t0->attr.period;
list_for_each_entry_safe(tsk, tmp, &tq->new, node) {
if (tsk == t0)
continue;
a = lcm;
b = tsk->attr.period;
/* already a multiple? */
if (a % b == 0)
continue;
while (a != b) {
if (a > b)
a -= b;
else
b -= a;
}
lcm = lcm * (tsk->attr.period / a);
}
/* argh, need to consider everything */
list_for_each_entry_safe(tsk, tmp, &tq->run, node) {
a = lcm;
b = tsk->attr.period;
/* already a multiple? */
if (a % b == 0)
continue;
while (a != b) {
if (a > b)
a -= b;
else
b -= a;
}
lcm = lcm * (tsk->attr.period / a);
}
/* meh ... */
list_for_each_entry_safe(tsk, tmp, &tq->wake, node) {
a = lcm;
b = tsk->attr.period;
/* already a multiple? */
if (a % b == 0)
continue;
while (a != b) {
if (a > b)
a -= b;
else
b -= a;
}
lcm = lcm * (tsk->attr.period / a);
}
return lcm;
}
/**** NEW EDF ****/
#include <kernel/init.h> #include <kernel/init.h>
#define MSG "SCHED_EDF: " #define MSG "SCHED_EDF: "
...@@ -638,145 +197,17 @@ static ktime edf_hyperperiod(struct task_queue *tq) ...@@ -638,145 +197,17 @@ static ktime edf_hyperperiod(struct task_queue *tq)
static int edf_schedulable(struct task_queue *tq, const struct task_struct *task) static int edf_schedulable(struct task_queue *tq, const struct task_struct *task)
{ {
ktime p = edf_hyperperiod(tq);
ktime h ;
ktime max = 0;
ktime uh, ut, f1;
ktime sh = 0, st = 0;
ktime stmin = 0x7fffffffffffffULL;
ktime shmin = 0x7fffffffffffffULL;
struct task_struct *t0 = NULL;
struct task_struct *tsk = NULL; struct task_struct *tsk = NULL;
struct task_struct *tmp; struct task_struct *tmp;
double u = 0.0; /* utilisation */ double u = 0.0; /* utilisation */
static int64_t dmin = 0x7fffffffffffffLL;
// printk("\nvvvv EDF analysis vvvv (%lld us) \n\n", ktime_to_us(p));
/* list_empty(....) */
if (p <= 0)
printk("appears to be empty\n");
list_for_each_entry_safe(tsk, tmp, &tq->new, node) {
if (tsk->attr.period > max) {
t0 = tsk;
max = tsk->attr.period;
}
if (dmin > tsk->attr.deadline_rel)
dmin = tsk->attr.deadline_rel;
}
list_for_each_entry_safe(tsk, tmp, &tq->wake, node) {
if (tsk->attr.period > max) {
t0 = tsk;
max = tsk->attr.period;
}
if (dmin > tsk->attr.deadline_rel)
dmin = tsk->attr.deadline_rel;
}
list_for_each_entry_safe(tsk, tmp, &tq->run, node) {
if (tsk->attr.period > max) {
t0 = tsk;
max = tsk->attr.period;
}
if (dmin > tsk->attr.deadline_rel)
dmin = tsk->attr.deadline_rel;
}
BUG_ON(!t0);
BUG_ON(p < t0->attr.period);
h = p / t0->attr.period;
printk("Period factor %lld, duration %lld actual period: %lld\n", h, ktime_to_us(p), ktime_to_us(t0->attr.period));
uh = h * (t0->attr.deadline_rel - t0->attr.wcet);
ut = h * (t0->attr.period - t0->attr.deadline_rel);
f1 = ut/h;
printk("max UH: %lld, UT: %lld\n", ktime_to_us(uh), ktime_to_us(ut));
/* subtract longest period thread from head, its slices must always
* be used before the deadline
*/
sh = h * t0->attr.wcet * t0->attr.deadline_rel / t0->attr.period;
if (sh < shmin)
shmin = sh;
uh = uh - sh;
printk("%s UH: %lld, UT: %lld\n", t0->name, ktime_to_us(uh), ktime_to_us(ut));
printk("%s SH: %lld, ST: %lld\n", t0->name, ktime_to_us(sh), ktime_to_us(st));
/* add all in new */ /* add all in new */
if (!list_empty(&tq->new)) { if (!list_empty(&tq->new)) {
list_for_each_entry_safe(tsk, tmp, &tq->new, node) { list_for_each_entry_safe(tsk, tmp, &tq->new, node)
if (tsk == t0)
continue;
if (tsk->attr.policy != SCHED_EDF)
continue;
u += (double) (int32_t) tsk->attr.wcet / (double) (int32_t) tsk->attr.period; u += (double) (int32_t) tsk->attr.wcet / (double) (int32_t) tsk->attr.period;
if (tsk->attr.deadline_rel <= t0->attr.deadline_rel) {
/* slots before deadline of T0 */
sh = h * tsk->attr.wcet * t0->attr.deadline_rel / tsk->attr.period;
if (sh < shmin)
shmin = sh;
#if 0
if (sh > uh) {
printk("NOT SCHEDULABLE in head: %s\n", tsk->name);
BUG();
}
#endif
uh = uh - sh;
}
/* slots after deadline of T0 */
st = h * tsk->attr.wcet * f1 / tsk->attr.period;
if (st < stmin)
stmin = st;
// printk("%s tail usage: %lld\n", tsk->name, ktime_to_ms(st));
#if 0
if (st > ut) {
printk("NOT SCHEDULABLE in tail: %s\n", tsk->name);
BUG();
}
#endif
ut = ut - st;
printk("w %s UH: %lld, UT: %lld\n", tsk->name, ktime_to_us(uh), ktime_to_us(ut));
printk("w %s SH: %lld, ST: %lld\n", tsk->name, ktime_to_us(sh), ktime_to_us(st));
}
} }
...@@ -784,204 +215,35 @@ static int edf_schedulable(struct task_queue *tq, const struct task_struct *task ...@@ -784,204 +215,35 @@ static int edf_schedulable(struct task_queue *tq, const struct task_struct *task
/* add all in wakeup */ /* add all in wakeup */
struct task_struct *tmp2; struct task_struct *tmp2;
if (!list_empty(&tq->wake)) { if (!list_empty(&tq->wake)) {
list_for_each_entry_safe(tsk, tmp, &tq->wake, node) { list_for_each_entry_safe(tsk, tmp, &tq->wake, node)
if (tsk == t0)
continue;
if (tsk->attr.policy != SCHED_EDF)
continue;
u += (double) (int32_t) tsk->attr.wcet / (double) (int32_t) tsk->attr.period; u += (double) (int32_t) tsk->attr.wcet / (double) (int32_t) tsk->attr.period;
if (tsk->attr.deadline_rel <= t0->attr.deadline_rel) {
/* slots before deadline of T0 */
sh = h * tsk->attr.wcet * t0->attr.deadline_rel / tsk->attr.period;
if (sh < shmin)
shmin = sh;
#if 0
if (sh > uh) {
printk("NOT SCHEDULABLE in head: %s\n", tsk->name);
BUG();
}
#endif
uh = uh - sh;
}
/* slots after deadline of T0 */
st = h * tsk->attr.wcet * f1 / tsk->attr.period;
if (st < stmin)
stmin = st;
// printk("%s tail usage: %lld\n", tsk->name, ktime_to_ms(st));
#if 0
if (st > ut) {
printk("NOT SCHEDULABLE in tail: %s\n", tsk->name);
BUG();
}
#endif
ut = ut - st;
printk("w %s UH: %lld, UT: %lld\n", tsk->name, ktime_to_us(uh), ktime_to_us(ut));
printk("w %s SH: %lld, ST: %lld\n", tsk->name, ktime_to_us(sh), ktime_to_us(st));
}
} }
/* add all running */ /* add all running */
if (!list_empty(&tq->run)) { if (!list_empty(&tq->run)) {
list_for_each_entry_safe(tsk, tmp, &tq->run, node) { list_for_each_entry_safe(tsk, tmp, &tq->run, node)
if (tsk == t0)
continue;
if (tsk->attr.policy != SCHED_EDF)
continue;
u += (double) (int32_t) tsk->attr.wcet / (double) (int32_t) tsk->attr.period; u += (double) (int32_t) tsk->attr.wcet / (double) (int32_t) tsk->attr.period;
if (tsk->attr.deadline_rel <= t0->attr.deadline_rel) {
/* slots before deadline of T0 */
sh = h * tsk->attr.wcet * t0->attr.deadline_rel / tsk->attr.period;
if (sh < shmin)
shmin = sh;
#if 0
if (sh > uh) {
printk("NOT SCHEDULABLE in head: %s\n", tsk->name);
BUG();
}
#endif
uh = uh - sh;
} }
/* slots after deadline of T0 */
st = h * tsk->attr.wcet * f1 / tsk->attr.period;
if (st < stmin)
stmin = st;
// printk("%s tail usage: %lld\n", tsk->name, ktime_to_ms(st));
//
#if 0
if (st > ut) {
printk("NOT SCHEDULABLE in tail: %s\n", tsk->name);
BUG();
}
#endif
ut = ut - st;
printk("r UH: %lld, UT: %lld\n", ktime_to_us(uh), ktime_to_us(ut));
printk("r SH: %lld, ST: %lld\n", ktime_to_us(sh), ktime_to_us(st));
}
}
printk("r SH: %lld (%lld), ST: %lld (%lld)\n", ktime_to_us(uh / h), uh, ktime_to_us(ut / h), ut);
if (ut <= 0) {
printk("NOT SCHEDULABLE in tail: %s %lld\n", task->name, ut);
BUG();
}
if (uh <= 0) {
printk("NOT SCHEDULABLE in head: %s %lld\n", task->name, uh);
BUG();
}
static int cnt;
if (cnt) {
#if 1
if (ut <= stmin) {
printk("xx NOT SCHEDULABLE in tail: %s %lld vs %lld\n", task->name, ut, stmin);
// BUG();
}
#endif
#if 0
if (uh <= shmin) {
printk("xx NOT SCHEDULABLE in head: %s %lld vs %lld \n", task->name, uh, shmin);
// BUG();
}
#endif
}
cnt++;
#if 0
//list_for_each_entry_safe(tsk, tmp, &tq->new, node)
{
tsk = t0;
ktime sh, st;
// if (tsk == t0)
// continue;
if (tsk->attr.deadline_rel < t0->attr.deadline_rel) {
/* slots before deadline of T0 */
sh = h * tsk->attr.wcet * t0->attr.deadline_rel / tsk->attr.period;
if (sh > uh) {
printk("NOT SCHEDULABLE in head: %s\n", tsk->name);
BUG();
}
uh = uh - sh;
}
/* slots after deadline of T0 */
st = h * tsk->attr.wcet * f1 / tsk->attr.period;
// printk("%s tail usage: %lld\n", tsk->name, ktime_to_ms(st));
if (st > ut) {
printk("NOT SCHEDULABLE in tail: %s\n", tsk->name);
BUG();
}
ut = ut - st;
printk("UH: %lld, UT: %lld\n", ktime_to_us(uh), ktime_to_us(ut));
printk("SH: %lld, ST: %lld\n", ktime_to_us(sh), ktime_to_us(st));
if (dmin > task->attr.deadline_rel)
dmin = task->attr.deadline_rel;
u += (double) (int32_t) task->attr.wcet / (double) (int32_t) task->attr.period;
#endif
if (u > 1.0) { if (u > 1.0) {
printk("I am NOT schedul-ableh: %f ", u); printk("I am NOT schedul-ableh: %f ", u);
BUG();
return -EINVAL; return -EINVAL;
printk("changed task mode to RR\n", u); printk("changed task mode to RR\n", u);
} else { } else {
printk("Utilisation: %g\n", u); printk("Utilisation: %g\n", u);
return 0; return 0;
} }
// }
u = (double) (int32_t) task->attr.wcet / (double) (int32_t) task->attr.period; u = (double) (int32_t) task->attr.wcet / (double) (int32_t) task->attr.period;
// printk("was the first task, utilisation: %g\n", u);
return 0; return 0;
} }
...@@ -1007,18 +269,16 @@ static struct task_struct *edf_pick_next(struct task_queue *tq) ...@@ -1007,18 +269,16 @@ static struct task_struct *edf_pick_next(struct task_queue *tq)
list_for_each_entry_safe(tsk, tmp, &tq->run, node) { list_for_each_entry_safe(tsk, tmp, &tq->run, node) {
// printk("checking %s\n", tsk->name);
/* time to wake up yet? */ /* time to wake up yet? */
delta = ktime_delta(tsk->wakeup, now); delta = ktime_delta(tsk->wakeup, now);
if (delta > 0) { if (delta > 0) {
/* nope, just update minimum runtime for this slot */ /* nope, optionally adjust slice */
if (delta < slot) if (delta < slot)
slot = delta; slot = delta;
continue; continue;
} }
...@@ -1028,39 +288,34 @@ static struct task_struct *edf_pick_next(struct task_queue *tq) ...@@ -1028,39 +288,34 @@ static struct task_struct *edf_pick_next(struct task_queue *tq)
if (!schedule_edf_can_execute(tsk, now)) { if (!schedule_edf_can_execute(tsk, now)) {
schedule_edf_reinit_task(tsk, now); schedule_edf_reinit_task(tsk, now);
/* nope, update minimum runtime for this slot */
delta = ktime_delta(tsk->wakeup, now); delta = ktime_delta(tsk->wakeup, now);
/* if wakeup must happen earlier than the next /* if wakeup must happen earlier than the next
* scheduling event, adjust the slot timeout * scheduling event, adjust the slice
*/ */
if (delta < slot) if (delta < slot)
slot = delta; slot = delta;
BUG_ON(delta < 0); BUG_ON(delta < 0);
/* always queue it up at the tail */
list_move_tail(&tsk->node, &tq->run); list_move_tail(&tsk->node, &tq->run);
// continue;
} }
// if (tsk->runtime < tsk->attr.wcet) /* if our deadline is earlier than the deadline of the
// printk("VVV %s %lld %lld\n", tsk->name, tsk->runtime, tsk->attr.wcet); * head of the list, we become the new head
*/
/* if our deadline is earlier than the deadline at the
* head of the list, move us to top */
first = list_first_entry(&tq->run, struct task_struct, node); first = list_first_entry(&tq->run, struct task_struct, node);
if (ktime_before (tsk->wakeup, now)) { if (ktime_before (tsk->wakeup, now)) {
if (ktime_before (tsk->deadline - tsk->runtime, first->deadline)) { if (ktime_before (tsk->deadline - tsk->runtime, first->deadline)) {
tsk->state = TASK_RUN; tsk->state = TASK_RUN;
// go = tsk;
list_move(&tsk->node, &tq->run); list_move(&tsk->node, &tq->run);
// printk("1 to top! %s\n", tsk->name);
} }
} }
// printk("1 nope %s\n", tsk->name);
continue; continue;
} }
...@@ -1068,23 +323,14 @@ static struct task_struct *edf_pick_next(struct task_queue *tq) ...@@ -1068,23 +323,14 @@ static struct task_struct *edf_pick_next(struct task_queue *tq)
/* time to wake up */ /* time to wake up */
if (tsk->state == TASK_IDLE) { if (tsk->state == TASK_IDLE) {
tsk->state = TASK_RUN; tsk->state = TASK_RUN;
/* move to top */
// printk("%s now in state RUN\n", tsk->name);
/* if our deadline is earlier than the deadline at the /* if our deadline is earlier than the deadline at the
* head of the list, move us to top */ * head of the list, move us to top */
first = list_first_entry(&tq->run, struct task_struct, node); first = list_first_entry(&tq->run, struct task_struct, node);
//if (ktime_before (tsk->deadline, first->deadline)) { if (ktime_before (tsk->deadline - tsk->runtime, first->deadline))
if (ktime_before (tsk->deadline - tsk->runtime, first->deadline)) {
// go = tsk;
list_move(&tsk->node, &tq->run); list_move(&tsk->node, &tq->run);
// printk("%s has earlier deadline, moved to top\n", tsk->name);
}
// printk("2 nope %s\n", tsk->name);
continue; continue;
} }
...@@ -1093,13 +339,14 @@ static struct task_struct *edf_pick_next(struct task_queue *tq) ...@@ -1093,13 +339,14 @@ static struct task_struct *edf_pick_next(struct task_queue *tq)
first = list_first_entry(&tq->run, struct task_struct, node); first = list_first_entry(&tq->run, struct task_struct, node);
delta = ktime_delta(first->wakeup, now); delta = ktime_delta(first->wakeup, now);
// if (delta <= 0)
if (first->state == TASK_RUN) { if (first->state == TASK_RUN) {
go = first; go = first;
slot = first->runtime; slot = first->runtime;
} }
#if 1 #if 0 /* XXX should not be needed, but needs verification! */
if (!go) { if (!go) {
list_for_each_entry_safe(tsk, tmp, &tq->run, node) { list_for_each_entry_safe(tsk, tmp, &tq->run, node) {
...@@ -1115,65 +362,42 @@ static struct task_struct *edf_pick_next(struct task_queue *tq) ...@@ -1115,65 +362,42 @@ static struct task_struct *edf_pick_next(struct task_queue *tq)
} }
} }
#endif #endif
// if (!go)
// printk("NULL\n");
// printk("in %llu\n", ktime_to_ms(slot));
#if 0
/** XXX **/
tsk = list_entry(tq->run.next, struct task_struct, node);
if (tsk->state == TASK_RUN)
return tsk;
else
#endif
return go; return go;
} }
static void edf_wake_next(struct task_queue *tq) static void edf_wake_next(struct task_queue *tq)
{ {
struct task_struct *tsk; ktime last;
struct task_struct *tmp; struct task_struct *tmp;
struct task_struct *task; struct task_struct *task;
struct task_struct *l;
ktime last=0;
ktime per = 0;
ktime wcet = 0;
if (list_empty(&tq->wake)) if (list_empty(&tq->wake))
return; return;
task = list_entry(tq->wake.next, struct task_struct, node);
last = ktime_get(); last = ktime_get();
list_for_each_entry_safe(tsk, tmp, &tq->run, node) { list_for_each_entry_safe(task, tmp, &tq->run, node) {
if (tsk->deadline > last) { if (last < task->deadline)
last = tsk->deadline; last = task->deadline;
l = tsk;
}
} }
// if (next->attr.policy == SCHED_EDF) task = list_entry(tq->wake.next, struct task_struct, node);
// return;
// task->state = TASK_IDLE;
/* initially furthest deadline as wakeup */
task->wakeup = l->deadline, task->attr.period;
// task->wakeup = ktime_add(l->deadline, task->attr.period);
/* add overhead */
// task->wakeup = ktime_add(task->wakeup, 50000UL);
#if 0
task->wakeup = ktime_add(task->wakeup, per);
#endif
/* initially furthest deadline as wakeup */
task->wakeup = ktime_add(last, task->attr.period);
task->deadline = ktime_add(task->wakeup, task->attr.deadline_rel); task->deadline = ktime_add(task->wakeup, task->attr.deadline_rel);
/* XXX unneeded, remove */
task->first_wake = task->wakeup; task->first_wake = task->wakeup;
task->first_dead = task->deadline; task->first_dead = task->deadline;
task->state = TASK_IDLE;
// printk("---- %s %llu\n", task->name, task->first_wake);
list_move_tail(&task->node, &tq->run); list_move_tail(&task->node, &tq->run);
} }
...@@ -1268,75 +492,28 @@ ktime edf_task_ready_ns(struct task_queue *tq) ...@@ -1268,75 +492,28 @@ ktime edf_task_ready_ns(struct task_queue *tq)
{ {
int64_t delta; int64_t delta;
struct task_struct *tsk; struct task_struct *tsk;
struct task_struct *tmp; struct task_struct *tmp;
ktime now = ktime_get();
ktime wake = 123456789123LL; ktime wake = 123456789123LL;
ktime now = ktime_get();
// wake = ktime_add(now, slot);
list_for_each_entry_safe(tsk, tmp, &tq->run, node) { list_for_each_entry_safe(tsk, tmp, &tq->run, node) {
#if 0
if (tsk->state == TASK_IDLE)
continue;
#endif
delta = ktime_delta(tsk->wakeup, now); delta = ktime_delta(tsk->wakeup, now);
if (delta <= 0) if (delta <= 0)
continue; continue;
if (wake > delta) { if (wake > delta)
wake = delta; wake = delta;
printk("delta for %s is %lld because now: %lld wake %lld\n",
tsk->name, ktime_to_us(delta), ktime_to_us(now), ktime_to_us(tsk->wakeup));
} }
if (slot > wake)
#if 0
/* all currently runnable task are at the top of the list */
if (tsk->state != TASK_RUN)
break;
#endif
#if 0
if (ktime_before(wake, tsk->wakeup))
continue;
delta = ktime_delta(wake, tsk->wakeup);
if (delta < 0) {
delta = ktime_delta(now, tsk->wakeup);
printk("\n [%lld] %s wakeup violated by %lld us\n", ktime_to_ms(now), tsk->name, ktime_to_us(delta));
}
if (delta < slot) {
if (delta)
slot = delta;
else
delta = tsk->runtime;
// wake = ktime_add(now, slot); /* update next wakeup */
/* move to top */
// list_move(&tsk->node, &tq->run);
BUG_ON(slot <= 0);
}
#endif
}
/* subtract call overhead */
// slot = wake;
//slot = ktime_sub(slot, 10000ULL);
//slot = ktime_sub(slot, 2000ULL);
//
if (slot > wake) {
printk("\nvvvvvvvvvvvvvvv\n");
printk("Slice adjusted from %lld to %lld (%lld)\n", ktime_to_us(slot), ktime_to_us(wake), ktime_to_us(wake - slot));
printk("\n^^^^^^^^^^^^^^^\n");
slot = wake; slot = wake;
}
BUG_ON(slot <= 0); BUG_ON(slot <= 0);
return slot; return slot;
......
...@@ -59,7 +59,7 @@ static void sched_edf_create_tasks_test(void) ...@@ -59,7 +59,7 @@ static void sched_edf_create_tasks_test(void)
struct task_struct *t; struct task_struct *t;
struct sched_attr attr; struct sched_attr attr;
#if 0
/* create task 1 */ /* create task 1 */
t = kmalloc(sizeof(struct task_struct)); t = kmalloc(sizeof(struct task_struct));
KSFT_ASSERT_PTR_NOT_NULL(t); KSFT_ASSERT_PTR_NOT_NULL(t);
...@@ -73,7 +73,7 @@ static void sched_edf_create_tasks_test(void) ...@@ -73,7 +73,7 @@ static void sched_edf_create_tasks_test(void)
t->attr.policy = SCHED_EDF; t->attr.policy = SCHED_EDF;
t->attr.period = us_to_ktime(1000); t->attr.period = us_to_ktime(1000);
t->attr.deadline_rel = us_to_ktime(900); t->attr.deadline_rel = us_to_ktime(900);
t->attr.wcet = us_to_ktime(255); t->attr.wcet = us_to_ktime(250);
edf_enqueue(&t->sched->tq, t); edf_enqueue(&t->sched->tq, t);
...@@ -90,7 +90,7 @@ static void sched_edf_create_tasks_test(void) ...@@ -90,7 +90,7 @@ static void sched_edf_create_tasks_test(void)
t->attr.policy = SCHED_EDF; t->attr.policy = SCHED_EDF;
t->attr.period = us_to_ktime(800); t->attr.period = us_to_ktime(800);
t->attr.deadline_rel = us_to_ktime(700); t->attr.deadline_rel = us_to_ktime(700);
t->attr.wcet = us_to_ktime(89); t->attr.wcet = us_to_ktime(90);
edf_enqueue(&t->sched->tq, t); edf_enqueue(&t->sched->tq, t);
...@@ -124,7 +124,7 @@ static void sched_edf_create_tasks_test(void) ...@@ -124,7 +124,7 @@ static void sched_edf_create_tasks_test(void)
t->attr.policy = SCHED_EDF; t->attr.policy = SCHED_EDF;
t->attr.period = us_to_ktime(2000); t->attr.period = us_to_ktime(2000);
t->attr.deadline_rel = us_to_ktime(900); t->attr.deadline_rel = us_to_ktime(900);
t->attr.wcet = us_to_ktime(125); t->attr.wcet = us_to_ktime(202);
edf_enqueue(&t->sched->tq, t); edf_enqueue(&t->sched->tq, t);
...@@ -142,8 +142,94 @@ static void sched_edf_create_tasks_test(void) ...@@ -142,8 +142,94 @@ static void sched_edf_create_tasks_test(void)
t->attr.policy = SCHED_EDF; t->attr.policy = SCHED_EDF;
t->attr.period = us_to_ktime(1000); t->attr.period = us_to_ktime(1000);
t->attr.deadline_rel = us_to_ktime(900); t->attr.deadline_rel = us_to_ktime(900);
t->attr.wcet = us_to_ktime(99); t->attr.wcet = us_to_ktime(199);
edf_enqueue(&t->sched->tq, t);
/* create task 6 */
t = kmalloc(sizeof(struct task_struct));
KSFT_ASSERT_PTR_NOT_NULL(t);
t->name = kmalloc(32);
KSFT_ASSERT_PTR_NOT_NULL(t->name);
snprintf(t->name, 32, "task_6");
t->sched = &sched_edf;
t->attr.policy = SCHED_EDF;
t->attr.period = us_to_ktime(24960);
t->attr.deadline_rel = us_to_ktime(11000);
t->attr.wcet = us_to_ktime(104);
edf_enqueue(&t->sched->tq, t);
#else
/* create task 1 */
t = kmalloc(sizeof(struct task_struct));
KSFT_ASSERT_PTR_NOT_NULL(t);
t->name = kmalloc(32);
KSFT_ASSERT_PTR_NOT_NULL(t->name);
snprintf(t->name, 32, "task_1");
t->sched = &sched_edf;
t->attr.policy = SCHED_EDF;
t->attr.period = us_to_ktime(1000);
t->attr.deadline_rel = us_to_ktime(900);
t->attr.wcet = us_to_ktime(250);
edf_enqueue(&t->sched->tq, t);
/* create task 2 */
t = kmalloc(sizeof(struct task_struct));
KSFT_ASSERT_PTR_NOT_NULL(t);
t->name = kmalloc(32);
KSFT_ASSERT_PTR_NOT_NULL(t->name);
snprintf(t->name, 32, "task_2");
t->sched = &sched_edf;
t->attr.policy = SCHED_EDF;
t->attr.period = us_to_ktime(1500);
t->attr.deadline_rel = us_to_ktime(400);
t->attr.wcet = us_to_ktime(300);
edf_enqueue(&t->sched->tq, t);
/* create task 3 */
t = kmalloc(sizeof(struct task_struct));
KSFT_ASSERT_PTR_NOT_NULL(t);
t->name = kmalloc(32);
KSFT_ASSERT_PTR_NOT_NULL(t->name);
snprintf(t->name, 32, "task_3");
t->sched = &sched_edf;
t->attr.policy = SCHED_EDF;
t->attr.period = us_to_ktime(30);
t->attr.deadline_rel = us_to_ktime(20);
t->attr.wcet = us_to_ktime(10);
edf_enqueue(&t->sched->tq, t);
/* create task 4 */
t = kmalloc(sizeof(struct task_struct));
KSFT_ASSERT_PTR_NOT_NULL(t);
t->name = kmalloc(32);
KSFT_ASSERT_PTR_NOT_NULL(t->name);
snprintf(t->name, 32, "task_3");
t->sched = &sched_edf;
t->attr.policy = SCHED_EDF;
t->attr.period = us_to_ktime(3000);
t->attr.deadline_rel = us_to_ktime(900);
t->attr.wcet = us_to_ktime(100);
edf_enqueue(&t->sched->tq, t); edf_enqueue(&t->sched->tq, t);
#endif
} }
...@@ -152,7 +238,7 @@ static void sched_edf_create_tasks_test(void) ...@@ -152,7 +238,7 @@ static void sched_edf_create_tasks_test(void)
* @test sched_edf_create_tasks_test * @test sched_edf_create_tasks_test
*/ */
#define CYCLES 20000 #define CYCLES 2000000
static void sched_edf_schedule_test(void) static void sched_edf_schedule_test(void)
{ {
...@@ -169,31 +255,31 @@ static void sched_edf_schedule_test(void) ...@@ -169,31 +255,31 @@ static void sched_edf_schedule_test(void)
curr = next; curr = next;
if (curr) { if (curr) {
printk("started: %lld now %lld\n", curr->exec_start, ktime_get()); // printk("started: %lld now %lld\n", curr->exec_start, ktime_get());
/* remove runtime of slice from curr */ /* remove runtime of slice from curr */
curr->runtime = ktime_sub(curr->runtime, ktime_sub(ktime_get(), curr->exec_start)); curr->runtime = ktime_sub(curr->runtime, ktime_sub(ktime_get(), curr->exec_start));
} }
edf_wake_next(&sched_edf.tq); edf_wake_next(&sched_edf.tq);
sched_print_edf_list_internal(&sched_edf.tq, ktime_get()); // sched_print_edf_list_internal(&sched_edf.tq, ktime_get());
next = edf_pick_next(&sched_edf.tq); next = edf_pick_next(&sched_edf.tq);
sched_print_edf_list_internal(&sched_edf.tq, ktime_get()); // sched_print_edf_list_internal(&sched_edf.tq, ktime_get());
if (next) { if (next) {
slice = next->runtime; slice = next->runtime;
printk("Next: %s slice %lld\n", next->name, ktime_to_us(slice)); // printk("Next: %s slice %lld\n", next->name, ktime_to_us(slice));
} else { } else {
slice = 1000000000; /* retry in 1 second */ slice = 1000000000; /* retry in 1 second */
printk("Next: NONE\n"); // printk("Next: NONE\n");
} }
wake = edf_task_ready_ns(&sched_edf.tq); wake = edf_task_ready_ns(&sched_edf.tq);
printk("New task ready in %llu\n", ktime_to_us(wake)); // printk("New task ready in %llu\n", ktime_to_us(wake));
if (wake < slice) { if (wake < slice) {
printk("reducing slice from %lld to %lld (%lld)\n", ktime_to_us(slice), ktime_to_us(wake), ktime_to_us(wake - slice)); // printk("reducing slice from %lld to %lld (%lld)\n", ktime_to_us(slice), ktime_to_us(wake), ktime_to_us(wake - slice));
slice = wake; slice = wake;
} }
...@@ -206,7 +292,7 @@ static void sched_edf_schedule_test(void) ...@@ -206,7 +292,7 @@ static void sched_edf_schedule_test(void)
/* our timeslice has passed: assume we return in time */ /* our timeslice has passed: assume we return in time */
kernel_time += slice; kernel_time += slice;
printk("\npretending slice of %lld\n", ktime_to_us(slice)); // printk("\npretending slice of %lld\n", ktime_to_us(slice));
ktime_wrap_set_time(kernel_time); ktime_wrap_set_time(kernel_time);
} }
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment