cgroup: implement cgroup2 thread mode, v2
Subsystems (8)
Tejun Heo
maintainerPATCH 1/1 cgroup: implement cgroup2 thread mode, v2
Hello,
This is v2 of cgroup2 thread mode patchset. The changes from the last take[L] are
* Support for mixed thread mode for the root cgroup added. This allows the root cgroup to serve as both a thread root and a parent to domain cgroups. This allows users to use thread mode without any nesting while not interfering with domain level cgroup operations. Note that this simply makes use of the fact that the system root has always been exempt from no-internal-process constraint. The whole resource hierarchy still follows the same basic rules w.r.t. resource domains.
* Thread mode enable / disable now piggy backs on the existing control mask update mechanism rather than implementing manual css_set update mechanism of its own. This makes the mechanism simpler and more flexible.
* Fixes and cleanups, including a fix from Waiman.
It is largely based on the discussions that we had at the plumbers last year. Here's the rough outline.
* Thread mode is explicitly enabled on a cgroup by writing "enable" into "cgroup.threads" file. The cgroup shouldn't have any child cgroups or enabled controllers.
* Once enabled, arbitrary sub-hierarchy can be created and threads can be put anywhere in the subtree by writing TIDs into "cgroup.threads" file. Process granularity and no-internal-process constraint don't apply in a threaded subtree.
* To be used in a threaded subtree, controllers should explicitly declare thread mode support and should be able to handle internal competition in some way.
* The root of a threaded subtree serves as the resource domain for the whole subtree. This is where all the controllers are guaranteed to have a common ground and resource consumptions in the threaded subtree which aren't tied to a specific thread are charged. Non-threaded controllers never see beyond thread root and can assume that all controllers will follow the same rules upto that point.
* Root cgroup can enable thread mode anytime and a first level child can opt-in to that thread subtree anchored at root by writing "join" to "cgroup.threads" files, start its own thread subtree or just be a normal cgroup.
This allows threaded controllers to implement thread granular resource control without getting in the way of system level resource partitioning.
This patchset contains the following ten patches. For more details on the interface and behavior, please refer to 0007.
0001-cgroup-separate-out-cgroup_has_tasks.patch 0002-cgroup-reorganize-cgroup.procs-task-write-path.patch 0003-cgroup-Fix-reference-counting-bug-in-cgroup_procs_wr.patch 0004-cgroup-add-flags-to-css_task_iter_start-and-implemen.patch 0005-cgroup-introduce-cgroup-proc_cgrp-and-threaded-css_s.patch 0006-cgroup-implement-CSS_TASK_ITER_THREADED.patch 0007-cgroup-implement-cgroup-v2-thread-support.patch 0008-sched-Misc-preps-for-cgroup-unified-hierarchy-interf.patch 0009-sched-Implement-interface-for-cgroup-unified-hierarc.patch 0010-sched-Make-cpu-cpuacct-threaded-controllers.patch
0001-0007 implement cgroup2 thread mode. 0008-0010 enable CPU controller on cgroup2 and mark them as supporting thread mode. 0008-0010 are included for reference.
The patchset is based on the current master 179145e6312b ("Merge tag 'iommu-fixes-v4.12-rc4' ofgit://git.kernel.org/pub/scm/linux/kernel/git/joro/iommu") and also available in the following git branch.
git://git.kernel.org/pub/scm/linux/kernel/git/tj/cgroup.git review-cgroup2-threads-v2
diffstat follows.
Documentation/cgroup-v2.txt | 99 +++++ include/linux/cgroup-defs.h | 34 + include/linux/cgroup.h | 12 kernel/cgroup/cgroup-internal.h | 8 kernel/cgroup/cgroup-v1.c | 64 +++ kernel/cgroup/cgroup.c | 727 ++++++++++++++++++++++++++++++++-------- kernel/cgroup/cpuset.c | 6 kernel/cgroup/freezer.c | 6 kernel/cgroup/pids.c | 1 kernel/events/core.c | 1 kernel/sched/core.c | 150 ++++++++ kernel/sched/cpuacct.c | 53 ++ kernel/sched/cpuacct.h | 5 mm/memcontrol.c | 2 net/core/netclassid_cgroup.c | 2 15 files changed, 992 insertions(+), 178 deletions(-)
Thanks.
--
tejun
[L] http://lkml.kernel.org/r/20170202200632.13992-1-tj-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org
Tejun Heo
maintainerPATCH 1/10 cgroup: separate out cgroup_has_tasks()
Separate out cgroup_has_tasks() test from cgroup_subtree_control_write(). This will be used by the following changes.
This patch doesn't cause any behavior changes.
--- kernel/cgroup/cgroup.c | 49 +++++++++++++++++++++++++++---------------------- 1 file changed, 27 insertions(+), 22 deletions(-)
kernel/cgroup/cgroup.c +27 -22
@@ -581,6 +581,30 @@ static bool css_set_populated(struct css_set *cset)return !list_empty (&cset->tasks) || !list_empty (&cset->mg_tasks); } +static bool cgroup_has_tasks (struct cgroup *cgrp) +{ +struct cgrp_cset_link *link; +bool has_tasks = false; + +/* +* Because namespaces pin csets too, @cgrp->cset_links +* might not be empty even when @cgrp is empty. Walk and +* verify each cset. +*/ +spin_lock_irq (&css_set_lock); + +list_for_each_entry (link, &cgrp->cset_links, cset_link) { +if (css_set_populated (link->cset)) { + has_tasks = true; +break ; + } + } + +spin_unlock_irq (&css_set_lock); + +return has_tasks; +} +/** * cgroup_update_populated - updated populated count of a cgroup * @cgrp: the target cgroup
@@ -2886,28 +2910,9 @@ static ssize_t cgroup_subtree_control_write(struct kernfs_open_file *of,* Except for the root, subtree_control must be zero for a cgroup * with tasks so that child cgroups don't compete against tasks. */ -if (enable &&cgroup_parent (cgrp)) { -struct cgrp_cset_link *link; - -/* -* Because namespaces pin csets too, @cgrp->cset_links -* might not be empty even when @cgrp is empty. Walk and -* verify each cset. -*/ -spin_lock_irq (&css_set_lock); - - ret =0 ; -list_for_each_entry (link, &cgrp->cset_links, cset_link) { -if (css_set_populated (link->cset)) { - ret = -EBUSY ; -break ; - } - } - -spin_unlock_irq (&css_set_lock); - -if (ret) - goto out_unlock; +if (enable &&cgroup_parent (cgrp) &&cgroup_has_tasks (cgrp)) { + ret = -EBUSY ; + goto out_unlock; }/* save and update control masks and prepare csses */
Signature · 1 line
2.13.0
Tejun Heo
maintainerPATCH 2/10 cgroup: reorganize cgroup.procs / task write path
In reply to Tejun HeoCurrently, writes "cgroup.procs" and "cgroup.tasks" files are all handled by __cgroup_procs_write() on both v1 and v2. This patch reoragnizes the write path so that there are common helper functions that different write paths use.
While this somewhat increases LOC, the different paths are no longer intertwined and each path has more flexibility to implement different behaviors which will be necessary for the planned v2 thread support.
--- kernel/cgroup/cgroup-internal.h | 8 +- kernel/cgroup/cgroup-v1.c | 58 ++++++++++++-- kernel/cgroup/cgroup.c | 163 +++++++++++++++++++++------------------- 3 files changed, 142 insertions(+), 87 deletions(-)
kernel/cgroup/cgroup-internal.h +4 -4
@@ -180,10 +180,10 @@ int cgroup_migrate(struct task_struct *leader, bool threadgroup,int cgroup_attach_task (struct cgroup *dst_cgrp,struct task_struct *leader,bool threadgroup); -ssize_t __cgroup_procs_write (struct kernfs_open_file *of,char *buf, -size_t nbytes,loff_t off,bool threadgroup); -ssize_t cgroup_procs_write (struct kernfs_open_file *of,char *buf,size_t nbytes, -loff_t off); +struct task_struct *cgroup_procs_write_start (char *buf,bool threadgroup) + __acquires(&cgroup_threadgroup_rwsem); +void cgroup_procs_write_finish(void) + __releases(&cgroup_threadgroup_rwsem);void cgroup_lock_and_drain_offline (struct cgroup *cgrp);
kernel/cgroup/cgroup-v1.c +53 -5
77 lines not on this page · raw message
kernel/cgroup/cgroup.c +85 -78
208 lines not on this page · raw message
Signature · 1 line
2.13.0
Tejun Heo
maintainerPATCH 3/10 cgroup: Fix reference counting bug in cgroup_procs_write()
In reply to Tejun HeoFrom: Waiman Long <[email protected]>
The cgroup_procs_write_start() took a reference to the task structure which was not properly released within cgroup_procs_write() and so on. So a put_task_struct() call is added to cgroup_procs_write_finish() to match the get_task_struct() in cgroup_procs_write_start() to fix this reference counting error.
--- kernel/cgroup/cgroup-internal.h | 2 +- kernel/cgroup/cgroup-v1.c | 2 +- kernel/cgroup/cgroup.c | 8 +++++--- 3 files changed, 7 insertions(+), 5 deletions(-)
kernel/cgroup/cgroup-internal.h +1 -1
@@ -182,7 +182,7 @@ int cgroup_attach_task(struct cgroup *dst_cgrp, struct task_struct *leader, bool threadgroup);struct task_struct *cgroup_procs_write_start (char *buf,bool threadgroup) __acquires(&cgroup_threadgroup_rwsem); -void cgroup_procs_write_finish(void) +void cgroup_procs_write_finish(struct task_struct *task) __releases(&cgroup_threadgroup_rwsem);void cgroup_lock_and_drain_offline (struct cgroup *cgrp);
kernel/cgroup/cgroup-v1.c +1 -1
@@ -549,7 +549,7 @@ static ssize_t __cgroup1_procs_write(struct kernfs_open_file *of, ret =cgroup_attach_task (cgrp, task, threadgroup); out_finish: -cgroup_procs_write_finish (); +cgroup_procs_write_finish (task); out_unlock:cgroup_kn_unlock (of->kn);
kernel/cgroup/cgroup.c +5 -3
@@ -2438,12 +2438,15 @@ struct task_struct *cgroup_procs_write_start(char *buf, bool threadgroup)return tsk; } -void cgroup_procs_write_finish (void ) +void cgroup_procs_write_finish (struct task_struct *task) __releases(&cgroup_threadgroup_rwsem) {struct cgroup_subsys *ss;int ssid; +/* release reference from cgroup_procs_write_start() */ +put_task_struct (task); +percpu_up_write (&cgroup_threadgroup_rwsem);for_each_subsys (ss, ssid)if (ss->post_attach)
@@ -3102,7 +3105,6 @@ static int cgroup_addrm_files(struct cgroup_subsys_state *css,static int cgroup_apply_cftypes (struct cftype *cfts,bool is_add) { -LIST_HEAD (pending);struct cgroup_subsys *ss = cfts[0 ].ss;struct cgroup *root = &ss->root->cgrp;struct cgroup_subsys_state *css;
@@ -3793,7 +3795,7 @@ static ssize_t cgroup_procs_write(struct kernfs_open_file *of, ret =cgroup_attach_task (cgrp, task, true); out_finish: -cgroup_procs_write_finish (); +cgroup_procs_write_finish (task); out_unlock:cgroup_kn_unlock (of->kn);
Signature · 1 line
2.13.0
Tejun Heo
maintainerPATCH 4/10 cgroup: add @flags to css_task_iter_start() and implement CSS_TASK_ITER_PROCS
In reply to Tejun Heocss_task_iter currently always walks all tasks. With the scheduled cgroup v2 thread support, the iterator would need to handle multiple types of iteration. As a preparation, add @flags to css_task_iter_start() and implement CSS_TASK_ITER_PROCS. If the flag is not specified, it walks all tasks as before. When asserted, the iterator only walks the group leaders.
For now, the only user of the flag is cgroup v2 "cgroup.procs" file which no longer needs to skip non-leader tasks in cgroup_procs_next(). Note that cgroup v1 "cgroup.procs" can't use the group leader walk as v1 "cgroup.procs" doesn't mean "list all thread group leaders in the cgroup" but "list all thread group id's with any threads in the cgroup".
While at it, update cgroup_procs_show() to use task_pid_vnr() instead of task_tgid_vnr(). As the iteration guarantees that the function only sees group leaders, this doesn't change the output and will allow sharing the function for thread iteration.
--- include/linux/cgroup.h | 6 +++++- kernel/cgroup/cgroup-v1.c | 6 +++--- kernel/cgroup/cgroup.c | 24 ++++++++++++++---------- kernel/cgroup/cpuset.c | 6 +++--- kernel/cgroup/freezer.c | 6 +++--- mm/memcontrol.c | 2 +- net/core/netclassid_cgroup.c | 2 +- 7 files changed, 30 insertions(+), 22 deletions(-)
include/linux/cgroup.h +5 -1
@@ -36,9 +36,13 @@#define CGROUP_WEIGHT_DFL 100#define CGROUP_WEIGHT_MAX 10000 +/* walk only threadgroup leaders */ +#define CSS_TASK_ITER_PROCS (1U << 0) +/* a css_task_iter should be treated as an opaque object */ struct css_task_iter {struct cgroup_subsys *ss; +unsigned int flags;struct list_head *cset_pos;struct list_head *cset_head;
@@ -129,7 +133,7 @@ struct task_struct *cgroup_taskset_first(struct cgroup_taskset *tset,struct task_struct *cgroup_taskset_next (struct cgroup_taskset *tset,struct cgroup_subsys_state **dst_cssp); -void css_task_iter_start (struct cgroup_subsys_state *css, +void css_task_iter_start (struct cgroup_subsys_state *css,unsigned int flags,struct css_task_iter *it);struct task_struct *css_task_iter_next (struct css_task_iter *it);void css_task_iter_end (struct css_task_iter *it);
kernel/cgroup/cgroup-v1.c +3 -3
@@ -121,7 +121,7 @@ int cgroup_transfer_tasks(struct cgroup *to, struct cgroup *from)* ->can_attach() fails. */ do { - css_task_iter_start(&from->self, &it); + css_task_iter_start(&from->self, 0, &it); task = css_task_iter_next(&it); if (task) get_task_struct(task);
@@ -377,7 +377,7 @@ static int pidlist_array_load(struct cgroup *cgrp, enum cgroup_filetype type,if (!array)return -ENOMEM ;/* now, populate the array */ -css_task_iter_start (&cgrp->self, &it); +css_task_iter_start (&cgrp->self,0 , &it);while ((tsk =css_task_iter_next (&it))) {if (unlikely (n == length))break ;
@@ -753,7 +753,7 @@ int cgroupstats_build(struct cgroupstats *stats, struct dentry *dentry) }rcu_read_unlock (); -css_task_iter_start (&cgrp->self, &it); +css_task_iter_start (&cgrp->self,0 , &it);while ((tsk =css_task_iter_next (&it))) {switch (tsk->state) {case TASK_RUNNING :
kernel/cgroup/cgroup.c +14 -10
@@ -3602,6 +3602,7 @@ static void css_task_iter_advance(struct css_task_iter *it)lockdep_assert_held (&css_set_lock);WARN_ON_ONCE (!l); +repeat:/* * Advance iterator to find next entry. cset->tasks is consumed * first and then ->mg_tasks. After ->mg_tasks, we move onto the
@@ -3616,11 +3617,18 @@ static void css_task_iter_advance(struct css_task_iter *it)css_task_iter_advance_css_set (it); else it->task_pos = l; + +/* if PROCS, skip over tasks which aren't group leaders */ +if ((it->flags &CSS_TASK_ITER_PROCS ) && it->task_pos && + !thread_group_leader(list_entry(it->task_pos, struct task_struct, + cg_list))) + goto repeat; }/** * css_task_iter_start - initiate task iteration * @css: the css to walk tasks of +* @flags: CSS_TASK_ITER_* flags * @it: the task iterator to use * * Initiate iteration through the tasks of @css. The caller can call
@@ -3628,7 +3636,7 @@ static void css_task_iter_advance(struct css_task_iter *it)* returns NULL. On completion of iteration, css_task_iter_end() must be * called. */ -void css_task_iter_start (struct cgroup_subsys_state *css, +void css_task_iter_start (struct cgroup_subsys_state *css,unsigned int flags,struct css_task_iter *it) {/* no one should try to iterate before mounting cgroups */
@@ -3639,6 +3647,7 @@ void css_task_iter_start(struct cgroup_subsys_state *css,spin_lock_irq (&css_set_lock); it->ss = css->ss; + it->flags = flags;if (it->ss) it->cset_pos = &css->cgroup->e_csets[css->ss->id];
@@ -3712,13 +3721,8 @@ static void *cgroup_procs_next(struct seq_file *s, void *v, loff_t *pos) {struct kernfs_open_file *of = s->private;struct css_task_iter *it = of->priv; -struct task_struct *task; - -do { - task =css_task_iter_next (it); - }while (task && !thread_group_leader (task)); -return task; +return css_task_iter_next (it); }static void *cgroup_procs_start (struct seq_file *s,loff_t *pos)
@@ -3739,10 +3743,10 @@ static void *cgroup_procs_start(struct seq_file *s, loff_t *pos)if (!it)return ERR_PTR (-ENOMEM ); of->priv = it; -css_task_iter_start (&cgrp->self, it); +css_task_iter_start (&cgrp->self,CSS_TASK_ITER_PROCS , it); }else if (!(*pos)++) {css_task_iter_end (it); -css_task_iter_start (&cgrp->self, it); +css_task_iter_start (&cgrp->self,CSS_TASK_ITER_PROCS , it); }return cgroup_procs_next (s,NULL ,NULL );
@@ -3750,7 +3754,7 @@ static void *cgroup_procs_start(struct seq_file *s, loff_t *pos)static int cgroup_procs_show (struct seq_file *s,void *v) { -seq_printf (s,"%d\n" ,task_tgid_vnr (v)); +seq_printf (s,"%d\n" ,task_pid_vnr (v));return 0 ; }
kernel/cgroup/cpuset.c +3 -3
@@ -861,7 +861,7 @@ static void update_tasks_cpumask(struct cpuset *cs)struct css_task_iter it;struct task_struct *task; -css_task_iter_start (&cs->css, &it); +css_task_iter_start (&cs->css,0 , &it);while ((task =css_task_iter_next (&it)))set_cpus_allowed_ptr (task, cs->effective_cpus);css_task_iter_end (&it);
@@ -1106,7 +1106,7 @@ static void update_tasks_nodemask(struct cpuset *cs)* It's ok if we rebind the same mm twice; mpol_rebind_mm() * is idempotent. Also migrate pages in each mm to new nodes. */ -css_task_iter_start (&cs->css, &it); +css_task_iter_start (&cs->css,0 , &it);while ((task =css_task_iter_next (&it))) {struct mm_struct *mm;bool migrate;
@@ -1299,7 +1299,7 @@ static void update_tasks_flags(struct cpuset *cs)struct css_task_iter it;struct task_struct *task; -css_task_iter_start (&cs->css, &it); +css_task_iter_start (&cs->css,0 , &it);while ((task =css_task_iter_next (&it)))cpuset_update_task_spread_flag (cs, task);css_task_iter_end (&it);
kernel/cgroup/freezer.c +3 -3
@@ -268,7 +268,7 @@ static void update_if_frozen(struct cgroup_subsys_state *css)rcu_read_unlock ();/* are all tasks frozen? */ -css_task_iter_start (css, &it); +css_task_iter_start (css,0 , &it);while ((task =css_task_iter_next (&it))) {if (freezing (task)) {
@@ -320,7 +320,7 @@ static void freeze_cgroup(struct freezer *freezer)struct css_task_iter it;struct task_struct *task; -css_task_iter_start (&freezer->css, &it); +css_task_iter_start (&freezer->css,0 , &it);while ((task =css_task_iter_next (&it)))freeze_task (task);css_task_iter_end (&it);
@@ -331,7 +331,7 @@ static void unfreeze_cgroup(struct freezer *freezer)struct css_task_iter it;struct task_struct *task; -css_task_iter_start (&freezer->css, &it); +css_task_iter_start (&freezer->css,0 , &it);while ((task =css_task_iter_next (&it)))__thaw_task (task);css_task_iter_end (&it);
mm/memcontrol.c +1 -1
@@ -917,7 +917,7 @@ int mem_cgroup_scan_tasks(struct mem_cgroup *memcg,struct css_task_iter it;struct task_struct *task; -css_task_iter_start (&iter->css, &it); +css_task_iter_start (&iter->css,0 , &it);while (!ret && (task =css_task_iter_next (&it))) ret =fn (task, arg);css_task_iter_end (&it);
net/core/netclassid_cgroup.c +1 -1
@@ -100,7 +100,7 @@ static int write_classid(struct cgroup_subsys_state *css, struct cftype *cft, cs->classid = (u32 )value; -css_task_iter_start (css, &it); +css_task_iter_start (css,0 , &it);while ((p =css_task_iter_next (&it))) {task_lock (p); iterate_fd(p->files, 0, update_classid_sock,
Signature · 1 line
2.13.0
Tejun Heo
maintainerPATCH 5/10 cgroup: introduce cgroup->proc_cgrp and threaded css_set handling
In reply to Tejun Heocgroup v2 is in the process of growing thread granularity support. Once thread mode is enabled, the root cgroup of the subtree serves as the proc_cgrp to which the processes of the subtree conceptually belong and domain-level resource consumptions not tied to any specific task are charged. In the subtree, threads won't be subject to process granularity or no-internal-task constraint and can be distributed arbitrarily across the subtree.
This patch introduces cgroup->proc_cgrp along with threaded css_set handling.
* cgroup->proc_cgrp is NULL if !threaded. If threaded, points to the proc_cgrp (root of the threaded subtree).
* css_set->proc_cset points to self if !threaded. If threaded, points to the css_set which belongs to the cgrp->proc_cgrp. The proc_cgrp serves as the resource domain and needs the matching csses readily available. The proc_cset holds those csses and makes them easily accessible.
* All threaded csets are linked on their proc_csets to enable iteration of all threaded tasks.
This patch adds the above but doesn't actually use them yet. The following patches will build on top.
v2: Added cgroup_is_threaded() helper.
--- include/linux/cgroup-defs.h | 22 +++++++++++ kernel/cgroup/cgroup.c | 93 ++++++++++++++++++++++++++++++++++++++++++--- 2 files changed, 109 insertions(+), 6 deletions(-)
include/linux/cgroup-defs.h +22 -0
@@ -163,6 +163,15 @@ struct css_set {/* reference count */ refcount_t refcount; +/* +* If not threaded, the following points to self. If threaded, to +* a cset which belongs to the top cgroup of the threaded subtree. +* The proc_cset provides access to the process cgroup and its +* csses to which domain level resource consumptions should be +* charged. +*/ +struct css_set __rcu *proc_cset; +/* the default cgroup associated with this css_set */ struct cgroup *dfl_cgrp;
@@ -188,6 +197,10 @@ struct css_set {*/ struct list_head e_cset_node[CGROUP_SUBSYS_COUNT ]; +/* all csets whose ->proc_cset points to this cset */ +struct list_head threaded_csets; +struct list_head threaded_csets_node; +/* * List running through all cgroup groups in the same hash * slot. Protected by css_set_lock
@@ -294,6 +307,15 @@ struct cgroup {struct list_head e_csets[CGROUP_SUBSYS_COUNT ];/* +* If !threaded, NULL. If threaded, it points to the top cgroup of +* the threaded subtree, on which it points to self. Threaded +* subtree is exempt from process granularity and no-internal-task +* constraint. Domain level resource consumptions which aren't +* tied to a specific task should be charged to the proc_cgrp. +*/ +struct cgroup *proc_cgrp; + +/* * list of pidlists, up to two for each namespace (one for procs, one * for tasks); created on demand. */
kernel/cgroup/cgroup.c +87 -6
197 lines not on this page · raw message
Signature · 1 line
2.13.0
Tejun Heo
maintainerPATCH 6/10 cgroup: implement CSS_TASK_ITER_THREADED
In reply to Tejun Heocgroup v2 is in the process of growing thread granularity support. Once thread mode is enabled, the root cgroup of the subtree serves as the proc_cgrp to which the processes of the subtree conceptually belong and domain-level resource consumptions not tied to any specific task are charged. In the subtree, threads won't be subject to process granularity or no-internal-task constraint and can be distributed arbitrarily across the subtree.
This patch implements a new task iterator flag CSS_TASK_ITER_THREADED, which, when used on a proc_cgrp, makes the iteration include the tasks on all the associated threaded css_sets. "cgroup.procs" read path is updated to use it so that reading the file on a proc_cgrp lists all processes. This will also be used by controller implementations which need to walk processes or tasks at the resource domain level.
Task iteration is implemented nested in css_set iteration. If CSS_TASK_ITER_THREADED is specified, after walking tasks of each !threaded css_set, all the associated threaded css_sets are visited before moving onto the next !threaded css_set.
--- include/linux/cgroup.h | 6 ++++ kernel/cgroup/cgroup.c | 81 +++++++++++++++++++++++++++++++++++++++++--------- 2 files changed, 73 insertions(+), 14 deletions(-)
include/linux/cgroup.h +6 -0
@@ -38,6 +38,8 @@/* walk only threadgroup leaders */ #define CSS_TASK_ITER_PROCS (1U << 0) +/* walk threaded css_sets as part of their proc_csets */ +#define CSS_TASK_ITER_THREADED (1U << 1)/* a css_task_iter should be treated as an opaque object */ struct css_task_iter {
@@ -47,11 +49,15 @@ struct css_task_iter {struct list_head *cset_pos;struct list_head *cset_head; +struct list_head *tcset_pos; +struct list_head *tcset_head; +struct list_head *task_pos;struct list_head *tasks_head;struct list_head *mg_tasks_head;struct css_set *cur_cset; +struct css_set *cur_pcset;struct task_struct *cur_task;struct list_head iters_node;/* css_set->task_iters */ };
kernel/cgroup/cgroup.c +67 -14
126 lines not on this page · raw message
Signature · 1 line
2.13.0
Tejun Heo
maintainerPATCH 7/10 cgroup: implement cgroup v2 thread support
In reply to Tejun HeoThis patch implements cgroup v2 thread support. The goal of the thread mode is supporting hierarchical accounting and control at thread granularity while staying inside the resource domain model which allows coordination across different resource controllers and handling of anonymous resource consumptions.
Once thread mode is enabled on a cgroup, the threads of the processes which are in its subtree can be placed inside the subtree without being restricted by process granularity or no-internal-process constraint. Note that the threads aren't allowed to escape to a different threaded subtree. To be used inside a threaded subtree, a controller should explicitly support threaded mode and be able to handle internal competition in the way which is appropriate for the resource.
The root of a threaded subtree, where thread mode is enabled in the first place, is called the thread root and serves as the resource domain for the whole subtree. This is the last cgroup where non-threaded controllers are operational and where all the domain-level resource consumptions in the subtree are accounted. This allows threaded controllers to operate at thread granularity when requested while staying inside the scope of system-level resource distribution.
As the root cgroup is exempt from the no-internal-process constraint, it can serve as both a thread root and a parent to normal cgroups. The root cgroup supports mixed cgroup mode which can be enabled and disabled anytime as long as there aren't any threaded children. First level child cgroups can selectively join the mixed threaded subtree.
Internally, in a threaded subtree, each css_set has its ->proc_cset pointing to a matching css_set which belongs to the thread root. This ensures that thread root level cgroup_subsys_state for all threaded controllers are readily accessible for domain-level operations.
This patch enables threaded mode for the pids and perf_events controllers. Neither has to worry about domain-level resource consumptions and it's enough to simply set the flag.
For more details on the interface and behavior of the thread mode, please refer to the section 2-2-2 in Documentation/cgroup-v2.txt added by this patch. Note that the documentation update is not complete as the rest of the documentation needs to be updated accordingly. Rolling those updates into this patch can be confusing so that will be separate patches.
v2: - After discussions with Waiman, support for mixed thread mode is
added. This should address the issue that Peter pointed out where any nesting should be avoided for thread subtrees while coexisting with other domain cgroups.
- Enabling / disabling thread mode now piggy backs on the existing control mask update mechanism.
- Bug fixes and cleanup.
--- Documentation/cgroup-v2.txt | 99 +++++++++++++- include/linux/cgroup-defs.h | 12 ++ kernel/cgroup/cgroup.c | 323 ++++++++++++++++++++++++++++++++++++++++++-- kernel/cgroup/pids.c | 1 + kernel/events/core.c | 1 + 5 files changed, 420 insertions(+), 16 deletions(-)
Documentation/cgroup-v2.txt +97 -2
@@ -16,7 +16,9 @@ CONTENTS 1-2. What is cgroup? 2. Basic Operations 2-1. Mounting - 2-2. Organizing Processes + 2-2. Organizing Processes and Threads + 2-2-1. Processes + 2-2-2. Threads 2-3. [Un]populated Notification 2-4. Controlling Controllers 2-4-1. Enabling and Disabling
@@ -150,7 +152,9 @@ and experimenting easier, the kernel parameter cgroup_no_v1= allows disabling controllers in v1 and make them always available in v2. -2-2. Organizing Processes +2-2. Organizing Processes and Threads + +2-2-1. Processes Initially, only the root cgroup exists to which all processes belong. A child cgroup can be created by creating a sub-directory.
@@ -201,6 +205,97 @@ is removed subsequently, " (deleted)" is appended to the path. 0::/test-cgroup/test-cgroup-nested (deleted) +2-2-2. Threads + +cgroup v2 supports thread granularity for a subset of controllers to +support use cases requiring hierarchical resource distribution across +the threads of a group of processes. By default, all threads of a +process belong to the same cgroup, which also serves as the resource +domain to host resource consumptions which are not specific to a +process or thread. The thread mode allows threads to be spread across +a subtree while still maintaining the common resource domain for them. + +Enabling thread mode on a subtree makes it threaded. The root of a +threaded subtree is called thread root and serves as the resource +domain for the entire subtree. In a threaded subtree, threads of a +process can be put in different cgroups and are not subject to the no +internal process constraint - threaded controllers can be enabled on +non-leaf cgroups whether they have threads in them or not. + +Because the root cgroup is not subject to no internal process +constraint, it can serve both as a thread root and a parent to normal +cgroups. This is called mixed thread mode. + +Thread mode can be enabled by writing "enable" to "cgroup.threads" +file. + + # echo enable > cgroup.threads + +On a non-root cgroup, to enable the thread mode, the following +conditions must be met. + +- The thread root doesn't have any child cgroups. + +- The thread root doesn't have any controllers enabled. + +On the root cgroup, only the mixed thread mode is supported and there +isn't any restriction on enabling it. On enable, unlike the normal +thread mode, the whole subtree is not turned into thread subtree. The +first level children have to explicitly join the thread subtree. A +cgroup can join the existing mixed threaded subtree by writing "join" +to "cgroup.threads" file. + + # echo join > cgroup.threads + +In addition to the usual enable conditions, the following extra +condition must met for joining. + +- The first level child doesn't have any tasks. + +Inside a threaded subtree, "cgroup.threads" can be read and contains +the list of the thread IDs of all threads in the cgroup. Except that +the operations are per-thread instead of per-process, "cgroup.threads" +has the same format and behaves the same way as "cgroup.procs". + +The thread root serves as the resource domain for the whole subtree, +and, while the threads can be scattered across the subtree, all the +processes are considered to be in the thread root. "cgroup.procs" in +a thread root contains the PIDs of all processes in the subtree and is +not readable in the subtree proper. However, "cgroup.procs" can be +written to from anywhere in the subtree to migrate all threads of the +matching process to the cgroup. + +Only threaded controllers can be enabled in a threaded subtree. When +a threaded controller is enabled inside a threaded subtree, it only +accounts for and controls resource consumptions associated with the +threads in the cgroup and its descendants. All consumptions which +aren't tied to a specific thread belong to the thread root. + +Because a threaded subtree is exempt from no internal process +constraint, a threaded controller must be able to handle competition +between threads in a non-leaf cgroup and its child cgroups. Each +threaded controller defines how such competitions are handled. + +Thread mode can be disabled by writing "disable" to "cgroup.threads" +file. + + # echo disable > cgroup.threads + +Disabling requires the same conditions as enabling and the following +extra. + +For a non-mixed threaded subtree: + +- The cgroup must be the thread root. Thread mode can't be disabled + partially in the subtree. + +For the root cgroup: + +- There can't be any child cgroup which is a part of the mixed thread + subtree. All first level children must be either non-threaded or + thread roots. + + 2-3. [Un]populated Notification Each non-root cgroup has a "cgroup.events" file which contains
include/linux/cgroup-defs.h +12 -0
@@ -502,6 +502,18 @@ struct cgroup_subsys { bool implicit_on_dfl:1;/* +* If %true, the controller, supports threaded mode on the default +* hierarchy. In a threaded subtree, both process granularity and +* no-internal-process constraint are ignored and a threaded +* controllers should be able to handle that. +* +* Note that as an implicit controller is automatically enabled on +* all cgroups on the default hierarchy, it should also be +* threaded. implicit && !threaded is not supported. +*/ + bool threaded:1; + +/* * If %false, this subsystem is properly hierarchical - * configuration, resource accounting and restriction on a parent * cgroup cover those of its children. If %true, hierarchy support
kernel/cgroup/cgroup.c +309 -14
415 lines not on this page · raw message
kernel/cgroup/pids.c +1 -0
@@ -345,4 +345,5 @@ struct cgroup_subsys pids_cgrp_subsys = { .free = pids_free, .legacy_cftypes = pids_files, .dfl_cftypes = pids_files, + .threaded = true, };
kernel/events/core.c +1 -0
@@ -11134,5 +11134,6 @@ struct cgroup_subsys perf_event_cgrp_subsys = {* controller is not mounted on a legacy hierarchy. */ .implicit_on_dfl = true, + .threaded = true, };#endif /* CONFIG_CGROUP_PERF */
Signature · 1 line
2.13.0
Waiman Long
maintainerRe: [PATCH 07/10] cgroup: implement cgroup v2 thread support
Quoted 30 lines · Tejun Heo
This patch implements cgroup v2 thread support. The goal of the thread mode is supporting hierarchical accounting and control at thread granularity while staying inside the resource domain model which allows coordination across different resource controllers and handling of anonymous resource consumptions.
Once thread mode is enabled on a cgroup, the threads of the processes which are in its subtree can be placed inside the subtree without being restricted by process granularity or no-internal-process constraint. Note that the threads aren't allowed to escape to a different threaded subtree. To be used inside a threaded subtree, a controller should explicitly support threaded mode and be able to handle internal competition in the way which is appropriate for the resource.
The root of a threaded subtree, where thread mode is enabled in the first place, is called the thread root and serves as the resource domain for the whole subtree. This is the last cgroup where non-threaded controllers are operational and where all the domain-level resource consumptions in the subtree are accounted. This allows threaded controllers to operate at thread granularity when requested while staying inside the scope of system-level resource distribution.
As the root cgroup is exempt from the no-internal-process constraint, it can serve as both a thread root and a parent to normal cgroups. The root cgroup supports mixed cgroup mode which can be enabled and disabled anytime as long as there aren't any threaded children. First level child cgroups can selectively join the mixed threaded subtree.
Quoted 4 lines
Internally, in a threaded subtree, each
css_sethas its ->proc_cset pointing to a matchingcss_setwhich belongs to the thread root. This ensures that thread root levelcgroup_subsys_statefor all threaded controllers are readily accessible for domain-level operations.
As far as I understand, the proc_cset thing is just for cgroup.procs iteration purpose. They are not used for accessing cgroup_subsys_state for domain-level operation. In fact, all the relevant CSSes will be available in the local css_set and there is no need to look elsewhere.
Quoted 38 lines
This patch enables threaded mode for the pids and
perf_eventscontrollers. Neither has to worry about domain-level resource consumptions and it's enough to simply set the flag.For more details on the interface and behavior of the thread mode, please refer to the section 2-2-2 in
Documentation/cgroup-v2.txtadded by this patch. Note that the documentation update is not complete as the rest of the documentation needs to be updated accordingly. Rolling those updates into this patch can be confusing so that will be separate patches.v2: - After discussions with Waiman, support for mixed thread mode is
added. This should address the issue that Peter pointed out where any nesting should be avoided for thread subtrees while coexisting with other domain cgroups.- Enabling / disabling thread mode now piggy backs on the existing control mask update mechanism.
- Bug fixes and cleanup.
Signed-off-by Tejun Heo <[email protected]>Cc Waiman Long <[email protected]>--- Documentation/cgroup-v2.txt | 99 +++++++++++++- include/linux/cgroup-defs.h | 12 ++ kernel/cgroup/cgroup.c | 323 ++++++++++++++++++++++++++++++++++++++++++-- kernel/cgroup/pids.c | 1 + kernel/events/core.c | 1 + 5 files changed, 420 insertions(+), 16 deletions(-)kernel/cgroup/cgroup.c +6
-0+/* is @cgrp root of a threaded subtree? */ +static bool cgroup_is_thread_root (struct cgroup *cgrp) +{ +return cgrp->proc_cgrp == cgrp; +} +
kernel/cgroup/cgroup.c static bool cgroup_is_threaded(struct cgroup *cgrp) · line 352
Quoted 10 lines
kernel/cgroup/cgroup.c +10
-0+/* if threaded, would @cgrp become root of a mixed threaded subtree? */ +static bool cgroup_is_mixable (struct cgroup *cgrp) +{ +/* +* Root isn't under domain level resource control exempting it from +* the no-internal-process constraint, so it can serve as a thread +* root and a parent of resource domains at the same time. +*/ +return !cgroup_parent (cgrp); +}
Eventually, I would like to see a container root to be regarded as mixable so that it will look and feel like a real root to the container. Yes, that will mean having to deal with internal process competition with resource domain controllers. If we are going to keep the no internal process constraint, this is the other exception that I would like to have. We can work around that by having, for example, special directory for resource domain controllers to manage their resources like what I have proposed in the resource domain patch. Or we can just let those resource domain controllers to deal with it.
Cheers,
Longman
Tejun Heo
maintainerRe: [PATCH 07/10] cgroup: implement cgroup v2 thread support
Hello, Waiman.
Quoted 9 lines · Waiman Long
Quoted 4 lines
Internally, in a threaded subtree, each
css_sethas its ->proc_cset pointing to a matchingcss_setwhich belongs to the thread root. This ensures that thread root levelcgroup_subsys_statefor all threaded controllers are readily accessible for domain-level operations.As far as I understand, the
proc_csetthing is just for cgroup.procs iteration purpose. They are not used for accessingcgroup_subsys_statefor domain-level operation. In fact, all the relevant CSSes will be available in the localcss_setand there is no need to look elsewhere.
Because none is implementing domain resource accounting. Once we start doing that, we'll have to charge them against domain csses not the thread ones.
Quoted 12 lines
kernel/cgroup/cgroup.c static bool cgroup_is_threaded(struct cgroup *cgrp) · line 352
Quoted 10 lines
kernel/cgroup/cgroup.c +10
-0+/* if threaded, would @cgrp become root of a mixed threaded subtree? */ +static bool cgroup_is_mixable (struct cgroup *cgrp) +{ +/* +* Root isn't under domain level resource control exempting it from +* the no-internal-process constraint, so it can serve as a thread +* root and a parent of resource domains at the same time. +*/ +return !cgroup_parent (cgrp); +}Eventually, I would like to see a container root to be regarded as
Quoted 8 lines
mixable so that it will look and feel like a real root to the container. Yes, that will mean having to deal with internal process competition with resource domain controllers. If we are going to keep the no internal process constraint, this is the other exception that I would like to have. We can work around that by having, for example, special directory for resource domain controllers to manage their resources like what I have proposed in the resource domain patch. Or we can just let those resource domain controllers to deal with it.
Yeah, the code and semantics are structured for future expansion. That said, such expansion has to mean something inherently useful. Up until now, all that have been suggested are either cosmetic or not clearly defined and IMHO do more to obscure what's going on rather than enable anything fundamental. What we do with the interface should follow the function. If we can come up with a way to lift the restriction on an internal node which enables some fundamental capabilities in a clearly defined manner, let's of course do that, but we shouldn't do that just because we feel like to.
Thanks.
Signature · 1 line
tejun
Tejun Heo
maintainerPATCH v3 7/10 cgroup: implement cgroup v2 thread support
In reply to Tejun HeoThis patch implements cgroup v2 thread support. The goal of the thread mode is supporting hierarchical accounting and control at thread granularity while staying inside the resource domain model which allows coordination across different resource controllers and handling of anonymous resource consumptions.
Once thread mode is enabled on a cgroup, the threads of the processes which are in its subtree can be placed inside the subtree without being restricted by process granularity or no-internal-process constraint. Note that the threads aren't allowed to escape to a different threaded subtree. To be used inside a threaded subtree, a controller should explicitly support threaded mode and be able to handle internal competition in the way which is appropriate for the resource.
The root of a threaded subtree, where thread mode is enabled in the first place, is called the thread root and serves as the resource domain for the whole subtree. This is the last cgroup where non-threaded controllers are operational and where all the domain-level resource consumptions in the subtree are accounted. This allows threaded controllers to operate at thread granularity when requested while staying inside the scope of system-level resource distribution.
As the root cgroup is exempt from the no-internal-process constraint, it can serve as both a thread root and a parent to normal cgroups. The root cgroup supports mixed cgroup mode which can be enabled and disabled anytime as long as there aren't any threaded children. First level child cgroups joins the mixed threaded subtree when thread mode is enabled on them.
Internally, in a threaded subtree, each css_set has its ->proc_cset pointing to a matching css_set which belongs to the thread root. This ensures that thread root level cgroup_subsys_state for all threaded controllers are readily accessible for domain-level operations.
This patch enables threaded mode for the pids and perf_events controllers. Neither has to worry about domain-level resource consumptions and it's enough to simply set the flag.
For more details on the interface and behavior of the thread mode, please refer to the section 2-2-2 in Documentation/cgroup-v2.txt added by this patch. Note that the documentation update is not complete as the rest of the documentation needs to be updated accordingly. Rolling those updates into this patch can be confusing so that will be separate patches.
v3: - Dropped "join" and always make mixed children join the parent's
threaded subtree.
v2: - After discussions with Waiman, support for mixed thread mode is
added. This should address the issue that Peter pointed out where any nesting should be avoided for thread subtrees while coexisting with other domain cgroups.
- Enabling / disabling thread mode now piggy backs on the existing control mask update mechanism.
- Bug fixes and cleanup.
---
Hello,
This is the alternative version where we don't support topologies like the following.
root (thread mode)
/ \
/ \
/ \
A B (member of root's (root of its own
thread subtree) thread subtree)
Supporting or not supporting the above topology only has user interface implications. Supporting it means more complication or ugliness in the interface. Not supporting it obviously results in a simpler interface but at the cost of some of the flexibility of thread mode.
Choosing one over the other is unlikely to result in substantial actual differences.
Thanks.
Documentation/cgroup-v2.txt | 111 +++++++++++++++ include/linux/cgroup-defs.h | 12 + kernel/cgroup/cgroup.c | 310 ++++++++++++++++++++++++++++++++++++++++++-- kernel/cgroup/pids.c | 1 kernel/events/core.c | 1 5 files changed, 419 insertions(+), 16 deletions(-)
Documentation/cgroup-v2.txt +109 -2
@@ -16,7 +16,9 @@ CONTENTS 1-2. What is cgroup? 2. Basic Operations 2-1. Mounting - 2-2. Organizing Processes + 2-2. Organizing Processes and Threads + 2-2-1. Processes + 2-2-2. Threads 2-3. [Un]populated Notification 2-4. Controlling Controllers 2-4-1. Enabling and Disabling
@@ -150,7 +152,9 @@ and experimenting easier, the kernel par disabling controllers in v1 and make them always available in v2. -2-2. Organizing Processes +2-2. Organizing Processes and Threads + +2-2-1. Processes Initially, only the root cgroup exists to which all processes belong. A child cgroup can be created by creating a sub-directory.
@@ -201,6 +205,109 @@ is removed subsequently, " (deleted)" is 0::/test-cgroup/test-cgroup-nested (deleted) +2-2-2. Threads + +cgroup v2 supports thread granularity for a subset of controllers to +support use cases requiring hierarchical resource distribution across +the threads of a group of processes. By default, all threads of a +process belong to the same cgroup, which also serves as the resource +domain to host resource consumptions which are not specific to a +process or thread. The thread mode allows threads to be spread across +a subtree while still maintaining the common resource domain for them. + +Enabling thread mode on a subtree makes it threaded. The root of a +threaded subtree is called thread root and serves as the resource +domain for the entire subtree. In a threaded subtree, threads of a +process can be put in different cgroups and are not subject to the no +internal process constraint - threaded controllers can be enabled on +non-leaf cgroups whether they have threads in them or not. + +Because the root cgroup is not subject to no internal process +constraint, it can serve both as a thread root and a parent to normal +cgroups. This is called mixed thread mode. + +Thread mode can be enabled by writing "enable" to "cgroup.threads" +file. + + # echo enable > cgroup.threads + +On a non-root cgroup, to enable the thread mode, the following +conditions must be met. + +- The thread root doesn't have any child cgroups. + +- The thread root doesn't have any controllers enabled. + +On the root cgroup, only the mixed thread mode is supported. The +following condition should be met to enable. + +- The root cgroup doesn't have any threaded children. + +Unlike the normal thread mode, the whole subtree is not turned into +thread subtree. The first level children have to explicitly opt-in to +join the thread subtree by enabling thread mode. To join the thread +subtree, a first level child must meet the following conditions. + +- The first level child doesn't have any child cgroups. + +- The first level child doesn't have any controllers enabled. + +- The first level child doesn't have any tasks. + +Inside a threaded subtree, "cgroup.threads" can be read and contains +the list of the thread IDs of all threads in the cgroup. Except that +the operations are per-thread instead of per-process, "cgroup.threads" +has the same format and behaves the same way as "cgroup.procs". + +The thread root serves as the resource domain for the whole subtree, +and, while the threads can be scattered across the subtree, all the +processes are considered to be in the thread root. "cgroup.procs" in +a thread root contains the PIDs of all processes in the subtree and is +not readable in the subtree proper. However, "cgroup.procs" can be +written to from anywhere in the subtree to migrate all threads of the +matching process to the cgroup. + +Only threaded controllers can be enabled in a threaded subtree. When +a threaded controller is enabled inside a threaded subtree, it only +accounts for and controls resource consumptions associated with the +threads in the cgroup and its descendants. All consumptions which +aren't tied to a specific thread belong to the thread root. + +Because a threaded subtree is exempt from no internal process +constraint, a threaded controller must be able to handle competition +between threads in a non-leaf cgroup and its child cgroups. Each +threaded controller defines how such competitions are handled. + +Thread mode can be disabled by writing "disable" to "cgroup.threads" +file. + + # echo disable > cgroup.threads + +On a normal thread subtree, to disable the thread mode, the following +conditions must be met. + +- The cgroup is a thread root. Thread mode can't be disabled + partially in the subtree. + +- The thread root doesn't have any child cgroups. + +- The thread root doesn't have any controllers enabled. + +On the root cgroup, to disable the mixed thread mode, the following +condition should be met. + +- The root cgroup doesn't have any threaded children. + +On a first level child of the mixed thread subtree, the following +conditions should be met. + +- The first level child doesn't have any child cgroups. + +- The first level child doesn't have any controllers enabled. + +- The first level child doesn't have any tasks. + + 2-3. [Un]populated Notification Each non-root cgroup has a "cgroup.events" file which contains
include/linux/cgroup-defs.h +12 -0
@@ -505,6 +505,18 @@ struct cgroup_subsys { bool implicit_on_dfl:1;/* +* If %true, the controller, supports threaded mode on the default +* hierarchy. In a threaded subtree, both process granularity and +* no-internal-process constraint are ignored and a threaded +* controllers should be able to handle that. +* +* Note that as an implicit controller is automatically enabled on +* all cgroups on the default hierarchy, it should also be +* threaded. implicit && !threaded is not supported. +*/ + bool threaded:1; + +/* * If %false, this subsystem is properly hierarchical - * configuration, resource accounting and restriction on a parent * cgroup cover those of its children. If %true, hierarchy support
kernel/cgroup/cgroup.c +296 -14
402 lines not on this page · raw message
kernel/cgroup/pids.c +1 -0
@@ -345,4 +345,5 @@ struct cgroup_subsys pids_cgrp_subsys = .free = pids_free, .legacy_cftypes = pids_files, .dfl_cftypes = pids_files, + .threaded = true, };
kernel/events/core.c +1 -0
@@ -11155,5 +11155,6 @@ struct cgroup_subsys perf_event_cgrp_sub* controller is not mounted on a legacy hierarchy. */ .implicit_on_dfl = true, + .threaded = true, };#endif /* CONFIG_CGROUP_PERF */
Tejun Heo
maintainerPATCH 8/10 sched: Misc preps for cgroup unified hierarchy interface
In reply to Tejun HeoMake the following changes in preparation for the cpu controller interface implementation for the unified hierarchy. This patch doesn't cause any functional differences.
* s/cpu_stats_show()/cpu_cfs_stats_show()/
* s/cpu_files/cpu_legacy_files/
* Separate out cpuacct_stats_read() from cpuacct_stats_show(). While at it, make the @val array u64 for consistency.
--- kernel/sched/core.c | 8 ++++---- kernel/sched/cpuacct.c | 29 ++++++++++++++++++----------- 2 files changed, 22 insertions(+), 15 deletions(-)
kernel/sched/core.c +4 -4
@@ -7246,7 +7246,7 @@ static int __cfs_schedulable(struct task_group *tg, u64 period, u64 quota)return ret; } -static int cpu_stats_show (struct seq_file *sf,void *v) +static int cpu_cfs_stats_show (struct seq_file *sf,void *v) {struct task_group *tg =css_tg (seq_css (sf));struct cfs_bandwidth *cfs_b = &tg->cfs_bandwidth;
@@ -7286,7 +7286,7 @@ static u64 cpu_rt_period_read_uint(struct cgroup_subsys_state *css, }#endif /* CONFIG_RT_GROUP_SCHED */ -static struct cftype cpu_files[] = { +static struct cftype cpu_legacy_files[] = {#ifdef CONFIG_FAIR_GROUP_SCHED { .name = "shares",
@@ -7307,7 +7307,7 @@ static struct cftype cpu_files[] = { }, { .name = "stat", - .seq_show = cpu_stats_show, + .seq_show = cpu_cfs_stats_show, },#endif #ifdef CONFIG_RT_GROUP_SCHED
@@ -7333,7 +7333,7 @@ struct cgroup_subsys cpu_cgrp_subsys = { .fork = cpu_cgroup_fork, .can_attach = cpu_cgroup_can_attach, .attach = cpu_cgroup_attach, - .legacy_cftypes = cpu_files, + .legacy_cftypes = cpu_legacy_files, .early_init = true, };
kernel/sched/cpuacct.c +18 -11
@@ -276,26 +276,33 @@ static int cpuacct_all_seq_show(struct seq_file *m, void *V)return 0 ; } -static int cpuacct_stats_show (struct seq_file *sf,void *v) +static void cpuacct_stats_read (struct cpuacct *ca, +u64 (*val)[CPUACCT_STAT_NSTATS ]) { -struct cpuacct *ca =css_ca (seq_css (sf)); -s64 val[CPUACCT_STAT_NSTATS ];int cpu; -int stat; -memset (val,0 ,sizeof (val)); +memset (val,0 ,sizeof (*val)); +for_each_possible_cpu (cpu) {u64 *cpustat =per_cpu_ptr (ca->cpustat, cpu)->cpustat; - val[CPUACCT_STAT_USER ] += cpustat[CPUTIME_USER ]; - val[CPUACCT_STAT_USER ] += cpustat[CPUTIME_NICE ]; - val[CPUACCT_STAT_SYSTEM ] += cpustat[CPUTIME_SYSTEM ]; - val[CPUACCT_STAT_SYSTEM ] += cpustat[CPUTIME_IRQ ]; - val[CPUACCT_STAT_SYSTEM ] += cpustat[CPUTIME_SOFTIRQ ]; + (*val)[CPUACCT_STAT_USER ] += cpustat[CPUTIME_USER ]; + (*val)[CPUACCT_STAT_USER ] += cpustat[CPUTIME_NICE ]; + (*val)[CPUACCT_STAT_SYSTEM ] += cpustat[CPUTIME_SYSTEM ]; + (*val)[CPUACCT_STAT_SYSTEM ] += cpustat[CPUTIME_IRQ ]; + (*val)[CPUACCT_STAT_SYSTEM ] += cpustat[CPUTIME_SOFTIRQ ]; } +} + +static int cpuacct_stats_show (struct seq_file *sf,void *v) +{ +u64 val[CPUACCT_STAT_NSTATS ]; +int stat; + +cpuacct_stats_read (css_ca (seq_css (sf)), &val);for (stat =0 ; stat <CPUACCT_STAT_NSTATS ; stat++) { -seq_printf (sf,"%s %lld\n" , +seq_printf (sf,"%s %llu\n" , cpuacct_stat_desc[stat], (long long )nsec_to_clock_t (val[stat])); }
Signature · 1 line
2.13.0
Tejun Heo
maintainerPATCH 9/10 sched: Implement interface for cgroup unified hierarchy
In reply to Tejun HeoWhile the cpu controller doesn't have any functional problems, there are a couple interface issues which can be addressed in the v2 interface.
* cpuacct being a separate controller. This separation is artificial and rather pointless as demonstrated by most use cases co-mounting the two controllers. It also forces certain information to be accounted twice.
* Use of different time units. Writable control knobs use microseconds, some stat fields use nanoseconds while other cpuacct stat fields use centiseconds.
* Control knobs which can't be used in the root cgroup still show up in the root.
* Control knob names and semantics aren't consistent with other controllers.
This patchset implements cpu controller's interface on the unified hierarchy which adheres to the controller file conventions described in Documentation/cgroups/unified-hierarchy.txt. Overall, the following changes are made.
* cpuacct is implictly enabled and disabled by cpu and its information is reported through "cpu.stat" which now uses microseconds for all time durations. All time duration fields now have "_usec" appended to them for clarity. While this doesn't solve the double accounting immediately, once majority of users switch to v2, cpu can directly account and report the relevant stats and cpuacct can be disabled on the unified hierarchy.
Note that cpuacct.usage_percpu is currently not included in "cpu.stat". If this information is actually called for, it can be added later.
* "cpu.shares" is replaced with "cpu.weight" and operates on the standard scale defined by CGROUP_WEIGHT_MIN/DFL/MAX (1, 100, 10000). The weight is scaled to scheduler weight so that 100 maps to 1024 and the ratio relationship is preserved - if weight is W and its scaled value is S, W / 100 == S / 1024. While the mapped range is a bit smaller than the orignal scheduler weight range, the dead zones on both sides are relatively small and covers wider range than the nice value mappings. This file doesn't make sense in the root cgroup and isn't create on root.
* "cpu.cfs_quota_us" and "cpu.cfs_period_us" are replaced by "cpu.max" which contains both quota and period.
* "cpu.rt_runtime_us" and "cpu.rt_period_us" are replaced by "cpu.rt.max" which contains both runtime and period.
v2: cpu_stats_show() was incorrectly using CONFIG_FAIR_GROUP_SCHED for
CFS bandwidth stats and also using raw division for u64. Use CONFIG_CFS_BANDWITH and do_div() instead.
The semantics of "cpu.rt.max" is not fully decided yet. Dropped for now.
--- kernel/sched/core.c | 141 +++++++++++++++++++++++++++++++++++++++++++++++++ kernel/sched/cpuacct.c | 23 ++++++++ kernel/sched/cpuacct.h | 5 ++ 3 files changed, 169 insertions(+)
kernel/sched/core.c +141 -0
@@ -7325,6 +7325,139 @@ static struct cftype cpu_legacy_files[] = { { }/* Terminate */ }; +static int cpu_stats_show (struct seq_file *sf,void *v) +{ +cpuacct_cpu_stats_show (sf); + +#ifdef CONFIG_CFS_BANDWIDTH + { +struct task_group *tg =css_tg (seq_css (sf)); +struct cfs_bandwidth *cfs_b = &tg->cfs_bandwidth; +u64 throttled_usec; + + throttled_usec = cfs_b->throttled_time; +do_div (throttled_usec,NSEC_PER_USEC ); + +seq_printf (sf,"nr_periods %d\n" +"nr_throttled %d\n" +"throttled_usec %llu\n" , + cfs_b->nr_periods, cfs_b->nr_throttled, + throttled_usec); + } +#endif +return 0 ; +} + +#ifdef CONFIG_FAIR_GROUP_SCHED +static u64 cpu_weight_read_u64 (struct cgroup_subsys_state *css, +struct cftype *cft) +{ +struct task_group *tg =css_tg (css); +u64 weight =scale_load_down (tg->shares); + +return DIV_ROUND_CLOSEST_ULL (weight *CGROUP_WEIGHT_DFL ,1024 ); +} + +static int cpu_weight_write_u64 (struct cgroup_subsys_state *css, +struct cftype *cftype,u64 weight) +{ +/* +* cgroup weight knobs should use the common MIN, DFL and MAX +* values which are 1, 100 and 10000 respectively. While it loses +* a bit of range on both ends, it maps pretty well onto the shares +* value used by scheduler and the round-trip conversions preserve +* the original value over the entire range. +*/ +if (weight <CGROUP_WEIGHT_MIN || weight >CGROUP_WEIGHT_MAX ) +return -ERANGE ; + + weight =DIV_ROUND_CLOSEST_ULL (weight *1024 ,CGROUP_WEIGHT_DFL ); + +return sched_group_set_shares (css_tg (css),scale_load (weight)); +} +#endif + +static void __maybe_unused cpu_period_quota_print (struct seq_file *sf, +long period,long quota) +{ +if (quota <0 ) +seq_puts (sf,"max" ); +else +seq_printf (sf,"%ld" , quota); + +seq_printf (sf," %ld\n" , period); +} + +/* caller should put the current value in *@periodp before calling */ +static int __maybe_unused cpu_period_quota_parse (char *buf, +u64 *periodp,u64 *quotap) +{ +char tok[21 ];/* U64_MAX */ + +if (!sscanf (buf,"%s %llu" , tok, periodp)) +return -EINVAL ; + + *periodp *=NSEC_PER_USEC ; + +if (sscanf (tok,"%llu" , quotap)) + *quotap *=NSEC_PER_USEC ; +else if (!strcmp (tok,"max" )) + *quotap =RUNTIME_INF ; +else +return -EINVAL ; + +return 0 ; +} + +#ifdef CONFIG_CFS_BANDWIDTH +static int cpu_max_show (struct seq_file *sf,void *v) +{ +struct task_group *tg =css_tg (seq_css (sf)); + +cpu_period_quota_print (sf,tg_get_cfs_period (tg),tg_get_cfs_quota (tg)); +return 0 ; +} + +static ssize_t cpu_max_write (struct kernfs_open_file *of, +char *buf,size_t nbytes,loff_t off) +{ +struct task_group *tg =css_tg (of_css (of)); +u64 period =tg_get_cfs_period (tg); +u64 quota; +int ret; + + ret =cpu_period_quota_parse (buf, &period, "a); +if (!ret) + ret =tg_set_cfs_bandwidth (tg, period, quota); +return ret ?: nbytes; +} +#endif + +static struct cftype cpu_files[] = { + { + .name ="stat" , + .flags =CFTYPE_NOT_ON_ROOT , + .seq_show = cpu_stats_show, + }, +#ifdef CONFIG_FAIR_GROUP_SCHED + { + .name ="weight" , + .flags =CFTYPE_NOT_ON_ROOT , + .read_u64 = cpu_weight_read_u64, + .write_u64 = cpu_weight_write_u64, + }, +#endif +#ifdef CONFIG_CFS_BANDWIDTH + { + .name ="max" , + .flags =CFTYPE_NOT_ON_ROOT , + .seq_show = cpu_max_show, + .write = cpu_max_write, + }, +#endif + { }/* terminate */ +}; +struct cgroup_subsys cpu_cgrp_subsys = { .css_alloc = cpu_cgroup_css_alloc, .css_online = cpu_cgroup_css_online,
@@ -7334,7 +7467,15 @@ struct cgroup_subsys cpu_cgrp_subsys = { .can_attach = cpu_cgroup_can_attach, .attach = cpu_cgroup_attach, .legacy_cftypes = cpu_legacy_files, + .dfl_cftypes = cpu_files, .early_init = true, +#ifdef CONFIG_CGROUP_CPUACCT +/* +* cpuacct is enabled together with cpu on the unified hierarchy +* and its stats are reported through "cpu.stat". +*/ + .depends_on = 1 << cpuacct_cgrp_id, +#endif };#endif /* CONFIG_CGROUP_SCHED */
kernel/sched/cpuacct.c +23 -0
@@ -347,6 +347,29 @@ static struct cftype files[] = { { }/* terminate */ }; +/* used to print cpuacct stats in cpu.stat on the unified hierarchy */ +void cpuacct_cpu_stats_show (struct seq_file *sf) +{ +struct cgroup_subsys_state *css; +u64 usage, val[CPUACCT_STAT_NSTATS ]; + + css =cgroup_get_e_css (seq_css (sf)->cgroup, &cpuacct_cgrp_subsys); + + usage =cpuusage_read (css,seq_cft (sf)); +cpuacct_stats_read (css_ca (css), &val); + +do_div (usage,NSEC_PER_USEC ); +do_div (val[CPUACCT_STAT_USER ],NSEC_PER_USEC ); +do_div (val[CPUACCT_STAT_SYSTEM ],NSEC_PER_USEC ); + +seq_printf (sf,"usage_usec %llu\n" +"user_usec %llu\n" +"system_usec %llu\n" , + usage, val[CPUACCT_STAT_USER ], val[CPUACCT_STAT_SYSTEM ]); + +css_put (css); +} +/* * charge this task's execution time to its accounting group. *
kernel/sched/cpuacct.h +5 -0
@@ -2,6 +2,7 @@extern void cpuacct_charge (struct task_struct *tsk,u64 cputime);extern void cpuacct_account_field (struct task_struct *tsk,int index,u64 val); +extern void cpuacct_cpu_stats_show (struct seq_file *sf);#else
@@ -14,4 +15,8 @@ cpuacct_account_field(struct task_struct *tsk, int index, u64 val) { } +static inline void cpuacct_cpu_stats_show (struct seq_file *sf) +{ +} +#endif
Signature · 1 line
2.13.0
Tejun Heo
maintainerPATCH 10/10 sched: Make cpu/cpuacct threaded controllers
In reply to Tejun HeoFrom: Waiman Long <[email protected]>
Make cpu and cpuacct cgroup controllers usable within a threaded cgroup.
--- kernel/sched/core.c | 1 + kernel/sched/cpuacct.c | 1 + 2 files changed, 2 insertions(+)
kernel/sched/core.c +1 -0
@@ -7469,6 +7469,7 @@ struct cgroup_subsys cpu_cgrp_subsys = { .legacy_cftypes = cpu_legacy_files, .dfl_cftypes = cpu_files, .early_init = true, + .threaded = true,#ifdef CONFIG_CGROUP_CPUACCT /* * cpuacct is enabled together with cpu on the unified hierarchy
kernel/sched/cpuacct.c +1 -0
@@ -412,4 +412,5 @@ struct cgroup_subsys cpuacct_cgrp_subsys = { .css_free = cpuacct_css_free, .legacy_cftypes = files, .early_init = true, + .threaded = true, };
Signature · 1 line
2.13.0
Peter Zijlstra
maintainerPlease don't rush this; also, I might not be around much the coming weeks due to taking some leave 'soon' (kid #3 is imminent).
And I really need more time to look at this (and re-read the old discussions, because I've forgot most everything again).
Quoted 20 lines · Tejun Heo
* Thread mode is explicitly enabled on a cgroup by writing "enable" into "cgroup.threads" file. The cgroup shouldn't have any child cgroups or enabled controllers.
* Once enabled, arbitrary sub-hierarchy can be created and threads can be put anywhere in the subtree by writing TIDs into "cgroup.threads" file. Process granularity and no-internal-process constraint don't apply in a threaded subtree.
* To be used in a threaded subtree, controllers should explicitly declare thread mode support and should be able to handle internal competition in some way.
* The root of a threaded subtree serves as the resource domain for the whole subtree. This is where all the controllers are guaranteed to have a common ground and resource consumptions in the threaded subtree which aren't tied to a specific thread are charged. Non-threaded controllers never see beyond thread root and can assume that all controllers will follow the same rules upto that point.
Quoted 4 lines
* Root cgroup can enable thread mode anytime and a first level child can opt-in to that thread subtree anchored at root by writing "join" to "cgroup.threads" files, start its own thread subtree or just be a normal cgroup.
Yuck... this again is a consequence of tagging the 'wrong' thing. Again, the primary construct is the resource domain.
If you use that as a tag, you don't need this weird join crap. Because as soon as you clear the 'resource domain' flag on a group, it instantly becomes a thread group and 'obviously' connects to the first parent that is a resource domain.
And, as per the last time, this threaded marker isn't uniquely identifying things, so it hard prohibits from ever extending the model to allow resource domains nested in a thread subtree. Now I understand why you don't implement that now -- you were struggling with the views API, but that is no excuse to create an API that permanently disables that feature.
I cannot at this time remember if there was a strong use-case for that scenario -- like said, I really need to re-read the email threads, but I might not have enough time to do so now.
Again, please don't rush this.
Quoted 18 lines
This allows threaded controllers to implement thread granular resource control without getting in the way of system level resource partitioning.
This patchset contains the following ten patches. For more details on the interface and behavior, please refer to 0007.
0001-cgroup-separate-out-cgroup_has_tasks.patch 0002-cgroup-reorganize-cgroup.procs-task-write-path.patch 0003-cgroup-Fix-reference-counting-bug-in-cgroup_procs_wr.patch 0004-cgroup-add-flags-to-css_task_iter_start-and-implemen.patch 0005-cgroup-introduce-cgroup-proc_cgrp-and-threaded-css_s.patch 0006-cgroup-implement-CSS_TASK_ITER_THREADED.patch 0007-cgroup-implement-cgroup-v2-thread-support.patch 0008-sched-Misc-preps-for-cgroup-unified-hierarchy-interf.patch 0009-sched-Implement-interface-for-cgroup-unified-hierarc.patch 0010-sched-Make-cpu-cpuacct-threaded-controllers.patch
Quoted 3 lines
0001-0007 implement cgroup2 thread mode. 0008-0010 enable CPU controller on cgroup2 and mark them as supporting thread mode. 0008-0010 are included for reference.
So I really regret the 'shares' interface; we really should have done a nice thing.
So I would like to change to that instead of the weird 100 thing.
As for the RT thing, the runtime/period thing is not a MAX but a MIN limit (conceptually -- in practise its both).
Also, we need cpuset to be a thread controller.
Tejun Heo
maintainerHello, Peter.
Quoted 2 lines · Peter Zijlstra
Please don't rush this; also, I might not be around much the coming weeks due to taking some leave 'soon' (kid #3 is imminent).
Congrats. As for this going forward, how can we possibly be slower?
Quoted 2 lines
And I really need more time to look at this (and re-read the old discussions, because I've forgot most everything again).
Can we at least unblock the cpu controller part? We can hash the details of thread support as long as necessary but I'm not sure it's reasonable to keep blocking the whole cpu controller at this point.
Quoted 5 lines
Quoted 4 lines
* Root cgroup can enable thread mode anytime and a first level child can opt-in to that thread subtree anchored at root by writing "join" to "cgroup.threads" files, start its own thread subtree or just be a normal cgroup.
Quoted 7 lines
Yuck... this again is a consequence of tagging the 'wrong' thing. Again, the primary construct is the resource domain.
If you use that as a tag, you don't need this weird join crap. Because as soon as you clear the 'resource domain' flag on a group, it instantly becomes a thread group and 'obviously' connects to the first parent that is a resource domain.
It has nothing to do with whether we mark domain or threaded subtrees. It is solely from whether you wanna express cases where a thread root is right below another thread root. Tn's are member cgroup of thread subtrees where the same number means the same threaded subtree, D's are of domain cgroups.
The following is straight forward.
T0
/ \
T0 DThe following is too.
T0
/ \
T0 D
\
T1The question is whether to allow something like the following.
T0
/ \
T0 T1That's where the "join" thing comes from because we wanna be able to tell apart whether a cgroup is gonna be a part of the existing thread subtree or starting its own thread subtree. There sure are multiple ways to express that but one way or the other, if you wanna support topologies like the last one, you have to distinguish the two.
The previous iteration actually was that way, so the only thread mode operation was setting whether to enable thread or not as before and if the parent is already thread mode, it'd always join the existing threaded subtree. If you like that better, I can post that version right away.
Quoted 6 lines
And, as per the last time, this threaded marker isn't uniquely identifying things, so it hard prohibits from ever extending the model to allow resource domains nested in a thread subtree. Now I understand why you don't implement that now -- you were struggling with the views API, but that is no excuse to create an API that permanently disables that feature.
Hmmm? We can just allow disabling thread mode if we ever get to that. We can't make arbitrary graphs out of these nodes. Whatever mode we put them in, they have to fall in with the overall tree structure, so I don't think the interface is unnecessarily restricting in that direction.
Quoted 5 lines
I cannot at this time remember if there was a strong use-case for that scenario -- like said, I really need to re-read the email threads, but I might not have enough time to do so now.
Again, please don't rush this.
Well, I don't have a way to do that.
Quoted 6 lines
So I really regret the 'shares' interface; we really should have done a nice thing.
So I would like to change to that instead of the weird 100 thing.
Is it? Relative weights are pretty fundamental and clearly defined in expressing work-conserving resource distribution. Do you have more details on what you have on mind?
Quoted 2 lines
As for the RT thing, the runtime/period thing is not a MAX but a MIN limit (conceptually -- in practise its both).
Yeah, it's a hard allocation.
Quoted 1 line
Also, we need cpuset to be a thread controller.
Yeah, absolutely.
Thanks.
Signature · 1 line
tejun
Tejun Heo
maintainerHello,
Quoted 5 lines · Tejun Heo
The previous iteration actually was that way, so the only thread mode operation was setting whether to enable thread or not as before and if the parent is already thread mode, it'd always join the existing threaded subtree. If you like that better, I can post that version right away.
Just posted v3 of the patch which drops the "join" operation, but do note that this inherently comes at the cost of losing the ability express certain topologies.
Thanks.
Signature · 1 line
tejun
Peter Zijlstra
maintainerI'm slowly getting back to things...
Quoted 39 lines · Tejun Heo
Quoted 5 lines
Quoted 4 lines
* Root cgroup can enable thread mode anytime and a first level child can opt-in to that thread subtree anchored at root by writing "join" to "cgroup.threads" files, start its own thread subtree or just be a normal cgroup.
Quoted 7 lines
Yuck... this again is a consequence of tagging the 'wrong' thing. Again, the primary construct is the resource domain.
If you use that as a tag, you don't need this weird join crap. Because as soon as you clear the 'resource domain' flag on a group, it instantly becomes a thread group and 'obviously' connects to the first parent that is a resource domain.
It has nothing to do with whether we mark domain or threaded subtrees. It is solely from whether you wanna express cases where a thread root is right below another thread root. Tn's are member cgroup of thread subtrees where the same number means the same threaded subtree, D's are of domain cgroups.
The following is straight forward.
T0 / \ T0 DThe following is too.
T0 / \ T0 D \ T1The question is whether to allow something like the following.
T0 / \ T0 T1
Quoted 5 lines
That's where the "join" thing comes from because we wanna be able to tell apart whether a cgroup is gonna be a part of the existing thread subtree or starting its own thread subtree. There sure are multiple ways to express that but one way or the other, if you wanna support topologies like the last one, you have to distinguish the two.
Hmm,.. I had not considered that. I was strictly considering the root to always be a resource domain. What use-case or scenario did you have to want to do this?
That is, what is the meaning of having T1 be a separate 'root' if its not also a resource domain?
Quoted 7 lines
Quoted 6 lines
And, as per the last time, this threaded marker isn't uniquely identifying things, so it hard prohibits from ever extending the model to allow resource domains nested in a thread subtree. Now I understand why you don't implement that now -- you were struggling with the views API, but that is no excuse to create an API that permanently disables that feature.
Quoted 5 lines
Hmmm? We can just allow disabling thread mode if we ever get to that. We can't make arbitrary graphs out of these nodes. Whatever mode we put them in, they have to fall in with the overall tree structure, so I don't think the interface is unnecessarily restricting in that direction.
IIRC the problem with the 'threaded' marker is that it doesn't clearly capture what a resource domain is.
That is, assuming that a thread root is always a resource domain, we get the following problem:
If we set 'threaded' on the root group in order to create a thread (sub)group. If we then want to create another domain group, we'd have to clear 'threaded' on that.
R (t=1)
/ \(t=1) T D (t=0)
So far so good. However, now we want to create another thread group under our domain group D, so we have to set its 'threaded' marker again:
R (t=1)
/ \
(t=1) T D (t=1)
/
T (t=1)And we can no longer identify D as a resource domain. If OTOH we mark 'domain' we get:
R (d=1)
/ \
(d=0) T D (d=1)
/
T (d=0)Which clearly identifies the domains and the thread only groups.
Your objections to doing this were representing the resource controllers in the intermediate thread-only groups like:
R
\
T -- what to do with eg. memcg here?
\
D
\
TI suggested having all resource controllers represented with a soft-link back into the (thread-root) resource domain. But you were not convinced and worried people were going to be confused.
Your current proposal treats the resource controllers as disabled in thread subgroups -- which is perfectly fine given the constraint that we cannot have new domains in a thread sub-tree. My worry is that we don't paint ourselves in a corner and create an interface where we can never extend to allow this.
The immediate use-case for wanting this would be allowing tasks in a thread-group to start a VM or container (which would then want a (sub) resource domain).
Quoted 10 lines
Quoted 6 lines
So I really regret the 'shares' interface; we really should have done a nice thing.
So I would like to change to that instead of the weird 100 thing.
Is it? Relative weights are pretty fundamental and clearly defined in expressing work-conserving resource distribution. Do you have more details on what you have on mind?
I'm not wanting to change the relative weight thing. I merely wish to change the interface for setting the group weight to match that of the task weight, since both directly compete against one another.
That is, a group weight is the same kind of weight as a task weight. Therefore it would make much more sense to set then in equal units too. Not having done that from the beginning was rather silly.
By having a 100 based weight it becomes very hard to match the weight of nice()'ed tasks (something that was already tricky with the current shares interface because we'd need to share the nice weight table with userspace).
By having both in nice units, its both conceptually clear that they're the same kind of weight and easier to match weights.
Tejun Heo
maintainerHello, Peter.
Quoted 2 lines · Peter Zijlstra
I'm slowly getting back to things...
Welcome back.
Quoted 10 lines · Tejun Heo
Quoted 5 lines
That's where the "join" thing comes from because we wanna be able to tell apart whether a cgroup is gonna be a part of the existing thread subtree or starting its own thread subtree. There sure are multiple ways to express that but one way or the other, if you wanna support topologies like the last one, you have to distinguish the two.
Hmm,.. I had not considered that. I was strictly considering the root to always be a resource domain. What use-case or scenario did you have to want to do this?
I don't have any really. It's mostly just from interface completeness.
Quoted 2 lines
That is, what is the meaning of having T1 be a separate 'root' if its not also a resource domain?
T1 is a resource domain. Hmm... I think I see what you mean. Let's continue below.
Quoted 26 lines
IIRC the problem with the 'threaded' marker is that it doesn't clearly capture what a resource domain is.
That is, assuming that a thread root is always a resource domain, we get the following problem:
If we set 'threaded' on the root group in order to create a thread (sub)group. If we then want to create another domain group, we'd have to clear 'threaded' on that.
R (t=1) / \(t=1) T D (t=0)
So far so good. However, now we want to create another thread group under our domain group D, so we have to set its 'threaded' marker again:
R (t=1) / \ (t=1) T D (t=1) / T (t=1)And we can no longer identify D as a resource domain. If OTOH we mark 'domain' we get:
Quoted 7 lines
R (d=1) / \ (d=0) T D (d=1) / T (d=0)Which clearly identifies the domains and the thread only groups.
So, the difference between the two interfaces is that the one I proposed is marking the thread root which makes all its descendants threaded while the above is marking each individual cgroup as being whether a resource domain or threaded.
Quoted 10 lines
Your objections to doing this were representing the resource controllers in the intermediate thread-only groups like:
R \ T -- what to do with eg. memcg here? \ D \ T
And that's a perfectly valid point and as you pointed out the downside of marking each node separately is that the interface would allow configurations which aren't supported (at least for now) and that there's just more to configure - the user has to set the mode on each node after creation which is just the natural cost of being able to express more.
Quoted 3 lines
I suggested having all resource controllers represented with a soft-link back into the (thread-root) resource domain. But you were not convinced and worried people were going to be confused.
There's more to it than just confusion because resource interface files belong to the parent cgroup rather than the cgroup which hosts the files. This becomes clear when thinking about which files a container should be granted write access to when delegating a cgroup subtree to it. I'm sure we can get around it some way but we need to be careful here.
Quoted 5 lines
Your current proposal treats the resource controllers as disabled in thread subgroups -- which is perfectly fine given the constraint that we cannot have new domains in a thread sub-tree. My worry is that we don't paint ourselves in a corner and create an interface where we can never extend to allow this.
Understood. We can err out on unsupported configurations and expand in the future as necessary.
Quoted 8 lines
I'm not wanting to change the relative weight thing. I merely wish to change the interface for setting the group weight to match that of the task weight, since both directly compete against one another.
That is, a group weight is the same kind of weight as a task weight. Therefore it would make much more sense to set then in equal units too. Not having done that from the beginning was rather silly.
Quoted 7 lines
By having a 100 based weight it becomes very hard to match the weight of nice()'ed tasks (something that was already tricky with the current shares interface because we'd need to share the nice weight table with userspace).
By having both in nice units, its both conceptually clear that they're the same kind of weight and easier to match weights.
I think there is another side to it. If you just think about threads, nice levels is the only thing we have. It's a relative interface which isn't defined rigidly and that can be a plus in that it allows the kernel the room to maneuver with evolving implentations, heuristics and so on.
Unfortunaltey, viewed from containerized resource control side, this is very difficult to deal with. The scale isn't strictly defined, rather coarse and in generally difficult to work with - e.g. what do you do when the system is split 20%, 80% and then you wanna add another workload so that it becomes 20%, 50%, 30%? And then there is the problem with consistency with other resource types which may also use proportional distribution.
But, it doesn't have to be this or that. We can easily support both units by simply allowing, say, "-5n" to be written to cpu.weight file and interpret that as the nice value and exposing the closest nice value in the cpu.stat file.
Does that sound workable?
Thanks.
Signature · 1 line
tejun
Peter Zijlstra
maintainerQuoted 35 lines · Tejun Heo
Quoted 34 lines · Peter Zijlstra
On Mon, Jun 12, 2017 at 05:27:53PM -0400, Tejun Heo wrote:
IIRC the problem with the 'threaded' marker is that it doesn't clearly capture what a resource domain is.
That is, assuming that a thread root is always a resource domain, we get the following problem:
If we set 'threaded' on the root group in order to create a thread (sub)group. If we then want to create another domain group, we'd have to clear 'threaded' on that.
R (t=1) / \(t=1) T D (t=0)
So far so good. However, now we want to create another thread group under our domain group D, so we have to set its 'threaded' marker again:
R (t=1) / \ (t=1) T D (t=1) / T (t=1)And we can no longer identify D as a resource domain. If OTOH we mark 'domain' we get:
R (d=1) / \ (d=0) T D (d=1) / T (d=0)
Quoted 6 lines
Quoted 1 line
Which clearly identifies the domains and the thread only groups.
So, the difference between the two interfaces is that the one I proposed is marking the thread root which makes all its descendants threaded while the above is marking each individual cgroup as being whether a resource domain or threaded.
You start by marking the thread root, but then continue to mark all 'threaded' (including root). This then leads to the problem described above where you cannot (easily) (re)discover what the actual root is.
My proposal differs in that we retain a clear difference between resource domain / root and threaded (sub)trees.
Quoted 11 lines
Quoted 10 lines
Your objections to doing this were representing the resource controllers in the intermediate thread-only groups like:
R \ T -- what to do with eg. memcg here? \ D \ T
Quoted 6 lines
And that's a perfectly valid point and as you pointed out the downside of marking each node separately is that the interface would allow configurations which aren't supported (at least for now) and that there's just more to configure - the user has to set the mode on each node after creation which is just the natural cost of being able to express more.
I'm not sure my proposal results in _more_ configuration per-se. Yes there are some differences, but they go both ways, with the threaded tag its easier to create multiple threaded subgroups, but with the domain tag its easier to create multiple domain subgroups.
And I think the bias for the domain tag -- easier to create more domains -- is the right one. The whole threaded thing is fairly special purpose.
In any case; I'm fine with initially not supporting domains nested under thread groups -- although I do think there's valid use-cases for doing so.
Quoted 10 lines
Quoted 3 lines
I suggested having all resource controllers represented with a soft-link back into the (thread-root) resource domain. But you were not convinced and worried people were going to be confused.
There's more to it than just confusion because resource interface files belong to the parent cgroup rather than the cgroup which hosts the files. This becomes clear when thinking about which files a container should be granted write access to when delegating a cgroup subtree to it. I'm sure we can get around it some way but we need to be careful here.
I would suggest having all the back-links be RO. That way you can never grant write permission, can never actually change things that don't make 'sense', but get a really good clue where you need to go.
Quoted 9 lines
Quoted 2 lines
By having both in nice units, its both conceptually clear that they're the same kind of weight and easier to match weights.
But, it doesn't have to be this or that. We can easily support both units by simply allowing, say, "-5n" to be written to cpu.weight file and interpret that as the nice value and exposing the closest nice value in the cpu.stat file.
Does that sound workable?
Not sure; reading the value would become somewhat awkward I suppose. But maybe we can simply do two files, whichever is written to last takes precedence. And when a !nice weight is written, the nice file returns -EINVAL or something.
Not particularly pretty though...
Waiman Long
maintainerQuoted 17 lines · Peter Zijlstra
Quoted 16 lines · Tejun Heo
Quoted 15 lines · Peter Zijlstra
On Mon, Jun 12, 2017 at 05:27:53PM -0400, Tejun Heo wrote:
IIRC the problem with the 'threaded' marker is that it doesn't clearly capture what a resource domain is.That is, assuming that a thread root is always a resource domain, we get the following problem:
If we set 'threaded' on the root group in order to create a thread (sub)group. If we then want to create another domain group, we'd have to clear 'threaded' on that.
R (t=1) / \(t=1) T D (t=0)
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
So far so good. However, now we want to create another thread group under our domain group D, so we have to set its 'threaded' marker again:
R (t=1) / \ (t=1) T D (t=1) / T (t=1)
This configuration is actually not possible with Tejun's latest v3 patch which took out the "join" operation. Maybe we should keep the "join" operation if this configuration is likely to happen.
Quoted 9 lines
Quoted 9 lines
Quoted 9 lines
And we can no longer identify D as a resource domain. If OTOH we mark 'domain' we get:
R (d=1) / \ (d=0) T D (d=1) / T (d=0)
Quoted 8 lines
Quoted 5 lines
Quoted 1 line
Which clearly identifies the domains and the thread only groups.
So, the difference between the two interfaces is that the one I proposed is marking the thread root which makes all its descendants threaded while the above is marking each individual cgroup as being whether a resource domain or threaded.
You start by marking the thread root, but then continue to mark all 'threaded' (including root). This then leads to the problem described above where you cannot (easily) (re)discover what the actual root is.
I don't think that is true. Internally, we can always find out if a cgroup is a thread root. Externally, the presence of resource domain control knobs in a threaded cgroup will indicate that it is a thread root.
Quoted 2 lines
My proposal differs in that we retain a clear difference between resource domain / root and threaded (sub)trees.
For me, I have no preference of using either the threaded or the domain marker as long as some kind of join operation that allows the configuration above is present in the thread mode. They both looks good to me. It is just a matter of which aspect of the cgroup we want to emphasize. I would suggest we reach a consensus ASAP and move forward to other more substantial issues in cgroup v2.
Cheers,
Longman
Peter Zijlstra
maintainerQuoted 27 lines · Waiman Long
Quoted 17 lines · Peter Zijlstra
Quoted 16 lines · Tejun Heo
Quoted 15 lines · Peter Zijlstra
On Mon, Jun 12, 2017 at 05:27:53PM -0400, Tejun Heo wrote:
IIRC the problem with the 'threaded' marker is that it doesn't clearly capture what a resource domain is.That is, assuming that a thread root is always a resource domain, we get the following problem:
If we set 'threaded' on the root group in order to create a thread (sub)group. If we then want to create another domain group, we'd have to clear 'threaded' on that.
R (t=1) / \(t=1) T D (t=0)
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
So far so good. However, now we want to create another thread group under our domain group D, so we have to set its 'threaded' marker again:
R (t=1) / \ (t=1) T D (t=1) / T (t=1)
Quoted 3 lines
This configuration is actually not possible with Tejun's latest v3 patch which took out the "join" operation. Maybe we should keep the "join" operation if this configuration is likely to happen.
Wait what? Why not? That's a fairly fundamental setup that needs to be possible. I understood the 'join' thing was for something else entirely. TJ said the 'join' was to allow thread-roots that were not domain controllers -- which I didn't get the point of.
Quoted 14 lines
Quoted 14 lines
Quoted 14 lines
Quoted 10 lines
And we can no longer identify D as a resource domain. If OTOH we mark 'domain' we get:
R (d=1) / \ (d=0) T D (d=1) / T (d=0)Which clearly identifies the domains and the thread only groups.
So, the difference between the two interfaces is that the one I proposed is marking the thread root which makes all its descendants threaded while the above is marking each individual cgroup as being whether a resource domain or threaded.
Quoted 7 lines
Quoted 3 lines
You start by marking the thread root, but then continue to mark all 'threaded' (including root). This then leads to the problem described above where you cannot (easily) (re)discover what the actual root is.
I don't think that is true. Internally, we can always find out if a cgroup is a thread root. Externally, the presence of resource domain control knobs in a threaded cgroup will indicate that it is a thread root.
You're confusing thread root with resource domain. While a resource domain must be a thread root the reverse is not necessarily so (this is what I understood the 'join' thing to be for).
And this is detection by inference, which breaks the moment you disable all resource domain controllers, because at that point those files will not be present.
Quoted 9 lines
Quoted 2 lines
My proposal differs in that we retain a clear difference between resource domain / root and threaded (sub)trees.
For me, I have no preference of using either the threaded or the domain marker as long as some kind of join operation that allows the configuration above is present in the thread mode. They both looks good to me. It is just a matter of which aspect of the cgroup we want to emphasize. I would suggest we reach a consensus ASAP and move forward to other more substantial issues in cgroup v2.
I think you're confused on join. Join should not be needed.
Waiman Long
maintainerQuoted 27 lines · Peter Zijlstra
Quoted 26 lines · Waiman Long
Quoted 25 lines · Peter Zijlstra
Quoted 24 lines · Tejun Heo
Quoted 23 lines · Peter Zijlstra
On Mon, Jun 12, 2017 at 05:27:53PM -0400, Tejun Heo wrote:
IIRC the problem with the 'threaded' marker is that it doesn't clearly capture what a resource domain is.That is, assuming that a thread root is always a resource domain, we get the following problem:
If we set 'threaded' on the root group in order to create a thread (sub)group. If we then want to create another domain group, we'd have to clear 'threaded' on that.
R (t=1) / \(t=1) T D (t=0)
So far so good. However, now we want to create another thread group under our domain group D, so we have to set its 'threaded' marker again:
R (t=1) / \ (t=1) T D (t=1) / T (t=1)
Quoted 7 lines
Quoted 3 lines
This configuration is actually not possible with Tejun's latest v3 patch which took out the "join" operation. Maybe we should keep the "join" operation if this configuration is likely to happen.
Wait what? Why not? That's a fairly fundamental setup that needs to be possible. I understood the 'join' thing was for something else entirely. TJ said the 'join' was to allow thread-roots that were not domain controllers -- which I didn't get the point of.
The "join" was a special op for the children of cgroup root to join the root as part of a threaded subtree. The children can instead use the "enable" option to become a thread root which was the configuration shown above. This behavior applied only to children of root. Down the hierarchy, you can't have configuration like:
R (t=0)
/ \
D (t=1)
/ \
T D (t=1)Instead, you can have
R (t=0)
/ \
D (t=0)
/ \(t=1)D D(t=1)
With Tejun's v3 patch, the "join" operation was removed and "enable" behaved like "join" in joining the threaded subtree of the root. I was wrong in saying that the configuration listed in your example was not possible. It was, but it depends on the order of activating the thread mode. If we enables thread mode on a child of root first followed by the root itself, we can have your configuration, but not in the reverse order. It was possible in the reverse order in the previous patch.
Quoted 17 lines
Quoted 17 lines
Quoted 17 lines
Quoted 9 lines
Quoted 9 lines
And we can no longer identify D as a resource domain. If OTOH we mark 'domain' we get:
R (d=1) / \ (d=0) T D (d=1) / T (d=0)Quoted 5 lines
Quoted 1 line
Which clearly identifies the domains and the thread only groups.
So, the difference between the two interfaces is that the one I proposed is marking the thread root which makes all its descendants threaded while the above is marking each individual cgroup as being whether a resource domain or threaded.
You start by marking the thread root, but then continue to mark all 'threaded' (including root). This then leads to the problem described above where you cannot (easily) (re)discover what the actual root is.
Quoted 6 lines
Quoted 3 lines
I don't think that is true. Internally, we can always find out if a cgroup is a thread root. Externally, the presence of resource domain control knobs in a threaded cgroup will indicate that it is a thread root.
You're confusing thread root with resource domain. While a resource domain must be a thread root the reverse is not necessarily so (this is what I understood the 'join' thing to be for).
I know the difference between thread root and resource domain. In the current scheme, all the cgroups which are not threaded under a thread root are resource domain.
Quoted 3 lines
And this is detection by inference, which breaks the moment you disable all resource domain controllers, because at that point those files will not be present.
It is true that there is no external marker to find out if a threaded cgroup is a root or not when the parent of a thread root is also a thread root of a separate threaded subtree if the domain controller files are not present. However, we can always add a status file to indicate the state of threaded-ness of a cgroup if we want to.
Quoted 9 lines
Quoted 8 lines
Quoted 2 lines
My proposal differs in that we retain a clear difference between resource domain / root and threaded (sub)trees.
For me, I have no preference of using either the threaded or the domain marker as long as some kind of join operation that allows the configuration above is present in the thread mode. They both looks good to me. It is just a matter of which aspect of the cgroup we want to emphasize. I would suggest we reach a consensus ASAP and move forward to other more substantial issues in cgroup v2.
I think you're confused on join. Join should not be needed.
Tejun's patch makes resource domain the default and threaded-ness as an additional attribute that needs to be specified. Your proposal make non-resource domain where threads can exist as the default and resource domain as something that needs to be explicitly specified. They are just different ways of partitioning a cgroup hierarchy into different domains. Tejun's patch has a well defined boundary for threaded subtree where threads can be migrated from one part of a subtree to another. Your proposal is less clear-cut on how to handle thread migration.
Yes, the "join" operation may not be needed. It is just a matter of how much flexibility we want to specify the desirable cgroup configuration.
Cheers,
Longman
Peter Zijlstra
maintainerQuoted 11 lines · Waiman Long
The "join" was a special op for the children of cgroup root to join the root as part of a threaded subtree. The children can instead use the "enable" option to become a thread root which was the configuration shown above. This behavior applied only to children of root. Down the hierarchy, you can't have configuration like:
R (t=0) / \ D (t=1) / \ T D (t=1)
Why not?
First you create:
R (t=0)
/ \
D (t=1)
/ \
T T (t=1)Then you flip t=0 like:
R (t=0)
/ \
D (t=1)
/ \
T D (t=0)And then you flip t=1 again:
R (t=0)
/ \
D (t=1)
/ \
T D (t=1)Quoted 1 line
With Tejun's v3 patch, the "join" operation was removed and "enable"
I've no clue what 'enable' is... :-(
Quoted 6 lines
behaved like "join" in joining the threaded subtree of the root. I was wrong in saying that the configuration listed in your example was not possible. It was, but it depends on the order of activating the thread mode. If we enables thread mode on a child of root first followed by the root itself, we can have your configuration, but not in the reverse order. It was possible in the reverse order in the previous patch.
Just create a T child, then flip t=0 to convert it to D, then flip it to 1 again to create a new thread-root, no?
Quoted 9 lines
Quoted 3 lines
And this is detection by inference, which breaks the moment you disable all resource domain controllers, because at that point those files will not be present.
It is true that there is no external marker to find out if a threaded cgroup is a root or not when the parent of a thread root is also a thread root of a separate threaded subtree if the domain controller files are not present. However, we can always add a status file to indicate the state of threaded-ness of a cgroup if we want to.
Why add status files when a simple change in marker can readily provide this information?
Quoted 4 lines
Tejun's patch makes resource domain the default and threaded-ness as an additional attribute that needs to be specified. Your proposal make non-resource domain where threads can exist as the default and resource domain as something that needs to be explicitly specified.
Not so. My proposal has resource domains as the default (remember, root _MUST_ be a resource domain, therefore we must start start with root.d=1). Therefore, any new subgroup will be a resource domain by default and if you ignore the new attribute it will work exactly like cgroup-v2 does today.
Only if you clear the new attribute do you get a thread subgroup.
Quoted 5 lines
They are just
different ways of partitioning a cgroup hierarchy into different domains. Tejun's patch has a well defined boundary for threaded subtree where threads can be migrated from one part of a subtree to another. Your proposal is less clear-cut on how to handle thread migration.
Disagree again. We have the exact same boundaries. Just ensure the migration doesn't escape the resource domain.
Waiman Long
maintainerQuoted 31 lines · Peter Zijlstra
Quoted 11 lines · Waiman Long
The "join" was a special op for the children of cgroup root to join the root as part of a threaded subtree. The children can instead use the "enable" option to become a thread root which was the configuration shown above. This behavior applied only to children of root. Down the hierarchy, you can't have configuration like:
R (t=0) / \ D (t=1) / \ T D (t=1)Why not?
First you create:
R (t=0) / \ D (t=1) / \ T T (t=1)Then you flip t=0 like:
R (t=0) / \ D (t=1) / \ T D (t=0)
Quoted 7 lines
And then you flip t=1 again:
R (t=0) / \ D (t=1) / \ T D (t=1)
Tejun's thread mode patch has constraints on what operations are allowed and what aren't. For a threaded subtree, thread mode cannot be disabled in the middle of the tree. You have to remove all the child cgroups in the subtree before you can disable thread mode at the thread root level. So the second step will not be allowed. We can certainly argue if it is a good thing or not. What I am talking about is the current behavior of the patch.
Quoted 2 lines
Quoted 1 line
With Tejun's v3 patch, the "join" operation was removed and "enable"
I've no clue what 'enable' is... :-(
The keywords to turn on and off thread mode are:
enable: t=1
disable: t=0
As discussed above, there are constraints on when that transition is allowed to happen.
Quoted 8 lines
Quoted 6 lines
behaved like "join" in joining the threaded subtree of the root. I was wrong in saying that the configuration listed in your example was not possible. It was, but it depends on the order of activating the thread mode. If we enables thread mode on a child of root first followed by the root itself, we can have your configuration, but not in the reverse order. It was possible in the reverse order in the previous patch.
Just create a T child, then flip t=0 to convert it to D, then flip it to 1 again to create a new thread-root, no?
The constraints are there to make it easier to code and observe guidelines like no internal process constraint. So what you said above is not current allowed.
Quoted 10 lines
Quoted 8 lines
Quoted 3 lines
And this is detection by inference, which breaks the moment you disable all resource domain controllers, because at that point those files will not be present.
It is true that there is no external marker to find out if a threaded cgroup is a root or not when the parent of a thread root is also a thread root of a separate threaded subtree if the domain controller files are not present. However, we can always add a status file to indicate the state of threaded-ness of a cgroup if we want to.
Why add status files when a simple change in marker can readily provide this information?
For thread mode, the only way to find out if a cgroup is in that mode is to dump out the content of the cgroup.procs and cgroup.threads files. Reading cgroup.threads will return error if thread mode is not enabled. Reading cgroup.procs is allowed in the thread root, but not in the rest of the threaded subtree. So there is a way to find out, but kind of indirect.
Quoted 11 lines
Quoted 4 lines
Tejun's patch makes resource domain the default and threaded-ness as an additional attribute that needs to be specified. Your proposal make non-resource domain where threads can exist as the default and resource domain as something that needs to be explicitly specified.
Not so. My proposal has resource domains as the default (remember, root _MUST_ be a resource domain, therefore we must start start with root.d=1). Therefore, any new subgroup will be a resource domain by default and if you ignore the new attribute it will work exactly like cgroup-v2 does today.
Only if you clear the new attribute do you get a thread subgroup.
OK.
Quoted 8 lines
Quoted 5 lines
They are just
different ways of partitioning a cgroup hierarchy into different domains. Tejun's patch has a well defined boundary for threaded subtree where threads can be migrated from one part of a subtree to another. Your proposal is less clear-cut on how to handle thread migration.Disagree again. We have the exact same boundaries. Just ensure the migration doesn't escape the resource domain.
Agreed.
Cheers,
Longman
Peter Zijlstra
maintainerQuoted 40 lines · Waiman Long
Quoted 31 lines · Peter Zijlstra
Quoted 11 lines · Waiman Long
The "join" was a special op for the children of cgroup root to join the root as part of a threaded subtree. The children can instead use the "enable" option to become a thread root which was the configuration shown above. This behavior applied only to children of root. Down the hierarchy, you can't have configuration like:
R (t=0) / \ D (t=1) / \ T D (t=1)Why not?
First you create:
R (t=0) / \ D (t=1) / \ T T (t=1)Then you flip t=0 like:
R (t=0) / \ D (t=1) / \ T D (t=0)Quoted 7 lines
And then you flip t=1 again:
R (t=0) / \ D (t=1) / \ T D (t=1)
Quoted 3 lines
Tejun's thread mode patch has constraints on what operations are allowed and what aren't. For a threaded subtree, thread mode cannot be disabled in the middle of the tree.
Where in that scenario did I change anything in the middle? All operations were on a leaf group.
Waiman Long
maintainerQuoted 40 lines · Peter Zijlstra
Quoted 39 lines · Waiman Long
Quoted 38 lines · Peter Zijlstra
Quoted 11 lines · Waiman Long
The "join" was a special op for the children of cgroup root to join the root as part of a threaded subtree. The children can instead use the "enable" option to become a thread root which was the configuration shown above. This behavior applied only to children of root. Down the hierarchy, you can't have configuration like:
R (t=0) / \ D (t=1) / \ T D (t=1)Why not?
First you create:
R (t=0) / \ D (t=1) / \ T T (t=1)Then you flip t=0 like:
R (t=0) / \ D (t=1) / \ T D (t=0)And then you flip t=1 again:
R (t=0) / \ D (t=1) / \ T D (t=1)
Quoted 5 lines
Quoted 3 lines
Tejun's thread mode patch has constraints on what operations are allowed and what aren't. For a threaded subtree, thread mode cannot be disabled in the middle of the tree.
Where in that scenario did I change anything in the middle? All operations were on a leaf group.
What I mean is that you can't disable thread mode if not at the thread root with no children left.
Cheers,
Longman
Tejun Heo
maintainerPATCH 1/1 cgroup: update debug controller to print out thread mode information
In reply to Tejun HeoFrom: Waiman Long <[email protected]>
Update debug controller so that it prints out debug info about thread mode.
1) The relationship between proc_cset and threaded_csets are displayed.
2) The status of being a thread root or threaded cgroup is displayed.
This patch is extracted from Waiman's larger patch.
---
Hello,
Waiman, this is the thread mode support part of your debug patch. I'll include this in the thread mode patchset and apply it together. It seems to work fine but if you spot anything silly, please let me know.
Thanks.
kernel/cgroup/debug.c | 57 +++++++++++++++++++++++++++++++++++++------------- 1 file changed, 43 insertions(+), 14 deletions(-)
kernel/cgroup/debug.c +43 -14
@@ -114,27 +114,53 @@ static int cgroup_css_links_read(struct {struct cgroup_subsys_state *css =seq_css (seq);struct cgrp_cset_link *link; -int dead_cnt =0 , extra_refs =0 ; +int dead_cnt =0 , extra_refs =0 , threaded_csets =0 ;spin_lock_irq (&css_set_lock); + +if (css->cgroup->proc_cgrp) +seq_puts (seq, (css->cgroup->proc_cgrp == css->cgroup) ? +"[thread root]\n" :"[threaded]\n" ); +list_for_each_entry (link, &css->cgroup->cset_links, cset_link) {struct css_set *cset = link->cset;struct task_struct *task;int count =0 ;int refcnt =refcount_read (&cset->refcount); -seq_printf (seq," %d" , refcnt); -if (refcnt - cset->nr_tasks >0 ) { -int extra = refcnt - cset->nr_tasks; - -seq_printf (seq," +%d" , extra); -/* -* Take out the one additional reference in -* init_css_set. -*/ -if (cset == &init_css_set) - extra--; - extra_refs += extra; +/* +* Print out the proc_cset and threaded_cset relationship +* and highlight difference between refcount and task_count. +*/ +seq_printf (seq,"css_set %pK" , cset); +if (rcu_dereference_protected (cset->proc_cset,1 ) != cset) { + threaded_csets++; +seq_printf (seq,"=>%pK" , cset->proc_cset); + } +if (!list_empty (&cset->threaded_csets)) { +struct css_set *tcset; +int idx =0 ; + +list_for_each_entry (tcset, &cset->threaded_csets, + threaded_csets_node) { +seq_puts (seq, idx ?"," :"<=" ); +seq_printf (seq,"%pK" , tcset); + idx++; + } + }else { +seq_printf (seq," %d" , refcnt); +if (refcnt - cset->nr_tasks >0 ) { +int extra = refcnt - cset->nr_tasks; + +seq_printf (seq," +%d" , extra); +/* +* Take out the one additional reference in +* init_css_set. +*/ +if (cset == &init_css_set) + extra--; + extra_refs += extra; + } }seq_puts (seq,"\n" );
@@ -163,10 +189,12 @@ static int cgroup_css_links_read(struct }spin_unlock_irq (&css_set_lock); -if (!dead_cnt && !extra_refs) +if (!dead_cnt && !extra_refs && !threaded_csets)return 0 ;seq_puts (seq,"\n" ); +if (threaded_csets) +seq_printf (seq,"threaded css_sets = %d\n" , threaded_csets);if (extra_refs)seq_printf (seq,"extra references = %d\n" , extra_refs);if (dead_cnt)
@@ -342,6 +370,7 @@ struct cgroup_subsys debug_cgrp_subsys = .css_alloc = debug_css_alloc, .css_free = debug_css_free, .legacy_cftypes = debug_legacy_files, + .threaded = true, };/*