From: Nick Piggin I think this might be causing problems. Maybe its there for a reason, but if so then I think some more work needs to be done. An idle CPU will be unable to pull tasks from a runqueue if they have all been run very recently. This patch changes that. Maybe it overbalances on other loads. Shown to reduce idle time on Zwane's box running volanomark. Ingo thinks its worth a try, but might cause some regressions due to over balancing. Andrew Theurer caught the exact same problem. kernel/sched.c | 48 +++++++++++++++++++++++++++++++++++------------- 1 files changed, 35 insertions(+), 13 deletions(-) diff -puN kernel/sched.c~np-sched-02-sched-migrate-fix kernel/sched.c --- 25/kernel/sched.c~np-sched-02-sched-migrate-fix 2003-09-01 02:05:47.000000000 -0700 +++ 25-akpm/kernel/sched.c 2003-09-01 02:05:47.000000000 -0700 @@ -1039,6 +1039,38 @@ static inline void pull_task(runqueue_t } /* + * can_migrate_task + * May task @p from runqueue @rq be migrated to @this_cpu? + * @idle: Is this_cpu idle + * Returns: 1 if @p may be migrated, 0 otherwise. + */ +static inline int +can_migrate_task(task_t *p, runqueue_t *rq, int this_cpu, int idle) +{ + unsigned long delta; + + /* + * We do not migrate tasks that are: + * 1) running (obviously), or + * 2) cannot be migrated to this CPU due to cpus_allowed, or + * 3) are cache-hot on their current CPU. + */ + + if (task_running(rq, p)) + return 0; + + if (!cpu_isset(this_cpu, p->cpus_allowed)) + return 0; + + /* Aggressive migration if we're idle */ + delta = jiffies - p->last_run; + if (!idle && (delta <= cache_decay_ticks)) + return 0; + + return 1; +} + +/* * Current runqueue is empty, or rebalance tick: if there is an * inbalance (current runqueue is too short) then pull from * busiest runqueue(s). @@ -1090,27 +1122,17 @@ skip_bitmap: skip_queue: tmp = list_entry(curr, task_t, run_list); - /* - * We do not migrate tasks that are: - * 1) running (obviously), or - * 2) cannot be migrated to this CPU due to cpus_allowed, or - * 3) are cache-hot on their current CPU. - */ - -#define CAN_MIGRATE_TASK(p,rq,this_cpu) \ - ((!idle || (jiffies - (p)->last_run > cache_decay_ticks)) && \ - !task_running(rq, p) && \ - cpu_isset(this_cpu, (p)->cpus_allowed)) - curr = curr->prev; - if (!CAN_MIGRATE_TASK(tmp, busiest, this_cpu)) { + if (!can_migrate_task(tmp, busiest, this_cpu, idle)) { if (curr != head) goto skip_queue; idx++; goto skip_bitmap; } pull_task(busiest, array, tmp, this_rq, this_cpu); + + /* Only migrate 1 task if we're idle */ if (!idle && --imbalance) { if (curr != head) goto skip_queue; _