Refactoring sched_entity and sched_rt_entity.
Subsystems (3)
cover Refactoring sched_entity and sched_rt_entity.
Hi everybody,
After having heard Peter talking about it many times, I finally decided to give this thing a spin. It is basically the idea of putting the current sched_entity and sched_rt_entity together in an union, contained in a more general structure which hosts the common fields of the twos. For example, it came out here: http://lkml.org/lkml/2009/7/9/153
Therefore, this patchset _DOES_NOT_ do that! :-O
In fact, this is some preliminary refactoring which I think it's needed before union-ify the two data structure, and on which I would like to get some preliminary comments, before going ahead with the wrong approach.
Basically, I renamed struct sched_entity to struct sched_cfs_entity and put it and sched_rt_entity inside a more general struct sched_entity... Is that clear? :-)
The patches just cope with that. Yes, there's some work done by a patch and undone by the next one. I now it's annoying, and I'm sorry, but I did such for the sake of reviewability and for making each patch compile cleanly.
As for the name of CFS's scheduling entities, sched_fair_entity would probably have been better, but it's longer, and "_cfs" is already present in many places, so I went for it... No big deal in changing that, apart from stay-within-80-characters-per-line issues! :-P
They're not inside an union yet, because I'm not sure on how to treat the task group case. In fact, tasks can only have _just_one_ scheduling policy at a time, and thus, for example, they need the run_list _or_ the rb_node for queueing (if the task is RT or fair, respectively), which is perfect with respect to using an union.
OTOH, groups are always considered both fair _and_ RT entities, for example they're always queued in _both_ an RT run_list and a fair rb-tree. So I can't put them in an union, because I need both at the same time!
Suggestions on how to deal with that will be appreciated.
I compiled and tested this on x86_64, and for [!]SMP, [!]CGROUP_SCHED, [!]FAIR_GROUP_SCHED, [!]RT_GROUP_SCHED and [!]SCHEDSTATS, and some combinations of these, but can't guarantee full coverage of all the possibilities yet... Working on it, in the meanwhile, forgive me if you find some configuration that does not build. ;-D
And as usual, comments of any kind are very very welcome! :-)
Thanks and Regards,
Dario Faggioli
[RFC][PATCH 0/3] Refactoring sched_entity and sched_rt_entity.
include/linux/init_task.h | 8 +- include/linux/sched.h | 35 ++- kernel/kthread.c | 2 +- kernel/posix-cpu-timers.c | 4 +- kernel/sched.c | 210 +++++++++------ kernel/sched_debug.c | 20 +- kernel/sched_fair.c | 636 ++++++++++++++++++++++++--------------------- kernel/sched_rt.c | 58 ++-- 8 files changed, 534 insertions(+), 439 deletions(-)
Signature · 5 lines
<<This happens because I choose it to happen!>> (Raistlin Majere) ---------------------------------------------------------------------- Dario Faggioli, ReTiS Lab, Scuola Superiore Sant'Anna, Pisa (Italy) http://retis.sssup.it/people/faggioli -- [email protected]
RFC PATCH 1/3 sched: rename sched_entity to sched_cfs_entity.
Using the name struct sched_entity' for the scheduling entity of the fair scheduling class is not fair to the other scheduling classes, which have to use things like struct sched_rt_entity'.
Moreover, changing that would make it possible to put all the `struct sched_*_entity' of all the scheduling classes in a more general structure (which will also contains all the common fields). This would make the code easier to understand and, if we manage in using an union for the class-specific fields, it would also save some memory.
Therefore, this commit turns sched_entity' into sched_cfs_entity', wherever it is being used.
--- fs/proc/base.c | 2 +- include/linux/init_task.h | 4 +- include/linux/sched.h | 6 +- kernel/delayacct.c | 2 +- kernel/exit.c | 2 +- kernel/posix-cpu-timers.c | 10 +- kernel/sched.c | 152 ++++++------ kernel/sched_debug.c | 117 +++++----- kernel/sched_fair.c | 611 +++++++++++++++++++++++---------------------- kernel/sched_rt.c | 26 +- kernel/sched_stoptask.c | 2 +- 11 files changed, 479 insertions(+), 455 deletions(-)
fs/proc/base.c +1 -1
@@ -356,7 +356,7 @@ static int proc_pid_stack(struct seq_file *m, struct pid_namespace *ns,static int proc_pid_schedstat (struct task_struct *task,char *buffer) {return sprintf (buffer,"%llu %llu %lu\n" , - (unsigned long long )task->se.sum_exec_runtime, + (unsigned long long )task->cfs.sum_exec_runtime, (unsigned long long )task->sched_info.run_delay, task->sched_info.pcount); }
include/linux/init_task.h +2 -2
@@ -142,8 +142,8 @@ extern struct cred init_cred; .cpus_allowed = CPU_MASK_ALL, \ .mm = NULL, \ .active_mm = &init_mm, \ - .se = { \ - .group_node = LIST_HEAD_INIT(tsk.se.group_node), \ + .cfs = { \ + .group_node = LIST_HEAD_INIT(tsk.cfs.group_node), \ }, \ .rt = { \ .run_list = LIST_HEAD_INIT(tsk.rt.run_list), \
include/linux/sched.h +3 -3
@@ -1137,7 +1137,7 @@ struct sched_statistics { };#endif -struct sched_entity { +struct sched_cfs_entity {struct load_weight load;/* for load-balancing */ struct rb_node run_node;struct list_head group_node;
@@ -1155,7 +1155,7 @@ struct sched_entity {#endif #ifdef CONFIG_FAIR_GROUP_SCHED -struct sched_entity *parent; +struct sched_cfs_entity *parent;/* rq on which this entity is (to be) queued: */ struct cfs_rq *cfs_rq;/* rq "owned" by this entity/group: */
@@ -1206,7 +1206,7 @@ struct task_struct {int prio, static_prio, normal_prio;unsigned int rt_priority;const struct sched_class *sched_class; -struct sched_entity se; +struct sched_cfs_entity cfs;struct sched_rt_entity rt;#ifdef CONFIG_PREEMPT_NOTIFIERS
kernel/delayacct.c +1 -1
@@ -128,7 +128,7 @@ int __delayacct_add_tsk(struct taskstats *d, struct task_struct *tsk)*/ t1 = tsk->sched_info.pcount; t2 = tsk->sched_info.run_delay; - t3 = tsk->se.sum_exec_runtime; + t3 = tsk->cfs.sum_exec_runtime; d->cpu_count += t1;
kernel/exit.c +1 -1
@@ -132,7 +132,7 @@ static void __exit_signal(struct task_struct *tsk) sig->inblock +=task_io_get_inblock (tsk); sig->oublock +=task_io_get_oublock (tsk);task_io_accounting_add (&sig->ioac, &tsk->ioac); - sig->sum_sched_runtime += tsk->se.sum_exec_runtime; + sig->sum_sched_runtime += tsk->cfs.sum_exec_runtime; } sig->nr_threads--;
kernel/posix-cpu-timers.c +5 -5
@@ -248,7 +248,7 @@ void thread_group_cputime(struct task_struct *tsk, struct task_cputime *times) do { times->utime = cputime_add(times->utime, t->utime); times->stime = cputime_add(times->stime, t->stime); - times->sum_exec_runtime += t->se.sum_exec_runtime; + times->sum_exec_runtime += t->cfs.sum_exec_runtime; } while_each_thread(tsk, t); out: rcu_read_unlock();
@@ -508,7 +508,7 @@ static void cleanup_timers(struct list_head *head,void posix_cpu_timers_exit (struct task_struct *tsk) {cleanup_timers (tsk->cpu_timers, - tsk->utime, tsk->stime, tsk->se.sum_exec_runtime); + tsk->utime, tsk->stime, tsk->cfs.sum_exec_runtime); }void posix_cpu_timers_exit_group (struct task_struct *tsk)
@@ -518,7 +518,7 @@ void posix_cpu_timers_exit_group(struct task_struct *tsk)cleanup_timers (tsk->signal->cpu_timers,cputime_add (tsk->utime, sig->utime),cputime_add (tsk->stime, sig->stime), - tsk->se.sum_exec_runtime + sig->sum_sched_runtime); + tsk->cfs.sum_exec_runtime + sig->sum_sched_runtime); }static void clear_dead_task (struct k_itimer *timer,union cpu_time_count now)
@@ -949,7 +949,7 @@ static void check_thread_timers(struct task_struct *tsk,struct cpu_timer_list *t =list_first_entry (timers, struct cpu_timer_list, entry); -if (!--maxfire || tsk->se.sum_exec_runtime < t->expires.sched) { +if (!--maxfire || tsk->cfs.sum_exec_runtime < t->expires.sched) { tsk->cputime_expires.sched_exp = t->expires.sched;break ; }
@@ -1276,7 +1276,7 @@ static inline int fastpath_timer_check(struct task_struct *tsk)struct task_cputime task_sample = { .utime = tsk->utime, .stime = tsk->stime, - .sum_exec_runtime = tsk->se.sum_exec_runtime + .sum_exec_runtime = tsk->cfs.sum_exec_runtime };if (task_cputime_expired (&task_sample, &tsk->cputime_expires))
kernel/sched.c +76 -76
424 lines not on this page · raw message
kernel/sched_debug.c +59 -58
185 lines not on this page · raw message
kernel/sched_fair.c +317 -294
1,371 lines not on this page · raw message
kernel/sched_rt.c +13 -13
@@ -628,16 +628,16 @@ static void update_curr_rt(struct rq *rq)if (!task_has_rt_policy (curr))return ; - delta_exec = rq->clock_task - curr->se.exec_start; + delta_exec = rq->clock_task - curr->cfs.exec_start;if (unlikely ((s64 )delta_exec <0 )) delta_exec =0 ; -schedstat_set (curr->se.statistics.exec_max,max (curr->se.statistics.exec_max, delta_exec)); +schedstat_set (curr->cfs.statistics.exec_max,max (curr->cfs.statistics.exec_max, delta_exec)); - curr->se.sum_exec_runtime += delta_exec; + curr->cfs.sum_exec_runtime += delta_exec;account_group_exec_runtime (curr, delta_exec); - curr->se.exec_start = rq->clock_task; + curr->cfs.exec_start = rq->clock_task;cpuacct_charge (curr, delta_exec);sched_rt_avg_update (rq, delta_exec);
@@ -1099,7 +1099,7 @@ static struct task_struct *_pick_next_task_rt(struct rq *rq) }while (rt_rq); p =rt_task_of (rt_se); - p->se.exec_start = rq->clock_task; + p->cfs.exec_start = rq->clock_task;return p; }
@@ -1126,13 +1126,13 @@ static struct task_struct *pick_next_task_rt(struct rq *rq)static void put_prev_task_rt (struct rq *rq,struct task_struct *p) {update_curr_rt (rq); - p->se.exec_start =0 ; + p->cfs.exec_start =0 ;/* * The previous task needs to be made eligible for pushing * if it is still active */ -if (p->se.on_rq && p->rt.nr_cpus_allowed >1 ) +if (p->cfs.on_rq && p->rt.nr_cpus_allowed >1 )enqueue_pushable_task (rq, p); }
@@ -1283,7 +1283,7 @@ static struct rq *find_lock_lowest_rq(struct task_struct *task, struct rq *rq) !cpumask_test_cpu(lowest_rq->cpu, &task->cpus_allowed) || task_running(rq, task) || - !task->se.on_rq)) { + !task->cfs.on_rq)) {raw_spin_unlock (&lowest_rq->lock); lowest_rq =NULL ;
@@ -1317,7 +1317,7 @@ static struct task_struct *pick_next_pushable_task(struct rq *rq)BUG_ON (task_current (rq, p));BUG_ON (p->rt.nr_cpus_allowed <=1 ); -BUG_ON (!p->se.on_rq); +BUG_ON (!p->cfs.on_rq);BUG_ON (!rt_task (p));return p;
@@ -1463,7 +1463,7 @@ static int pull_rt_task(struct rq *this_rq)*/ if (p && (p->prio < this_rq->rt.highest_prio.curr)) {WARN_ON (p == src_rq->curr); -WARN_ON (!p->se.on_rq); +WARN_ON (!p->cfs.on_rq);/* * There's a chance that p is higher in priority
@@ -1534,7 +1534,7 @@ static void set_cpus_allowed_rt(struct task_struct *p,* Update the migration status of the RQ if we have an RT task * which is running AND changing its weight value. */ -if (p->se.on_rq && (weight != p->rt.nr_cpus_allowed)) { +if (p->cfs.on_rq && (weight != p->rt.nr_cpus_allowed)) {struct rq *rq =task_rq (p);if (!task_current (rq, p)) {
@@ -1701,7 +1701,7 @@ static void watchdog(struct rq *rq, struct task_struct *p) p->rt.timeout++; next =DIV_ROUND_UP (min (soft, hard),USEC_PER_SEC /HZ );if (p->rt.timeout > next) - p->cputime_expires.sched_exp = p->se.sum_exec_runtime; + p->cputime_expires.sched_exp = p->cfs.sum_exec_runtime; } }
@@ -1737,7 +1737,7 @@ static void set_curr_task_rt(struct rq *rq) {struct task_struct *p = rq->curr; - p->se.exec_start = rq->clock_task; + p->cfs.exec_start = rq->clock_task;/* The running task is never eligible for pushing */ dequeue_pushable_task (rq, p);
kernel/sched_stoptask.c +1 -1
@@ -26,7 +26,7 @@ static struct task_struct *pick_next_task_stop(struct rq *rq) {struct task_struct *stop = rq->stop; -if (stop && stop->se.on_rq) +if (stop && stop->cfs.on_rq)return stop;return NULL ;
Signature · 8 lines
1.7.2.3 -- <<This happens because I choose it to happen!>> (Raistlin Majere) ---------------------------------------------------------------------- Dario Faggioli, ReTiS Lab, Scuola Superiore Sant'Anna, Pisa (Italy) http://retis.sssup.it/people/faggioli -- [email protected]
RFC PATCH 2/3 sched: make `struct sched_entity' independent from the scheduling class.
In reply to Dario FaggioliNow that the fair scheduling entity structure is called sched_cfs_entity we can use the name sched_entity for a more general data structure, which accommodates both sched_cfs_entity and sched_rt_entity, along with all the fields that are common and useful for both the classes.
In fact, it sounds a bit awkward for fields like on_rq or exec_start, that are meaningful and actually used from within sched_rt.c (for RT tasks and groups scheduling), to be placed in some other scheduling class' scheduling entity.
This commit addresses that. Notice that it places sched_cfs_entity and sched_rt_entity inside sched_entity as full structure, it doesn't use an union for them yet.
No fields are added, and the memory occupation of this solution should be pretty much the same of the previous one, apart from the case where just one of CONFIG_FAIR_GROUP_SCHED and CONFIG_RT_GROUP_SCHED is defined, which is a bit more expensive than before.
--- fs/proc/base.c | 2 +- include/linux/init_task.h | 8 +- include/linux/sched.h | 33 ++++-- kernel/delayacct.c | 2 +- kernel/exit.c | 2 +- kernel/kthread.c | 2 +- kernel/posix-cpu-timers.c | 14 ++-- kernel/sched.c | 262 ++++++++++++++++++++++++++------------------- kernel/sched_debug.c | 109 ++++++++++--------- kernel/sched_fair.c | 184 +++++++++++++++++-------------- kernel/sched_rt.c | 80 +++++++------- kernel/sched_stoptask.c | 2 +- 12 files changed, 385 insertions(+), 315 deletions(-)
fs/proc/base.c +1 -1
@@ -356,7 +356,7 @@ static int proc_pid_stack(struct seq_file *m, struct pid_namespace *ns,static int proc_pid_schedstat (struct task_struct *task,char *buffer) {return sprintf (buffer,"%llu %llu %lu\n" , - (unsigned long long )task->cfs.sum_exec_runtime, + (unsigned long long )task->se.sum_exec_runtime, (unsigned long long )task->sched_info.run_delay, task->sched_info.pcount); }
include/linux/init_task.h +4 -4
@@ -142,11 +142,11 @@ extern struct cred init_cred; .cpus_allowed = CPU_MASK_ALL, \ .mm = NULL, \ .active_mm = &init_mm, \ - .cfs = { \ - .group_node = LIST_HEAD_INIT(tsk.cfs.group_node), \ + .se.cfs = { \ + .group_node = LIST_HEAD_INIT(tsk.se.cfs.group_node),\ }, \ - .rt = { \ - .run_list = LIST_HEAD_INIT(tsk.rt.run_list), \ + .se.rt = { \ + .run_list = LIST_HEAD_INIT(tsk.se.rt.run_list), \ .time_slice = HZ, \ .nr_cpus_allowed = NR_CPUS, \ }, \
include/linux/sched.h +21 -12
@@ -1141,18 +1141,8 @@ struct sched_cfs_entity {struct load_weight load;/* for load-balancing */ struct rb_node run_node;struct list_head group_node; -unsigned int on_rq; -u64 exec_start; -u64 sum_exec_runtime;u64 vruntime; -u64 prev_sum_exec_runtime; - -u64 nr_migrations; - -#ifdef CONFIG_SCHEDSTATS -struct sched_statistics statistics; -#endif #ifdef CONFIG_FAIR_GROUP_SCHED struct sched_cfs_entity *parent;
@@ -1179,6 +1169,26 @@ struct sched_rt_entity {#endif }; +struct sched_entity { +unsigned int on_rq; +u64 exec_start; +u64 sum_exec_runtime; +u64 prev_sum_exec_runtime; +u64 nr_migrations; + +/*union { +struct sched_cfs_entity cfs; +struct sched_rt_entity rt; +};*/ +struct sched_cfs_entity cfs; +struct sched_rt_entity rt; + +#ifdef CONFIG_SCHEDSTATS +struct sched_statistics statistics; +#endif + +}; +struct rcu_node ;enum perf_event_task_context {
@@ -1206,8 +1216,7 @@ struct task_struct {int prio, static_prio, normal_prio;unsigned int rt_priority;const struct sched_class *sched_class; -struct sched_cfs_entity cfs; -struct sched_rt_entity rt; +struct sched_entity se;#ifdef CONFIG_PREEMPT_NOTIFIERS /* list of struct preempt_notifier: */
kernel/delayacct.c +1 -1
@@ -128,7 +128,7 @@ int __delayacct_add_tsk(struct taskstats *d, struct task_struct *tsk)*/ t1 = tsk->sched_info.pcount; t2 = tsk->sched_info.run_delay; - t3 = tsk->cfs.sum_exec_runtime; + t3 = tsk->se.sum_exec_runtime; d->cpu_count += t1;
kernel/exit.c +1 -1
@@ -132,7 +132,7 @@ static void __exit_signal(struct task_struct *tsk) sig->inblock +=task_io_get_inblock (tsk); sig->oublock +=task_io_get_oublock (tsk);task_io_accounting_add (&sig->ioac, &tsk->ioac); - sig->sum_sched_runtime += tsk->cfs.sum_exec_runtime; + sig->sum_sched_runtime += tsk->se.sum_exec_runtime; } sig->nr_threads--;
kernel/kthread.c +1 -1
@@ -184,7 +184,7 @@ void kthread_bind(struct task_struct *p, unsigned int cpu) } p->cpus_allowed =cpumask_of_cpu (cpu); - p->rt.nr_cpus_allowed =1 ; + p->se.rt.nr_cpus_allowed =1 ; p->flags |=PF_THREAD_BOUND ; }EXPORT_SYMBOL (kthread_bind);
kernel/posix-cpu-timers.c +7 -7
@@ -248,7 +248,7 @@ void thread_group_cputime(struct task_struct *tsk, struct task_cputime *times) do { times->utime = cputime_add(times->utime, t->utime); times->stime = cputime_add(times->stime, t->stime); - times->sum_exec_runtime += t->cfs.sum_exec_runtime; + times->sum_exec_runtime += t->se.sum_exec_runtime; } while_each_thread(tsk, t); out: rcu_read_unlock();
@@ -508,7 +508,7 @@ static void cleanup_timers(struct list_head *head,void posix_cpu_timers_exit (struct task_struct *tsk) {cleanup_timers (tsk->cpu_timers, - tsk->utime, tsk->stime, tsk->cfs.sum_exec_runtime); + tsk->utime, tsk->stime, tsk->se.sum_exec_runtime); }void posix_cpu_timers_exit_group (struct task_struct *tsk)
@@ -518,7 +518,7 @@ void posix_cpu_timers_exit_group(struct task_struct *tsk)cleanup_timers (tsk->signal->cpu_timers,cputime_add (tsk->utime, sig->utime),cputime_add (tsk->stime, sig->stime), - tsk->cfs.sum_exec_runtime + sig->sum_sched_runtime); + tsk->se.sum_exec_runtime + sig->sum_sched_runtime); }static void clear_dead_task (struct k_itimer *timer,union cpu_time_count now)
@@ -949,7 +949,7 @@ static void check_thread_timers(struct task_struct *tsk,struct cpu_timer_list *t =list_first_entry (timers, struct cpu_timer_list, entry); -if (!--maxfire || tsk->cfs.sum_exec_runtime < t->expires.sched) { +if (!--maxfire || tsk->se.sum_exec_runtime < t->expires.sched) { tsk->cputime_expires.sched_exp = t->expires.sched;break ; }
@@ -966,7 +966,7 @@ static void check_thread_timers(struct task_struct *tsk,ACCESS_ONCE (sig->rlim[RLIMIT_RTTIME ].rlim_max);if (hard !=RLIM_INFINITY && - tsk->rt.timeout >DIV_ROUND_UP (hard,USEC_PER_SEC /HZ )) { + tsk->se.rt.timeout >DIV_ROUND_UP (hard,USEC_PER_SEC /HZ )) {/* * At the hard limit, we just die. * No need to calculate anything else now.
@@ -974,7 +974,7 @@ static void check_thread_timers(struct task_struct *tsk,__group_send_sig_info (SIGKILL ,SEND_SIG_PRIV , tsk);return ; } -if (tsk->rt.timeout >DIV_ROUND_UP (soft,USEC_PER_SEC /HZ )) { +if (tsk->se.rt.timeout >DIV_ROUND_UP (soft,USEC_PER_SEC /HZ )) {/* * At the soft limit, send a SIGXCPU every second. */
@@ -1276,7 +1276,7 @@ static inline int fastpath_timer_check(struct task_struct *tsk)struct task_cputime task_sample = { .utime = tsk->utime, .stime = tsk->stime, - .sum_exec_runtime = tsk->cfs.sum_exec_runtime + .sum_exec_runtime = tsk->se.sum_exec_runtime };if (task_cputime_expired (&task_sample, &tsk->cputime_expires))
kernel/sched.c +152 -110
606 lines not on this page · raw message
kernel/sched_debug.c +55 -54
171 lines not on this page · raw message
kernel/sched_fair.c +101 -83
543 lines not on this page · raw message
kernel/sched_rt.c +40 -40
266 lines not on this page · raw message
kernel/sched_stoptask.c +1 -1
@@ -26,7 +26,7 @@ static struct task_struct *pick_next_task_stop(struct rq *rq) {struct task_struct *stop = rq->stop; -if (stop && stop->cfs.on_rq) +if (stop && stop->se.on_rq)return stop;return NULL ;
Signature · 8 lines
1.7.2.3 -- <<This happens because I choose it to happen!>> (Raistlin Majere) ---------------------------------------------------------------------- Dario Faggioli, ReTiS Lab, Scuola Superiore Sant'Anna, Pisa (Italy) http://retis.sssup.it/people/faggioli -- [email protected]
RFC PATCH 3/3 sched: beautify access to some common fields.
In reply to Dario FaggioliFields like on_rq or statistics are accessed quite frequently from CFS within implementation, although they're no longer part of sched_cfs_entity (they're in the general sched_entity).
This commit provides some macros that makes the code which deals with them a bit less cumbersome.
--- kernel/sched_fair.c | 111 ++++++++++++++++++++++++++------------------------- 1 files changed, 56 insertions(+), 55 deletions(-)
kernel/sched_fair.c +56 -55
@@ -107,6 +107,11 @@ static inline struct sched_entity *se_of_cfs_se(struct sched_cfs_entity *cfs_se) return container_of(cfs_se, struct sched_entity, cfs); } +static inline int cfs_se_on_rq (struct sched_cfs_entity *cfs_se) +{ +return se_of_cfs_se (cfs_se)->on_rq; +} +#ifdef CONFIG_FAIR_GROUP_SCHED /* cpu runqueue to which this cfs_rq is attached */
@@ -455,6 +460,8 @@ static struct sched_cfs_entity *__pick_last_entity(struct cfs_rq *cfs_rq)* Scheduling class statistics methods: */ +#define cfs_se_statistics (cfs_se) ((se_of_cfs_se(cfs_se))->statistics) +#ifdef CONFIG_SCHED_DEBUG int sched_proc_update_handler(struct ctl_table *table, int write, void __user *buffer, size_t *lenp,
@@ -521,8 +528,7 @@ static u64 __sched_period(unsigned long nr_running)*/ static u64 sched_slice (struct cfs_rq *cfs_rq,struct sched_cfs_entity *cfs_se) { -struct sched_entity *se =se_of_cfs_se (cfs_se); -u64 slice =__sched_period (cfs_rq->nr_running + !se->on_rq); +u64 slice =__sched_period (cfs_rq->nr_running + !cfs_se_on_rq (cfs_se));for_each_sched_cfs_entity (cfs_se) {struct load_weight *load;
@@ -531,7 +537,7 @@ static u64 sched_slice(struct cfs_rq *cfs_rq, struct sched_cfs_entity *cfs_se) cfs_rq =cfs_rq_of (cfs_se); load = &cfs_rq->load; -if (unlikely (!se_of_cfs_se (cfs_se)->on_rq)) { +if (unlikely (!cfs_se_on_rq (cfs_se))) { lw = cfs_rq->load;update_load_add (&lw, cfs_se->load.weight);
@@ -564,13 +570,12 @@ static inline void __update_curr(struct cfs_rq *cfs_rq, struct sched_cfs_entity *curr, unsigned long delta_exec) { - struct sched_entity *curr_se = se_of_cfs_se(curr); unsigned long delta_exec_weighted; -schedstat_set (curr_se->statistics.exec_max, -max ((u64 )delta_exec, curr_se->statistics.exec_max)); +schedstat_set (cfs_se_statistics (curr).exec_max, +max ((u64 )delta_exec,cfs_se_statistics (curr).exec_max)); - curr_se->sum_exec_runtime += delta_exec; +se_of_cfs_se (curr)->sum_exec_runtime += delta_exec;schedstat_add (cfs_rq, exec_clock, delta_exec); delta_exec_weighted =calc_delta_fair (delta_exec, curr);
@@ -616,7 +621,7 @@ static void update_curr(struct cfs_rq *cfs_rq)static inline void update_stats_wait_start (struct cfs_rq *cfs_rq,struct sched_cfs_entity *cfs_se) { -schedstat_set (se_of_cfs_se (cfs_se)->statistics.wait_start, +schedstat_set (cfs_se_statistics (cfs_se).wait_start,rq_of (cfs_rq)->clock); }
@@ -637,20 +642,20 @@ update_stats_enqueue(struct cfs_rq *cfs_rq, struct sched_cfs_entity *cfs_se)static void update_stats_wait_end (struct cfs_rq *cfs_rq,struct sched_cfs_entity *cfs_se) { +schedstat_set (cfs_se_statistics (cfs_se).wait_max, +max (cfs_se_statistics (cfs_se).wait_max, +rq_of (cfs_rq)->clock -cfs_se_statistics (cfs_se).wait_start)); +schedstat_set (cfs_se_statistics (cfs_se).wait_count, +cfs_se_statistics (cfs_se).wait_count+1 ); +schedstat_set (cfs_se_statistics (cfs_se).wait_sum, +cfs_se_statistics (cfs_se).wait_sum + +rq_of (cfs_rq)->clock -cfs_se_statistics (cfs_se).wait_start);#ifdef CONFIG_SCHEDSTATS -/* #ifdef-ing like this suppresses a gcc warning */ -struct sched_entity *se =se_of_cfs_se (cfs_se); - -schedstat_set (se->statistics.wait_max,max (se->statistics.wait_max, -rq_of (cfs_rq)->clock - se->statistics.wait_start)); -schedstat_set (se->statistics.wait_count, se->statistics.wait_count+1 ); -schedstat_set (se->statistics.wait_sum, se->statistics.wait_sum + -rq_of (cfs_rq)->clock - se->statistics.wait_start);if (cfs_entity_is_task (cfs_se)) {trace_sched_stat_wait (cfs_task_of (cfs_se),rq_of (cfs_rq)->clock - - se->statistics.wait_start); +cfs_se_statistics (cfs_se).wait_start); } -schedstat_set (se->statistics.wait_start,0 ); +schedstat_set (cfs_se_statistics (cfs_se).wait_start,0 );#endif }
@@ -787,9 +792,7 @@ static void reweight_entity(struct cfs_rq *cfs_rq, struct sched_cfs_entity *cfs_se, unsigned long weight) { -struct sched_entity *se =se_of_cfs_se (cfs_se); - -if (se->on_rq) { + if (cfs_se_on_rq(cfs_se)) { /* commit outstanding execution time */ if (cfs_rq->curr == cfs_se) update_curr(cfs_rq);
@@ -798,7 +801,7 @@ static void reweight_entity(struct cfs_rq *cfs_rq,update_load_set (&cfs_se->load, weight); -if (se->on_rq) +if (cfs_se_on_rq (cfs_se))account_entity_enqueue (cfs_rq, cfs_se); }
@@ -860,44 +863,45 @@ enqueue_sleeper(struct cfs_rq *cfs_rq, struct sched_cfs_entity *cfs_se) {#ifdef CONFIG_SCHEDSTATS struct task_struct *tsk =NULL ; -struct sched_entity *se =se_of_cfs_se (cfs_se);if (cfs_entity_is_task (cfs_se)) tsk =cfs_task_of (cfs_se); -if (se->statistics.sleep_start) { -u64 delta =rq_of (cfs_rq)->clock - se->statistics.sleep_start; +if (cfs_se_statistics (cfs_se).sleep_start) { +u64 delta =rq_of (cfs_rq)->clock - +cfs_se_statistics (cfs_se).sleep_start;if ((s64 )delta <0 ) delta =0 ; -if (unlikely (delta > se->statistics.sleep_max)) - se->statistics.sleep_max = delta; +if (unlikely (delta >cfs_se_statistics (cfs_se).sleep_max)) +cfs_se_statistics (cfs_se).sleep_max = delta; - se->statistics.sleep_start =0 ; - se->statistics.sum_sleep_runtime += delta; +cfs_se_statistics (cfs_se).sleep_start =0 ; +cfs_se_statistics (cfs_se).sum_sleep_runtime += delta;if (tsk) {account_scheduler_latency (tsk, delta >>10 ,1 );trace_sched_stat_sleep (tsk, delta); } } -if (se->statistics.block_start) { -u64 delta =rq_of (cfs_rq)->clock - se->statistics.block_start; +if (cfs_se_statistics (cfs_se).block_start) { +u64 delta =rq_of (cfs_rq)->clock - +cfs_se_statistics (cfs_se).block_start;if ((s64 )delta <0 ) delta =0 ; -if (unlikely (delta > se->statistics.block_max)) - se->statistics.block_max = delta; +if (unlikely (delta >cfs_se_statistics (cfs_se).block_max)) +cfs_se_statistics (cfs_se).block_max = delta; - se->statistics.block_start =0 ; - se->statistics.sum_sleep_runtime += delta; +cfs_se_statistics (cfs_se).block_start =0 ; +cfs_se_statistics (cfs_se).sum_sleep_runtime += delta;if (tsk) {if (tsk->in_iowait) { - se->statistics.iowait_sum += delta; - se->statistics.iowait_count++; +cfs_se_statistics (cfs_se).iowait_sum += delta; +cfs_se_statistics (cfs_se).iowait_count++;trace_sched_stat_iowait (tsk, delta); }
@@ -1031,12 +1035,11 @@ dequeue_entity(struct cfs_rq *cfs_rq, struct sched_cfs_entity *cfs_se,#ifdef CONFIG_SCHEDSTATS if (cfs_entity_is_task (cfs_se)) {struct task_struct *tsk =cfs_task_of (cfs_se); -struct sched_entity *se =se_of_cfs_se (cfs_se);if (tsk->state &TASK_INTERRUPTIBLE ) - se->statistics.sleep_start =rq_of (cfs_rq)->clock; +cfs_se_statistics (cfs_se).sleep_start =rq_of (cfs_rq)->clock;if (tsk->state &TASK_UNINTERRUPTIBLE ) - se->statistics.block_start =rq_of (cfs_rq)->clock; +cfs_se_statistics (cfs_se).block_start =rq_of (cfs_rq)->clock; }#endif }
@@ -1104,10 +1107,8 @@ check_preempt_tick(struct cfs_rq *cfs_rq, struct sched_cfs_entity *curr)static void set_next_entity (struct cfs_rq *cfs_rq,struct sched_cfs_entity *cfs_se) { -struct sched_entity *se =se_of_cfs_se (cfs_se); -/* 'current' is not kept within the tree. */ -if (se->on_rq) { +if (cfs_se_on_rq (cfs_se)) {/* * Any task has to be enqueued before it get to execute on * a CPU. So account for the time it spent waiting on the
@@ -1126,11 +1127,13 @@ set_next_entity(struct cfs_rq *cfs_rq, struct sched_cfs_entity *cfs_se)* when there are only lesser-weight tasks around): */ if (rq_of (cfs_rq)->load.weight >=2 *cfs_se->load.weight) { - se->statistics.slice_max =max (se->statistics.slice_max, - se->sum_exec_runtime - se->prev_sum_exec_runtime); +cfs_se_statistics (cfs_se).slice_max =max (cfs_se_statistics (cfs_se).slice_max, +se_of_cfs_se (cfs_se)->sum_exec_runtime - +se_of_cfs_se (cfs_se)->prev_sum_exec_runtime); }#endif - se->prev_sum_exec_runtime = se->sum_exec_runtime; +se_of_cfs_se (cfs_se)->prev_sum_exec_runtime = +se_of_cfs_se (cfs_se)->sum_exec_runtime; } static int wakeup_preempt_entity(struct sched_cfs_entity *curr,
@@ -1158,17 +1161,15 @@ static struct sched_cfs_entity *pick_next_entity(struct cfs_rq *cfs_rq)static void put_prev_entity (struct cfs_rq *cfs_rq,struct sched_cfs_entity *prev) { -struct sched_entity *prev_se =se_of_cfs_se (prev); -/* * If still on the runqueue then deactivate_task() * was not called and update_curr() has to be done: */ -if (prev_se->on_rq) +if (cfs_se_on_rq (prev))update_curr (cfs_rq);check_spread (cfs_rq, prev); -if (prev_se->on_rq) { +if (cfs_se_on_rq (prev)) {update_stats_wait_start (cfs_rq, prev);/* Put 'current' back into the tree. */ __enqueue_entity (cfs_rq, prev);
@@ -1279,11 +1280,11 @@ static inline void hrtick_update(struct rq *rq)static void enqueue_task_fair (struct rq *rq,struct task_struct *p,int flags) { -struct cfs_rq *cfs_rq;struct sched_cfs_entity *cfs_se = &p->se.cfs; +struct cfs_rq *cfs_rq;for_each_sched_cfs_entity (cfs_se) { -if (se_of_cfs_se (cfs_se)->on_rq) +if (cfs_se_on_rq (cfs_se))break ; cfs_rq =cfs_rq_of (cfs_se);enqueue_entity (cfs_rq, cfs_se, flags);
@@ -1505,7 +1506,7 @@ static int wake_affine(struct sched_domain *sd, struct task_struct *p, int sync)if (sync && balanced)return 1 ; -schedstat_inc (p, se.statistics.nr_wakeups_affine_attempts); +schedstat_inc (p,cfs_se_statistics (cfs_se).nr_wakeups_affine_attempts); tl_per_task =cpu_avg_load_per_task (this_cpu); if (balanced ||
@@ -1517,7 +1518,7 @@ static int wake_affine(struct sched_domain *sd, struct task_struct *p, int sync)* there is no bad imbalance. */ schedstat_inc (sd, ttwu_move_affine); -schedstat_inc (p, se.statistics.nr_wakeups_affine); +schedstat_inc (p,cfs_se_statistics (cfs_se).nr_wakeups_affine);return 1 ; }
@@ -1902,7 +1903,7 @@ preempt:* Also, during early boot the idle thread is in the fair class, * for obvious reasons its a bad idea to schedule back to it. */ -if (unlikely (!se_of_cfs_se (cfs_se)->on_rq || curr == rq->idle)) +if (unlikely (!cfs_se_on_rq (cfs_se) || curr == rq->idle))return ;if (sched_feat (LAST_BUDDY ) && scale &&cfs_entity_is_task (cfs_se))
Signature · 8 lines
1.7.2.3 -- <<This happens because I choose it to happen!>> (Raistlin Majere) ---------------------------------------------------------------------- Dario Faggioli, ReTiS Lab, Scuola Superiore Sant'Anna, Pisa (Italy) http://retis.sssup.it/people/faggioli -- [email protected]
Hi Dario
Quoted 27 lines · Dario Faggioli
Hi everybody,
After having heard Peter talking about it many times, I finally decided to give this thing a spin. It is basically the idea of putting the current
sched_entityandsched_rt_entitytogether in an union, contained in a more general structure which hosts the common fields of the twos. For example, it came out here: http://lkml.org/lkml/2009/7/9/153Therefore, this patchset _DOES_NOT_ do that! :-O
In fact, this is some preliminary refactoring which I think it's needed before union-ify the two data structure, and on which I would like to get some preliminary comments, before going ahead with the wrong approach.
Basically, I renamed struct
sched_entityto structsched_cfs_entityand put it andsched_rt_entityinside a more general structsched_entity... Is that clear? :-)
The patches just cope with that. Yes, there's some work done by a patch and undone by the next one. I now it's annoying, and I'm sorry, but I did such for the sake of reviewability and for making each patch compile cleanly.
As for the name of CFS's scheduling entities,sched_fair_entitywould probably have been better, but it's longer, and "_cfs" is already present in many places, so I went for it... No big deal in changing that, apart from stay-within-80-characters-per-line issues! :-P
Quoted 11 lines
They're not inside an union yet, because I'm not sure on how to treat the task group case. In fact, tasks can only have _just_one_ scheduling policy at a time, and thus, for example, they need the
run_list_or_ therb_nodefor queueing (if the task is RT or fair, respectively), which is perfect with respect to using an union.
OTOH, groups are always considered both fair _and_ RT entities, for example they're always queued in _both_ an RTrun_listand a fair rb-tree. So I can't put them in an union, because I need both at the same time!
Suggestions on how to deal with that will be appreciated.
In fact I created the patchset but I didn't have time to finish, polish, test and send. There are several corner cases that must be treated that made me think if it was really worth the work.
In this repo you can find a greatly outdated branch that treats some of the troubles you'll need to think about:
git://git.profusion.mobi/users/lucas/linux-2.6.git schedentity
And this was a rebase I did, but irc it was not working well:
git://git.profusion.mobi/users/lucas/linux-2.6.git schedentity-rebased
Lucas De Marchi
Quoted 2 lines · Lucas De Marchi
Hi Dario
Hi there,
Quoted 6 lines
Quoted 2 lines
Suggestions on how to deal with that will be appreciated.
In fact I created the patchset but I didn't have time to finish, polish, test and send.
Heh, I know that feeling! :-)
Quoted 3 lines
There are several corner cases that must be treated that made me think if it was really worth the work.
Ok, again, while git-clone and git-push do their jobs, feel free to share some of these concerns of yours with me, because I'm not sure I'm getting here...
Quoted 5 lines
In this repo you can find a greatly outdated branch that treats some of the troubles you'll need to think about:
git://git.profusion.mobi/users/lucas/linux-2.6.gitschedentity
Ok, this is mine (it'll be ready in a while, I'm pushing it up):
git://gitorious.org/sched_deadline/linux-26.git schedentity
Right now I'm pushing my schedentity branch and cloning yours! :-D Unfortunately, both seems to be quite long operations... :-(
Quoted 2 lines
And this was a rebase I did, but irc it was not working well:
Well, I'll be very busy in the next days, but I plan to keep this updated enough, so feel free to comment and/or use it as a basis for further patching if you think it could help.
Thanks and Regards,
Dario
Signature · 5 lines
<<This happens because I choose it to happen!>> (Raistlin Majere) ---------------------------------------------------------------------- Dario Faggioli, ReTiS Lab, Scuola Superiore Sant'Anna, Pisa (Italy) http://retis.sssup.it/people/faggioli -- [email protected]
Quoted 9 lines · Dario Faggioli
They're not inside an union yet, because I'm not sure on how to treat the task group case. In fact, tasks can only have _just_one_ scheduling policy at a time, and thus, for example, they need the
run_list_or_ therb_nodefor queueing (if the task is RT or fair, respectively), which is perfect with respect to using an union.
OTOH, groups are always considered both fair _and_ RT entities, for example they're always queued in _both_ an RTrun_listand a fair rb-tree. So I can't put them in an union, because I need both at the same time!
Just like its now, keep a sched_entity per class.
struct task_group {
#ifdef CONFIG_FAIR_GROUP_SCHED struct sched_entity **cfs_se; ...
#endif
#ifdef CONFIG_RT_GROUP_SCHED struct sched_entity **rt_se; ...
#endif
}
Quoted 1 line
And as usual, comments of any kind are very very welcome! :-)
Yay!
I see once clash with my current ttwu patch set though, see:
http://lkml.org/lkml/2011/1/4/228
But that should be easy to resolve.
Quoted 12 lines · Peter Zijlstra
Quoted 4 lines
OTOH, groups are always considered both fair _and_ RT entities, for example they're always queued in _both_ an RT
run_listand a fair rb-tree. So I can't put them in an union, because I need both at the same time!Just like its now, keep a
sched_entityper class.struct
task_group{#ifdef CONFIG_FAIR_GROUP_SCHED struct sched_entity **cfs_se; ...
Quoted 9 lines
#endif
#ifdef CONFIG_RT_GROUP_SCHED struct sched_entity **rt_se; ...#endif
}
Well, sure this can be done. But what about the common fields? I guess you're suggesting to use something like `struct sched_entity_common' and putting them there, aren't you?
If yes, I'm fine with that, although it'll add one more level of indirection for those fields (e.g., p->se.comm.on_rq). Are we cool with this?
Quoted 6 lines
I see once clash with my current ttwu patch set though, see:
http://lkml.org/lkml/2011/1/4/228
But that should be easy to resolve.
It's based on current tip, and yes, I plan to keep it updated and solve the clashes as soon as I run into them. :-)
Thanks and Regards,
Dario
Signature · 5 lines
<<This happens because I choose it to happen!>> (Raistlin Majere) ---------------------------------------------------------------------- Dario Faggioli, ReTiS Lab, Scuola Superiore Sant'Anna, Pisa (Italy) http://retis.sssup.it/people/faggioli -- [email protected]
Quoted 14 lines · Dario Faggioli
Quoted 5 lines
struct
task_group{#ifdef CONFIG_FAIR_GROUP_SCHED struct sched_entity **cfs_se; ...Quoted 9 lines
#endif
#ifdef CONFIG_RT_GROUP_SCHED struct sched_entity **rt_se; ...#endif
}
Quoted 7 lines
Well, sure this can be done. But what about the common fields? I guess you're suggesting to use something like `struct
sched_entity_common' and putting them there, aren't you?If yes, I'm fine with that, although it'll add one more level of indirection for those fields (e.g.,
p->se.comm.on_rq). Are we cool with this?
I'm pretty sure we're mis-understanding each other here, I meant to keep two complete sched_entity structures (both containing the common/fair/rt parts). That way, one can use the fair and the other the rt part.
Quoted 10 lines · Dario Faggioli
They're not inside an union yet, because I'm not sure on how to treat the task group case. In fact, tasks can only have _just_one_ scheduling policy at a time, and thus, for example, they need the
run_list_or_ therb_nodefor queueing (if the task is RT or fair, respectively), which is perfect with respect to using an union.
OTOH, groups are always considered both fair _and_ RT entities, for example they're always queued in _both_ an RTrun_listand a fair rb-tree. So I can't put them in an union, because I need both at the same time!
Suggestions on how to deal with that will be appreciated.
Don't forget the PI case too. You will need to change rt_mutex_setprio() to keep a copy of sched_cfs_entity in struct rt_mutex_waiter.
Peter, isn't sched_fair_entity a better name?
Lucas De Marchi
Quoted 4 lines · Lucas De Marchi
Peter, isn't
sched_fair_entitya better name?
Yeah, it probably is..
Quoted 5 lines · Peter Zijlstra
Quoted 3 lines
Peter, isn't
sched_fair_entitya better name?Yeah, it probably is..
As you wish. I know it's just one letter longer, but be prepared for it to break a lot of lines, since you may find four of it in a row! :-P
Thanks and Regards,
Dario
Signature · 5 lines
<<This happens because I choose it to happen!>> (Raistlin Majere) ---------------------------------------------------------------------- Dario Faggioli, ReTiS Lab, Scuola Superiore Sant'Anna, Pisa (Italy) http://retis.sssup.it/people/faggioli -- [email protected]
Quoted 6 lines · Lucas De Marchi
Quoted 1 line
Suggestions on how to deal with that will be appreciated.
Don't forget the PI case too. You will need to change
rt_mutex_setprio()to keep a copy ofsched_cfs_entityin structrt_mutex_waiter.
Mmm... do I? While I'm cloning your git, could you elaborate a bit on why, because I don't seem to see that... :-P
Thanks and Regards,
Dario
Signature · 5 lines
<<This happens because I choose it to happen!>> (Raistlin Majere) ---------------------------------------------------------------------- Dario Faggioli, ReTiS Lab, Scuola Superiore Sant'Anna, Pisa (Italy) http://retis.sssup.it/people/faggioli -- [email protected]
Quoted 9 lines · Dario Faggioli
Quoted 6 lines · Lucas De Marchi
Quoted 1 line
Suggestions on how to deal with that will be appreciated.
Don't forget the PI case too. You will need to change
rt_mutex_setprio()to keep a copy ofsched_cfs_entityin structrt_mutex_waiter.Mmm... do I? While I'm cloning your git, could you elaborate a bit on why, because I don't seem to see that... :-P
Suppose a RT task blocks on a PI-mutex, the lock owner will be boosted to RT and go through a class change in rt_mutex_setprio(). Since now a class change reinitializes the class-specific, if fair and rt fields are on the same memory space, we need to save the sched_fair_entity before changing the class to RT and put it again when going back to the fair class.
Quoting Peter about this:
[ Initially I was thinking not, because the task slept we'll have to
reinsert it in the rb-tree anyway, but upon further consideration that'll loose the old vruntime setting, which can lead to an unseemly gain of time in place_entity()'s never backward check failing.
So yes, we'd have to place a copy of the old sched_entity in struct rt_mutex_waiter, not very hard to do. ]
As a side-note: irc this is one thing i didn't do when i prepared that patches.
Lucas De Marchi
Quoted 10 lines · Lucas De Marchi
Quoted 2 lines
Mmm... do I? While I'm cloning your git, could you elaborate a bit on why, because I don't seem to see that... :-P
Suppose a RT task blocks on a PI-mutex, the lock owner will be boosted to RT and go through a class change in
rt_mutex_setprio(). Since now a class change reinitializes the class-specific, if fair and rt fields are on the same memory space, we need to save thesched_fair_entitybefore changing the class to RT and put it again when going back to the fair class.
Well, I know, but you're deactivating+dequeueing and then activating+enqueueing it back and forth within the proper scheduling class, so that shouldn't be a big deal...
Actually, the point might be that forgetting something like, e.g., vruntime would then lead to unexpected behaviour when the task is back to fair scheduling, but do we need to cache the whole sched_[cfs| fair]_entity for that?
Quoted 10 lines
Quoting Peter about this:
[ Initially I was thinking not, because the task slept we'll have to
reinsert it in the rb-tree anyway, but upon further consideration that'll loose the old vruntime setting, which can lead to an unseemly gain of time in place_entity()'s never backward check failing.So yes, we'd have to place a copy of the old
sched_entityin structrt_mutex_waiter, not very hard to do. ]
Ok, exactly, I now see that, and it's probably not hard to do... But I'm now thinking of how many fields must be saved to avoid this. Surely, not these ones:
...
struct rb_node run_node; struct list_head group_node;
#ifdef CONFIG_FAIR_GROUP_SCHED struct sched_cfs_entity *parent; /* rq on which this entity is (to be) queued: */ struct cfs_rq *cfs_rq; /* rq "owned" by this entity/group: */ struct cfs_rq *my_q;
#endif
...
I'll double check, but if it's just a matter of vruntime and a couple of other u64, isn't it worth to just save them?
Thanks and Regards,
Dario
Signature · 5 lines
<<This happens because I choose it to happen!>> (Raistlin Majere) ---------------------------------------------------------------------- Dario Faggioli, ReTiS Lab, Scuola Superiore Sant'Anna, Pisa (Italy) http://retis.sssup.it/people/faggioli -- [email protected]