summaryrefslogtreecommitdiffstats
path: root/sys/kern/sched_ule.c
diff options
context:
space:
mode:
authorjeff <jeff@FreeBSD.org>2003-06-09 00:39:09 +0000
committerjeff <jeff@FreeBSD.org>2003-06-09 00:39:09 +0000
commit64dd44ce61ce3216e321e02b38071f7a0e42aff6 (patch)
treeb9865d1933d16c7f3c7f501c041884d61f0b2e21 /sys/kern/sched_ule.c
parentff5d1b58643e60d13a62f668165744be55da295b (diff)
downloadFreeBSD-src-64dd44ce61ce3216e321e02b38071f7a0e42aff6.zip
FreeBSD-src-64dd44ce61ce3216e321e02b38071f7a0e42aff6.tar.gz
- Add a simple CPU load balancing algorithm. This works by executing once a
second and equalizing the load between the two most imbalanced CPU. This is intended to clear up long term load imbalances that would not be handled by the 'pull' method in sched_choose(). - Pull out some bits of sched_choose() into a kseq_move() function that moves an arbitrary thread from one kseq to another.
Diffstat (limited to 'sys/kern/sched_ule.c')
-rw-r--r--sys/kern/sched_ule.c102
1 files changed, 95 insertions, 7 deletions
diff --git a/sys/kern/sched_ule.c b/sys/kern/sched_ule.c
index 6d79520..defe981 100644
--- a/sys/kern/sched_ule.c
+++ b/sys/kern/sched_ule.c
@@ -74,6 +74,11 @@ SYSCTL_INT(_kern_sched, OID_AUTO, slice_max, CTLFLAG_RW, &slice_max, 0, "");
int realstathz;
int tickincr = 1;
+#ifdef SMP
+/* Callout to handle load balancing SMP systems. */
+static struct callout kseq_lb_callout;
+#endif
+
/*
* These datastructures are allocated within their parent datastructure but
* are scheduler specific.
@@ -239,6 +244,8 @@ static void kseq_nice_rem(struct kseq *kseq, int nice);
void kseq_print(int cpu);
#ifdef SMP
struct kseq * kseq_load_highest(void);
+void kseq_balance(void *arg);
+void kseq_move(struct kseq *from, int cpu);
#endif
void
@@ -333,6 +340,75 @@ kseq_nice_rem(struct kseq *kseq, int nice)
}
#ifdef SMP
+/*
+ * kseq_balance is a simple CPU load balancing algorithm. It operates by
+ * finding the least loaded and most loaded cpu and equalizing their load
+ * by migrating some processes.
+ *
+ * Dealing only with two CPUs at a time has two advantages. Firstly, most
+ * installations will only have 2 cpus. Secondly, load balancing too much at
+ * once can have an unpleasant effect on the system. The scheduler rarely has
+ * enough information to make perfect decisions. So this algorithm chooses
+ * algorithm simplicity and more gradual effects on load in larger systems.
+ *
+ * It could be improved by considering the priorities and slices assigned to
+ * each task prior to balancing them. There are many pathological cases with
+ * any approach and so the semi random algorithm below may work as well as any.
+ *
+ */
+void
+kseq_balance(void *arg)
+{
+ struct kseq *kseq;
+ int high_load;
+ int low_load;
+ int high_cpu;
+ int low_cpu;
+ int move;
+ int diff;
+ int i;
+
+ high_cpu = 0;
+ low_cpu = 0;
+ high_load = 0;
+ low_load = -1;
+
+ mtx_lock_spin(&sched_lock);
+ for (i = 0; i < mp_maxid; i++) {
+ if (CPU_ABSENT(i))
+ continue;
+ kseq = KSEQ_CPU(i);
+ if (kseq->ksq_load > high_load) {
+ high_load = kseq->ksq_load;
+ high_cpu = i;
+ }
+ if (low_load == -1 || kseq->ksq_load < low_load) {
+ low_load = kseq->ksq_load;
+ low_cpu = i;
+ }
+ }
+
+ /*
+ * Nothing to do.
+ */
+ if (high_load < 2 || low_load == high_load)
+ goto out;
+
+ diff = high_load - low_load;
+ move = diff / 2;
+ if (diff & 0x1)
+ move++;
+
+ for (i = 0; i < move; i++)
+ kseq_move(KSEQ_CPU(high_cpu), low_cpu);
+
+out:
+ mtx_unlock_spin(&sched_lock);
+ callout_reset(&kseq_lb_callout, hz, kseq_balance, NULL);
+
+ return;
+}
+
struct kseq *
kseq_load_highest(void)
{
@@ -359,6 +435,20 @@ kseq_load_highest(void)
return (NULL);
}
+
+void
+kseq_move(struct kseq *from, int cpu)
+{
+ struct kse *ke;
+
+ ke = kseq_choose(from);
+ runq_remove(ke->ke_runq, ke);
+ ke->ke_state = KES_THREAD;
+ kseq_rem(from, ke);
+
+ ke->ke_cpu = cpu;
+ sched_add(ke);
+}
#endif
struct kse *
@@ -436,6 +526,10 @@ sched_setup(void *dummy)
kseq_add(KSEQ_SELF(), &kse0);
mtx_unlock_spin(&sched_lock);
+#ifdef SMP
+ callout_init(&kseq_lb_callout, 1);
+ kseq_balance(NULL);
+#endif
}
/*
@@ -1053,13 +1147,7 @@ retry:
* on the current processor. Then we will dequeue it
* normally above.
*/
- ke = kseq_choose(kseq);
- runq_remove(ke->ke_runq, ke);
- ke->ke_state = KES_THREAD;
- kseq_rem(kseq, ke);
-
- ke->ke_cpu = PCPU_GET(cpuid);
- sched_add(ke);
+ kseq_move(kseq, PCPU_GET(cpuid));
goto retry;
}
#endif
OpenPOWER on IntegriCloud