diff --git a/kernel/sched/edf.c b/kernel/sched/edf.c index 09c8d6f5a807a3972a30ac4b1a4940ec3da43dd2..0b4b0c0241dac48526174d02df2508fa96ed377c 100644 --- a/kernel/sched/edf.c +++ b/kernel/sched/edf.c @@ -12,7 +12,6 @@ #include <kernel/tick.h> -#if 1 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"); } -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: * @@ -160,442 +154,7 @@ static inline void schedule_edf_reinit_task(struct task_struct *tsk, ktime now) 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> @@ -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) { - - - 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 *tmp; 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 */ if (!list_empty(&tq->new)) { - list_for_each_entry_safe(tsk, tmp, &tq->new, node) { - - if (tsk == t0) - continue; - - if (tsk->attr.policy != SCHED_EDF) - continue; - + list_for_each_entry_safe(tsk, tmp, &tq->new, node) 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 /* add all in wakeup */ struct task_struct *tmp2; if (!list_empty(&tq->wake)) { - list_for_each_entry_safe(tsk, tmp, &tq->wake, node) { - - if (tsk == t0) - continue; - - if (tsk->attr.policy != SCHED_EDF) - continue; + list_for_each_entry_safe(tsk, tmp, &tq->wake, node) 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 */ if (!list_empty(&tq->run)) { - 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; - - - 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)); - } - } + list_for_each_entry_safe(tsk, tmp, &tq->run, node) - 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(); + u += (double) (int32_t) tsk->attr.wcet / (double) (int32_t) tsk->attr.period; } - 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 + if (u > 1.0) { + printk("I am NOT schedul-ableh: %f ", u); + BUG(); + return -EINVAL; + printk("changed task mode to RR\n", u); + } else { + printk("Utilisation: %g\n", u); + return 0; } - 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) { - printk("I am NOT schedul-ableh: %f ", u); - return -EINVAL; - printk("changed task mode to RR\n", u); - } else { - printk("Utilisation: %g\n", u); - return 0; - } -// } - - u = (double) (int32_t) task->attr.wcet / (double) (int32_t) task->attr.period; -// printk("was the first task, utilisation: %g\n", u); - return 0; } @@ -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) { -// printk("checking %s\n", tsk->name); /* time to wake up yet? */ delta = ktime_delta(tsk->wakeup, now); if (delta > 0) { - /* nope, just update minimum runtime for this slot */ + /* nope, optionally adjust slice */ if (delta < slot) slot = delta; - continue; } @@ -1028,39 +288,34 @@ static struct task_struct *edf_pick_next(struct task_queue *tq) 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 wakeup must happen earlier than the next - * scheduling event, adjust the slot timeout + * scheduling event, adjust the slice */ + if (delta < slot) slot = delta; BUG_ON(delta < 0); + /* always queue it up at the tail */ list_move_tail(&tsk->node, &tq->run); - // continue; } - // if (tsk->runtime < tsk->attr.wcet) - // printk("VVV %s %lld %lld\n", tsk->name, tsk->runtime, tsk->attr.wcet); - - /* if our deadline is earlier than the deadline at the - * head of the list, move us to top */ + /* if our deadline is earlier than the deadline of the + * head of the list, we become the new head + */ first = list_first_entry(&tq->run, struct task_struct, node); if (ktime_before (tsk->wakeup, now)) { if (ktime_before (tsk->deadline - tsk->runtime, first->deadline)) { tsk->state = TASK_RUN; - // go = tsk; list_move(&tsk->node, &tq->run); - // printk("1 to top! %s\n", tsk->name); } } - // printk("1 nope %s\n", tsk->name); continue; } @@ -1068,23 +323,14 @@ static struct task_struct *edf_pick_next(struct task_queue *tq) /* time to wake up */ if (tsk->state == TASK_IDLE) { 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 * head of the list, move us to top */ 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)) { - // go = tsk; + if (ktime_before (tsk->deadline - tsk->runtime, first->deadline)) 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; } @@ -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); delta = ktime_delta(first->wakeup, now); -// if (delta <= 0) + + if (first->state == TASK_RUN) { go = first; slot = first->runtime; } -#if 1 +#if 0 /* XXX should not be needed, but needs verification! */ if (!go) { 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) } } #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; } static void edf_wake_next(struct task_queue *tq) { - struct task_struct *tsk; + ktime last; + struct task_struct *tmp; struct task_struct *task; - struct task_struct *l; - ktime last=0; - ktime per = 0; - ktime wcet = 0; + if (list_empty(&tq->wake)) return; - task = list_entry(tq->wake.next, struct task_struct, node); - - last = ktime_get(); - list_for_each_entry_safe(tsk, tmp, &tq->run, node) { - if (tsk->deadline > last) { - last = tsk->deadline; - l = tsk; - } + list_for_each_entry_safe(task, tmp, &tq->run, node) { + if (last < task->deadline) + last = task->deadline; } -// if (next->attr.policy == SCHED_EDF) -// return; -// + task = list_entry(tq->wake.next, struct task_struct, node); + + 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 + 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_dead = task->deadline; - task->state = TASK_IDLE; -// printk("---- %s %llu\n", task->name, task->first_wake); list_move_tail(&task->node, &tq->run); } @@ -1268,75 +492,28 @@ ktime edf_task_ready_ns(struct task_queue *tq) { int64_t delta; - struct task_struct *tsk; struct task_struct *tmp; - ktime now = ktime_get(); ktime wake = 123456789123LL; + ktime now = ktime_get(); -// wake = ktime_add(now, slot); 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); + if (delta <= 0) continue; - if (wake > delta) { + if (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 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"); + if (slot > wake) slot = wake; - } + BUG_ON(slot <= 0); return slot; diff --git a/tools/testing/unittest/edf/edf_test.c b/tools/testing/unittest/edf/edf_test.c index 911820d5eb93672c4146014e4bf6410514339c4a..231a133baa50865699f739a97864d17494744dfc 100644 --- a/tools/testing/unittest/edf/edf_test.c +++ b/tools/testing/unittest/edf/edf_test.c @@ -59,7 +59,7 @@ static void sched_edf_create_tasks_test(void) struct task_struct *t; struct sched_attr attr; - +#if 0 /* create task 1 */ t = kmalloc(sizeof(struct task_struct)); KSFT_ASSERT_PTR_NOT_NULL(t); @@ -73,7 +73,7 @@ static void sched_edf_create_tasks_test(void) 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(255); + t->attr.wcet = us_to_ktime(250); edf_enqueue(&t->sched->tq, t); @@ -90,7 +90,7 @@ static void sched_edf_create_tasks_test(void) t->attr.policy = SCHED_EDF; t->attr.period = us_to_ktime(800); 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); @@ -124,7 +124,7 @@ static void sched_edf_create_tasks_test(void) t->attr.policy = SCHED_EDF; t->attr.period = us_to_ktime(2000); 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); @@ -142,8 +142,94 @@ static void sched_edf_create_tasks_test(void) 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(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); +#endif + } @@ -152,7 +238,7 @@ static void sched_edf_create_tasks_test(void) * @test sched_edf_create_tasks_test */ -#define CYCLES 20000 +#define CYCLES 2000000 static void sched_edf_schedule_test(void) { @@ -169,31 +255,31 @@ static void sched_edf_schedule_test(void) curr = next; 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 */ curr->runtime = ktime_sub(curr->runtime, ktime_sub(ktime_get(), curr->exec_start)); } 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); - sched_print_edf_list_internal(&sched_edf.tq, ktime_get()); + // sched_print_edf_list_internal(&sched_edf.tq, ktime_get()); if (next) { 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 { slice = 1000000000; /* retry in 1 second */ - printk("Next: NONE\n"); + // printk("Next: NONE\n"); } 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) { - 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; } @@ -206,7 +292,7 @@ static void sched_edf_schedule_test(void) /* our timeslice has passed: assume we return in time */ 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); }