Fix scheduler's load tracking. Add load balancer.
The load tracking in the scheduler had a bug were the BSP would always have the lowest load on the system leading to large imbalance. Also add a simple periodic load balancer.
This commit is contained in:
parent
2846b0ab97
commit
7d8d1b64b9
|
|
@ -29,11 +29,6 @@ static int schedule_process(struct schedproc * rmp, unsigned flags);
|
||||||
SCHEDULE_CHANGE_CPU \
|
SCHEDULE_CHANGE_CPU \
|
||||||
)
|
)
|
||||||
|
|
||||||
#define schedule_process_local(p) \
|
|
||||||
schedule_process(p, SCHEDULE_CHANGE_PRIO | SCHEDULE_CHANGE_QUANTUM)
|
|
||||||
#define schedule_process_migrate(p) \
|
|
||||||
schedule_process(p, SCHEDULE_CHANGE_CPU)
|
|
||||||
|
|
||||||
#define CPU_DEAD -1
|
#define CPU_DEAD -1
|
||||||
|
|
||||||
#define cpu_is_available(c) (cpu_proc[c] >= 0)
|
#define cpu_is_available(c) (cpu_proc[c] >= 0)
|
||||||
|
|
@ -45,38 +40,41 @@ static int schedule_process(struct schedproc * rmp, unsigned flags);
|
||||||
|
|
||||||
static unsigned cpu_proc[CONFIG_MAX_CPUS];
|
static unsigned cpu_proc[CONFIG_MAX_CPUS];
|
||||||
|
|
||||||
static void pick_cpu(struct schedproc * proc)
|
static void allow_all_cpus(struct schedproc *proc)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
for(i=0;i<BITMAP_CHUNKS(CONFIG_MAX_CPUS);++i) {
|
||||||
|
bit_fill(proc->cpu_mask[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int next_cpu = 0;
|
||||||
|
static int pick_cpu(struct schedproc * proc)
|
||||||
{
|
{
|
||||||
#ifdef CONFIG_SMP
|
#ifdef CONFIG_SMP
|
||||||
unsigned cpu, c;
|
unsigned cpu, c;
|
||||||
unsigned cpu_load = (unsigned) -1;
|
unsigned cpu_load = (unsigned) -1;
|
||||||
|
|
||||||
if (machine.processors_count == 1) {
|
if (machine.processors_count == 1)
|
||||||
proc->cpu = machine.bsp_id;
|
return machine.bsp_id;
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* schedule sysytem processes only on the boot cpu */
|
|
||||||
if (is_system_proc(proc)) {
|
|
||||||
proc->cpu = machine.bsp_id;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* if no other cpu available, try BSP */
|
/* if no other cpu available, try BSP */
|
||||||
cpu = machine.bsp_id;
|
cpu = machine.bsp_id;
|
||||||
|
cpu_load = cpu_proc[machine.bsp_id];
|
||||||
for (c = 0; c < machine.processors_count; c++) {
|
for (c = 0; c < machine.processors_count; c++) {
|
||||||
/* skip dead cpus */
|
/* skip dead cpus */
|
||||||
if (!cpu_is_available(c))
|
if (!cpu_is_available(c))
|
||||||
continue;
|
continue;
|
||||||
|
if(!GET_BIT(proc->cpu_mask,c))
|
||||||
|
continue;
|
||||||
if (c != machine.bsp_id && cpu_load > cpu_proc[c]) {
|
if (c != machine.bsp_id && cpu_load > cpu_proc[c]) {
|
||||||
cpu_load = cpu_proc[c];
|
cpu_load = cpu_proc[c];
|
||||||
cpu = c;
|
cpu = c;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
proc->cpu = cpu;
|
return cpu;
|
||||||
cpu_proc[cpu]++;
|
|
||||||
#else
|
#else
|
||||||
proc->cpu = 0;
|
return 0;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -100,7 +98,8 @@ int do_noquantum(message *m_ptr)
|
||||||
rmp->priority += 1; /* lower priority */
|
rmp->priority += 1; /* lower priority */
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((rv = schedule_process_local(rmp)) != OK) {
|
rv = schedule_process(rmp,SCHEDULE_CHANGE_PRIO|SCHEDULE_CHANGE_QUANTUM);
|
||||||
|
if (rv != OK) {
|
||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
return OK;
|
return OK;
|
||||||
|
|
@ -126,10 +125,8 @@ int do_stop_scheduling(message *m_ptr)
|
||||||
}
|
}
|
||||||
|
|
||||||
rmp = &schedproc[proc_nr_n];
|
rmp = &schedproc[proc_nr_n];
|
||||||
#ifdef CONFIG_SMP
|
|
||||||
cpu_proc[rmp->cpu]--;
|
|
||||||
#endif
|
|
||||||
rmp->flags = 0; /*&= ~IN_USE;*/
|
rmp->flags = 0; /*&= ~IN_USE;*/
|
||||||
|
cpu_proc[rmp->cpu]--;
|
||||||
|
|
||||||
return OK;
|
return OK;
|
||||||
}
|
}
|
||||||
|
|
@ -141,6 +138,7 @@ int do_start_scheduling(message *m_ptr)
|
||||||
{
|
{
|
||||||
register struct schedproc *rmp;
|
register struct schedproc *rmp;
|
||||||
int rv, proc_nr_n, parent_nr_n;
|
int rv, proc_nr_n, parent_nr_n;
|
||||||
|
int cpu_chosen;
|
||||||
|
|
||||||
/* we can handle two kinds of messages here */
|
/* we can handle two kinds of messages here */
|
||||||
assert(m_ptr->m_type == SCHEDULING_START ||
|
assert(m_ptr->m_type == SCHEDULING_START ||
|
||||||
|
|
@ -165,6 +163,9 @@ int do_start_scheduling(message *m_ptr)
|
||||||
return EINVAL;
|
return EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
allow_all_cpus(rmp);
|
||||||
|
|
||||||
|
cpu_chosen = 0;
|
||||||
/* Inherit current priority and time slice from parent. Since there
|
/* Inherit current priority and time slice from parent. Since there
|
||||||
* is currently only one scheduler scheduling the whole system, this
|
* is currently only one scheduler scheduling the whole system, this
|
||||||
* value is local and we assert that the parent endpoint is valid */
|
* value is local and we assert that the parent endpoint is valid */
|
||||||
|
|
@ -183,6 +184,7 @@ int do_start_scheduling(message *m_ptr)
|
||||||
#ifdef CONFIG_SMP
|
#ifdef CONFIG_SMP
|
||||||
rmp->cpu = machine.bsp_id;
|
rmp->cpu = machine.bsp_id;
|
||||||
/* FIXME set the cpu mask */
|
/* FIXME set the cpu mask */
|
||||||
|
cpu_chosen = 1;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -223,12 +225,11 @@ int do_start_scheduling(message *m_ptr)
|
||||||
rmp->flags = IN_USE;
|
rmp->flags = IN_USE;
|
||||||
|
|
||||||
/* Schedule the process, giving it some quantum */
|
/* Schedule the process, giving it some quantum */
|
||||||
pick_cpu(rmp);
|
if(!cpu_chosen)
|
||||||
while ((rv = schedule_process(rmp, SCHEDULE_CHANGE_ALL)) == EBADCPU) {
|
rmp->cpu = pick_cpu(rmp);
|
||||||
/* don't try this CPU ever again */
|
cpu_proc[rmp->cpu]++;
|
||||||
cpu_proc[rmp->cpu] = CPU_DEAD;
|
if((rv = schedule_process(rmp, SCHEDULE_CHANGE_ALL)) == EBADCPU)
|
||||||
pick_cpu(rmp);
|
panic("EBADCPU\n");
|
||||||
}
|
|
||||||
|
|
||||||
if (rv != OK) {
|
if (rv != OK) {
|
||||||
printf("Sched: Error while scheduling process, kernel replied %d\n",
|
printf("Sched: Error while scheduling process, kernel replied %d\n",
|
||||||
|
|
@ -281,7 +282,8 @@ int do_nice(message *m_ptr)
|
||||||
/* Update the proc entry and reschedule the process */
|
/* Update the proc entry and reschedule the process */
|
||||||
rmp->max_priority = rmp->priority = new_q;
|
rmp->max_priority = rmp->priority = new_q;
|
||||||
|
|
||||||
if ((rv = schedule_process_local(rmp)) != OK) {
|
rv = schedule_process(rmp,SCHEDULE_CHANGE_PRIO|SCHEDULE_CHANGE_QUANTUM);
|
||||||
|
if (rv != OK) {
|
||||||
/* Something went wrong when rescheduling the process, roll
|
/* Something went wrong when rescheduling the process, roll
|
||||||
* back the changes to proc struct */
|
* back the changes to proc struct */
|
||||||
rmp->priority = old_q;
|
rmp->priority = old_q;
|
||||||
|
|
@ -299,8 +301,6 @@ static int schedule_process(struct schedproc * rmp, unsigned flags)
|
||||||
int err;
|
int err;
|
||||||
int new_prio, new_quantum, new_cpu, niced;
|
int new_prio, new_quantum, new_cpu, niced;
|
||||||
|
|
||||||
pick_cpu(rmp);
|
|
||||||
|
|
||||||
if (flags & SCHEDULE_CHANGE_PRIO)
|
if (flags & SCHEDULE_CHANGE_PRIO)
|
||||||
new_prio = rmp->priority;
|
new_prio = rmp->priority;
|
||||||
else
|
else
|
||||||
|
|
@ -359,7 +359,11 @@ void balance_queues(void)
|
||||||
if (rmp->flags & IN_USE) {
|
if (rmp->flags & IN_USE) {
|
||||||
if (rmp->priority > rmp->max_priority) {
|
if (rmp->priority > rmp->max_priority) {
|
||||||
rmp->priority -= 1; /* increase priority */
|
rmp->priority -= 1; /* increase priority */
|
||||||
schedule_process_local(rmp);
|
/* Balance the load, select new cpu. */
|
||||||
|
cpu_proc[rmp->cpu]--;
|
||||||
|
rmp->cpu = pick_cpu(rmp);
|
||||||
|
cpu_proc[rmp->cpu]++;
|
||||||
|
schedule_process(rmp,SCHEDULE_CHANGE_ALL);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user