Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 1baca4ce authored by Juri Lelli's avatar Juri Lelli Committed by Ingo Molnar
Browse files

sched/deadline: Add SCHED_DEADLINE SMP-related data structures & logic



Introduces data structures relevant for implementing dynamic
migration of -deadline tasks and the logic for checking if
runqueues are overloaded with -deadline tasks and for choosing
where a task should migrate, when it is the case.

Adds also dynamic migrations to SCHED_DEADLINE, so that tasks can
be moved among CPUs when necessary. It is also possible to bind a
task to a (set of) CPU(s), thus restricting its capability of
migrating, or forbidding migrations at all.

The very same approach used in sched_rt is utilised:
 - -deadline tasks are kept into CPU-specific runqueues,
 - -deadline tasks are migrated among runqueues to achieve the
   following:
    * on an M-CPU system the M earliest deadline ready tasks
      are always running;
    * affinity/cpusets settings of all the -deadline tasks is
      always respected.

Therefore, this very special form of "load balancing" is done with
an active method, i.e., the scheduler pushes or pulls tasks between
runqueues when they are woken up and/or (de)scheduled.
IOW, every time a preemption occurs, the descheduled task might be sent
to some other CPU (depending on its deadline) to continue executing
(push). On the other hand, every time a CPU becomes idle, it might pull
the second earliest deadline ready task from some other CPU.

To enforce this, a pull operation is always attempted before taking any
scheduling decision (pre_schedule()), as well as a push one after each
scheduling decision (post_schedule()). In addition, when a task arrives
or wakes up, the best CPU where to resume it is selected taking into
account its affinity mask, the system topology, but also its deadline.
E.g., from the scheduling point of view, the best CPU where to wake
up (and also where to push) a task is the one which is running the task
with the latest deadline among the M executing ones.

In order to facilitate these decisions, per-runqueue "caching" of the
deadlines of the currently running and of the first ready task is used.
Queued but not running tasks are also parked in another rb-tree to
speed-up pushes.

Signed-off-by: default avatarJuri Lelli <juri.lelli@gmail.com>
Signed-off-by: default avatarDario Faggioli <raistlin@linux.it>
Signed-off-by: default avatarPeter Zijlstra <peterz@infradead.org>
Link: http://lkml.kernel.org/r/1383831828-15501-5-git-send-email-juri.lelli@gmail.com


Signed-off-by: default avatarIngo Molnar <mingo@kernel.org>
parent aab03e05
Loading
Loading
Loading
Loading
+1 −0
Original line number Original line Diff line number Diff line
@@ -1201,6 +1201,7 @@ struct task_struct {
	struct list_head tasks;
	struct list_head tasks;
#ifdef CONFIG_SMP
#ifdef CONFIG_SMP
	struct plist_node pushable_tasks;
	struct plist_node pushable_tasks;
	struct rb_node pushable_dl_tasks;
#endif
#endif


	struct mm_struct *mm, *active_mm;
	struct mm_struct *mm, *active_mm;
+8 −1
Original line number Original line Diff line number Diff line
@@ -1848,6 +1848,7 @@ int sched_fork(unsigned long clone_flags, struct task_struct *p)
	init_task_preempt_count(p);
	init_task_preempt_count(p);
#ifdef CONFIG_SMP
#ifdef CONFIG_SMP
	plist_node_init(&p->pushable_tasks, MAX_PRIO);
	plist_node_init(&p->pushable_tasks, MAX_PRIO);
	RB_CLEAR_NODE(&p->pushable_dl_tasks);
#endif
#endif


	put_cpu();
	put_cpu();
@@ -5040,6 +5041,7 @@ static void free_rootdomain(struct rcu_head *rcu)
	struct root_domain *rd = container_of(rcu, struct root_domain, rcu);
	struct root_domain *rd = container_of(rcu, struct root_domain, rcu);


	cpupri_cleanup(&rd->cpupri);
	cpupri_cleanup(&rd->cpupri);
	free_cpumask_var(rd->dlo_mask);
	free_cpumask_var(rd->rto_mask);
	free_cpumask_var(rd->rto_mask);
	free_cpumask_var(rd->online);
	free_cpumask_var(rd->online);
	free_cpumask_var(rd->span);
	free_cpumask_var(rd->span);
@@ -5091,8 +5093,10 @@ static int init_rootdomain(struct root_domain *rd)
		goto out;
		goto out;
	if (!alloc_cpumask_var(&rd->online, GFP_KERNEL))
	if (!alloc_cpumask_var(&rd->online, GFP_KERNEL))
		goto free_span;
		goto free_span;
	if (!alloc_cpumask_var(&rd->rto_mask, GFP_KERNEL))
	if (!alloc_cpumask_var(&rd->dlo_mask, GFP_KERNEL))
		goto free_online;
		goto free_online;
	if (!alloc_cpumask_var(&rd->rto_mask, GFP_KERNEL))
		goto free_dlo_mask;


	if (cpupri_init(&rd->cpupri) != 0)
	if (cpupri_init(&rd->cpupri) != 0)
		goto free_rto_mask;
		goto free_rto_mask;
@@ -5100,6 +5104,8 @@ static int init_rootdomain(struct root_domain *rd)


free_rto_mask:
free_rto_mask:
	free_cpumask_var(rd->rto_mask);
	free_cpumask_var(rd->rto_mask);
free_dlo_mask:
	free_cpumask_var(rd->dlo_mask);
free_online:
free_online:
	free_cpumask_var(rd->online);
	free_cpumask_var(rd->online);
free_span:
free_span:
@@ -6451,6 +6457,7 @@ void __init sched_init_smp(void)
	free_cpumask_var(non_isolated_cpus);
	free_cpumask_var(non_isolated_cpus);


	init_sched_rt_class();
	init_sched_rt_class();
	init_sched_dl_class();
}
}
#else
#else
void __init sched_init_smp(void)
void __init sched_init_smp(void)