summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNick Piggin <nickpiggin@yahoo.com.au>2005-06-25 14:57:26 -0700
committerLinus Torvalds <torvalds@ppc970.osdl.org>2005-06-25 16:24:43 -0700
commit3dbd5342074a1e570ec84edf859deb9be588006d (patch)
treea5f0aa3f4152b409d9b109766f55020c28bbb9af
parent245af2c7870bd5940f7bfad19a0a03b32751fbc5 (diff)
downloadlinux-3dbd5342074a1e570ec84edf859deb9be588006d.tar.bz2
[PATCH] sched: multilevel sbe sbf
The fundamental problem that Suresh has with balance on exec and fork is that it only tries to balance the top level domain with the flag set. This was worked around by removing degenerate domains, but is still a problem if people want to start using more complex sched-domains, especially multilevel NUMA that ia64 is already using. This patch makes balance on fork and exec try balancing over not just the top most domain with the flag set, but all the way down the domain tree. Signed-off-by: Nick Piggin <nickpiggin@yahoo.com.au> Acked-by: Ingo Molnar <mingo@elte.hu> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
-rw-r--r--kernel/sched.c45
1 files changed, 38 insertions, 7 deletions
diff --git a/kernel/sched.c b/kernel/sched.c
index e75b301b5340..ef32389ee768 100644
--- a/kernel/sched.c
+++ b/kernel/sched.c
@@ -1319,21 +1319,24 @@ void fastcall wake_up_new_task(task_t * p, unsigned long clone_flags)
sd = tmp;
if (sd) {
+ cpumask_t span;
int new_cpu;
struct sched_group *group;
+again:
schedstat_inc(sd, sbf_cnt);
+ span = sd->span;
cpu = task_cpu(p);
group = find_idlest_group(sd, p, cpu);
if (!group) {
schedstat_inc(sd, sbf_balanced);
- goto no_forkbalance;
+ goto nextlevel;
}
new_cpu = find_idlest_cpu(group, cpu);
if (new_cpu == -1 || new_cpu == cpu) {
schedstat_inc(sd, sbf_balanced);
- goto no_forkbalance;
+ goto nextlevel;
}
if (cpu_isset(new_cpu, p->cpus_allowed)) {
@@ -1343,9 +1346,21 @@ void fastcall wake_up_new_task(task_t * p, unsigned long clone_flags)
rq = task_rq_lock(p, &flags);
cpu = task_cpu(p);
}
+
+ /* Now try balancing at a lower domain level */
+nextlevel:
+ sd = NULL;
+ for_each_domain(cpu, tmp) {
+ if (cpus_subset(span, tmp->span))
+ break;
+ if (tmp->flags & SD_BALANCE_FORK)
+ sd = tmp;
+ }
+
+ if (sd)
+ goto again;
}
-no_forkbalance:
#endif
/*
* We decrease the sleep average of forking parents
@@ -1711,25 +1726,41 @@ void sched_exec(void)
sd = tmp;
if (sd) {
+ cpumask_t span;
struct sched_group *group;
+again:
schedstat_inc(sd, sbe_cnt);
+ span = sd->span;
group = find_idlest_group(sd, current, this_cpu);
if (!group) {
schedstat_inc(sd, sbe_balanced);
- goto out;
+ goto nextlevel;
}
new_cpu = find_idlest_cpu(group, this_cpu);
if (new_cpu == -1 || new_cpu == this_cpu) {
schedstat_inc(sd, sbe_balanced);
- goto out;
+ goto nextlevel;
}
schedstat_inc(sd, sbe_pushed);
put_cpu();
sched_migrate_task(current, new_cpu);
- return;
+
+ /* Now try balancing at a lower domain level */
+ this_cpu = get_cpu();
+nextlevel:
+ sd = NULL;
+ for_each_domain(this_cpu, tmp) {
+ if (cpus_subset(span, tmp->span))
+ break;
+ if (tmp->flags & SD_BALANCE_EXEC)
+ sd = tmp;
+ }
+
+ if (sd)
+ goto again;
}
-out:
+
put_cpu();
}