Commit 8c6f4906 authored by Andrew Morton's avatar Andrew Morton Committed by Linus Torvalds

[PATCH] O21 for interactivity 2.6.0

From: Con Kolivas <kernel@kolivas.org>

A non-critical corner case has come up for interactivity that I believe needs 
to be addressed. It is only extensive testing and examination that revealed
this, as this interactivity work is in maintenance mode.

Description:

  It is possible for a highly interactive task (like X) to cause large
  latencies in tasks that are less 'niced' (eg negative nice number
  compared to X which should normally run at nice 0) if they are fully
  cpu bound.  This occurs due to expiration of the cpu bound tasks.

  This patch addresses this by not reinserting interactive tasks into
  the active array if there is a better static priority task running but
  has been placed on the expired array.  This causes a substantial
  reduction in the maximum scheduling latency a task with a less nice
  value can have. 

  This also has the positive side effect of maintaining better cpu%
  proportions for tasks of different nice levels.

Testers will only be able to discern a difference with highly cpu bound tasks 
of normal scheduling policy at different nice levels. Test cases are doing 
something cpu intensive relatively -niced in the presence of an interactive
load (eg capturing and encoding video at nice -10 while using X nice 0, or 
something nice 0 vs nice +10) and so on. Because of the crossover of 10 
'nice' levels of dynamic priorities between interactive and cpu bound tasks
this patch will have a more noticable effect as the nice difference is
greater, especially 11 or more.
parent f6ef9d5b
...@@ -203,7 +203,7 @@ struct runqueue { ...@@ -203,7 +203,7 @@ struct runqueue {
task_t *curr, *idle; task_t *curr, *idle;
struct mm_struct *prev_mm; struct mm_struct *prev_mm;
prio_array_t *active, *expired, arrays[2]; prio_array_t *active, *expired, arrays[2];
int prev_cpu_load[NR_CPUS]; int best_expired_prio, prev_cpu_load[NR_CPUS];
#ifdef CONFIG_NUMA #ifdef CONFIG_NUMA
atomic_t *node_nr_running; atomic_t *node_nr_running;
int prev_node_load[MAX_NUMNODES]; int prev_node_load[MAX_NUMNODES];
...@@ -1342,12 +1342,14 @@ EXPORT_PER_CPU_SYMBOL(kstat); ...@@ -1342,12 +1342,14 @@ EXPORT_PER_CPU_SYMBOL(kstat);
* interactivity of a task if the first expired task had to wait more * interactivity of a task if the first expired task had to wait more
* than a 'reasonable' amount of time. This deadline timeout is * than a 'reasonable' amount of time. This deadline timeout is
* load-dependent, as the frequency of array switched decreases with * load-dependent, as the frequency of array switched decreases with
* increasing number of running tasks: * increasing number of running tasks. We also ignore the interactivity
* if a better static_prio task has expired:
*/ */
#define EXPIRED_STARVING(rq) \ #define EXPIRED_STARVING(rq) \
(STARVATION_LIMIT && ((rq)->expired_timestamp && \ ((STARVATION_LIMIT && ((rq)->expired_timestamp && \
(jiffies - (rq)->expired_timestamp >= \ (jiffies - (rq)->expired_timestamp >= \
STARVATION_LIMIT * ((rq)->nr_running) + 1))) STARVATION_LIMIT * ((rq)->nr_running) + 1))) || \
((rq)->curr->static_prio > (rq)->best_expired_prio))
/* /*
* This function gets called by the timer code, with HZ frequency. * This function gets called by the timer code, with HZ frequency.
...@@ -1429,6 +1431,8 @@ void scheduler_tick(int user_ticks, int sys_ticks) ...@@ -1429,6 +1431,8 @@ void scheduler_tick(int user_ticks, int sys_ticks)
rq->expired_timestamp = jiffies; rq->expired_timestamp = jiffies;
if (!TASK_INTERACTIVE(p) || EXPIRED_STARVING(rq)) { if (!TASK_INTERACTIVE(p) || EXPIRED_STARVING(rq)) {
enqueue_task(p, rq->expired); enqueue_task(p, rq->expired);
if (p->static_prio < rq->best_expired_prio)
rq->best_expired_prio = p->static_prio;
} else } else
enqueue_task(p, rq->active); enqueue_task(p, rq->active);
} else { } else {
...@@ -1549,6 +1553,7 @@ asmlinkage void schedule(void) ...@@ -1549,6 +1553,7 @@ asmlinkage void schedule(void)
rq->expired = array; rq->expired = array;
array = rq->active; array = rq->active;
rq->expired_timestamp = 0; rq->expired_timestamp = 0;
rq->best_expired_prio = MAX_PRIO;
} }
idx = sched_find_first_bit(array->bitmap); idx = sched_find_first_bit(array->bitmap);
...@@ -2811,6 +2816,8 @@ void __init sched_init(void) ...@@ -2811,6 +2816,8 @@ void __init sched_init(void)
rq = cpu_rq(i); rq = cpu_rq(i);
rq->active = rq->arrays; rq->active = rq->arrays;
rq->expired = rq->arrays + 1; rq->expired = rq->arrays + 1;
rq->best_expired_prio = MAX_PRIO;
spin_lock_init(&rq->lock); spin_lock_init(&rq->lock);
INIT_LIST_HEAD(&rq->migration_queue); INIT_LIST_HEAD(&rq->migration_queue);
atomic_set(&rq->nr_iowait, 0); atomic_set(&rq->nr_iowait, 0);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment