From: Con Kolivas I've ironed out all the rough spots I could find and implemented most of what I wanted. It might need more tuning from here but works very well at the moment and I'm not getting any bad reports from the people I have testing it. It *might* still cause slight jerkiness in mouse response with lots of forked processes, but it is acceptable. This is the same as the one posted yesterday with comments and cleanups. 25-akpm/include/linux/sched.h | 1 25-akpm/kernel/sched.c | 80 +++++++++++++++++++++++++++++++++++------- 2 files changed, 69 insertions(+), 12 deletions(-) diff -puN include/linux/sched.h~o1-interactivity include/linux/sched.h --- 25/include/linux/sched.h~o1-interactivity Tue Jul 8 13:40:59 2003 +++ 25-akpm/include/linux/sched.h Tue Jul 8 13:40:59 2003 @@ -340,6 +340,7 @@ struct task_struct { prio_array_t *array; unsigned long sleep_avg; + unsigned long avg_start; unsigned long last_run; unsigned long policy; diff -puN kernel/sched.c~o1-interactivity kernel/sched.c --- 25/kernel/sched.c~o1-interactivity Tue Jul 8 13:40:59 2003 +++ 25-akpm/kernel/sched.c Tue Jul 8 13:41:01 2003 @@ -73,6 +73,7 @@ #define EXIT_WEIGHT 3 #define PRIO_BONUS_RATIO 25 #define INTERACTIVE_DELTA 2 +#define MIN_SLEEP_AVG (HZ) #define MAX_SLEEP_AVG (10*HZ) #define STARVATION_LIMIT (10*HZ) #define NODE_THRESHOLD 125 @@ -297,6 +298,26 @@ static inline void enqueue_task(struct t array->nr_active++; p->array = array; } +/* + * normalise_sleep converts a task's sleep_avg to + * an appropriate proportion of MIN_SLEEP_AVG. + */ +static inline void normalise_sleep(task_t *p) +{ + unsigned long old_avg_time = jiffies - p->avg_start; + + if (old_avg_time < MIN_SLEEP_AVG) + return; + + if (p->sleep_avg > MAX_SLEEP_AVG) + p->sleep_avg = MAX_SLEEP_AVG; + + if (old_avg_time > MAX_SLEEP_AVG) + old_avg_time = MAX_SLEEP_AVG; + + p->sleep_avg = p->sleep_avg * MIN_SLEEP_AVG / old_avg_time; + p->avg_start = jiffies - MIN_SLEEP_AVG; +} /* * effective_prio - return the priority that is based on the static @@ -315,11 +336,28 @@ static inline void enqueue_task(struct t static int effective_prio(task_t *p) { int bonus, prio; + unsigned long sleep_period; if (rt_task(p)) return p->prio; - bonus = MAX_USER_PRIO*PRIO_BONUS_RATIO*p->sleep_avg/MAX_SLEEP_AVG/100 - + sleep_period = jiffies - p->avg_start; + + if (unlikely(!sleep_period)) + return p->static_prio; + + if (sleep_period > MAX_SLEEP_AVG) + sleep_period = MAX_SLEEP_AVG; + + if (p->sleep_avg > sleep_period) + sleep_period = p->sleep_avg; + + /* + * The bonus is determined according to the accumulated + * sleep avg over the duration the task has been running + * until it reaches MAX_SLEEP_AVG. -ck + */ + bonus = MAX_USER_PRIO*PRIO_BONUS_RATIO*p->sleep_avg/sleep_period/100 - MAX_USER_PRIO*PRIO_BONUS_RATIO/100/2; prio = p->static_prio - bonus; @@ -350,7 +388,7 @@ static inline void activate_task(task_t long sleep_time = jiffies - p->last_run - 1; if (sleep_time > 0) { - int sleep_avg; + unsigned long runtime = jiffies - p->avg_start; /* * This code gives a bonus to interactive tasks. @@ -360,20 +398,36 @@ static inline void activate_task(task_t * spends sleeping, the higher the average gets - and the * higher the priority boost gets as well. */ - sleep_avg = p->sleep_avg + sleep_time; + p->sleep_avg += sleep_time; + /* + * Give a bonus to tasks that wake early on to prevent + * the problem of the denominator in the bonus equation + * from continually getting larger. + */ + if (runtime < MAX_SLEEP_AVG) + p->sleep_avg += (runtime - p->sleep_avg) * (MAX_SLEEP_AVG - runtime) / MAX_SLEEP_AVG; /* - * 'Overflow' bonus ticks go to the waker as well, so the - * ticks are not lost. This has the effect of further - * boosting tasks that are related to maximum-interactive - * tasks. + * Keep a buffer of 10-20% bonus sleep_avg with hysteresis + * to prevent short bursts of cpu activity from making + * interactive tasks lose their bonus */ - if (sleep_avg > MAX_SLEEP_AVG) - sleep_avg = MAX_SLEEP_AVG; - if (p->sleep_avg != sleep_avg) { - p->sleep_avg = sleep_avg; - p->prio = effective_prio(p); + if (p->sleep_avg > MAX_SLEEP_AVG * 12/10) + p->sleep_avg = MAX_SLEEP_AVG * 11/10; + + /* + * Tasks that sleep a long time are categorised as idle and + * get their static priority only + */ + if (sleep_time > MIN_SLEEP_AVG){ + p->avg_start = jiffies - MIN_SLEEP_AVG; + p->sleep_avg = MIN_SLEEP_AVG / 2; + } + if (unlikely(p->avg_start > jiffies)){ + p->avg_start = jiffies; + p->sleep_avg = 0; } + p->prio = effective_prio(p); } __activate_task(p, rq); } @@ -551,6 +605,8 @@ void wake_up_forked_process(task_t * p) * from forking tasks that are max-interactive. */ current->sleep_avg = current->sleep_avg * PARENT_PENALTY / 100; + p->avg_start = current->avg_start; + normalise_sleep(p); p->sleep_avg = p->sleep_avg * CHILD_PENALTY / 100; p->prio = effective_prio(p); set_task_cpu(p, smp_processor_id()); _