From: Con Kolivas <kernel@kolivas.org>

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	Thu Jul 17 14:45:32 2003
+++ 25-akpm/include/linux/sched.h	Thu Jul 17 14:45:32 2003
@@ -341,6 +341,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	Thu Jul 17 14:45:32 2003
+++ 25-akpm/kernel/sched.c	Thu Jul 17 14:45:32 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());

_