From: Kirill A. Shutsemov <hidden> Date: 2011-02-14 13:06:43
From: Kirill A. Shutemov <redacted>
Every task_struct has timer_slack_ns value. This value uses to round up
poll() and select() timeout values. This feature can be useful in
mobile environment where combined wakeups are desired.
cgroup subsys "timer_slack" implement timer slack controller. It
provides a way to group tasks by timer slack value and manage the
value of group's tasks.
Idea-by: Jacob Pan [off-list ref]
Signed-off-by: Kirill A. Shutemov <redacted>
---
Documentation/cgroups/timer_slack.txt | 93 +++++++++++
include/linux/cgroup_subsys.h | 6 +
init/Kconfig | 10 ++
kernel/Makefile | 1 +
kernel/cgroup_timer_slack.c | 285 +++++++++++++++++++++++++++++++++
5 files changed, 395 insertions(+), 0 deletions(-)
create mode 100644 Documentation/cgroups/timer_slack.txt
create mode 100644 kernel/cgroup_timer_slack.c
@@ -0,0 +1,93 @@+Timer Slack Controller+=====================++Overview+--------++Every task_struct has timer_slack_ns value. This value uses to round up+poll() and select() timeout values. This feature can be useful in+mobile environment where combined wakeups are desired.++cgroup subsys "timer_slack" implement timer slack controller. It+provides a way to group tasks by timer slack value and manage the+value of group's tasks.+++User interface+--------------++To get timer slack controller functionality you need to enable it in+kernel configuration:++CONFIG_CGROUP_TIMER_SLACK=y++or if you want to compile it as module:++CONFIG_CGROUP_TIMER_SLACK=m++The controller provides three files in cgroup directory:++# mount -t cgroup -o timer_slack none /sys/fs/cgroup+# ls /sys/fs/cgroup/timer_slack.*+/sys/fs/cgroup/timer_slack.max_slack_ns+/sys/fs/cgroup/timer_slack.min_slack_ns+/sys/fs/cgroup/timer_slack.set_slack_ns++timer_slack.min_slack_ns and timer_slack.set_slack_ns specify allowed+range of timer slack for tasks in cgroup. By default it unlimited:++# cat /sys/fs/cgroup/timer_slack.min_slack_ns+0+# cat /sys/fs/cgroup/timer_slack.max_slack_ns+4294967295++You can specify limits you want:++# echo 50000 > /sys/fs/cgroup/timer_slack.min_slack_ns+# echo 1000000 > /sys/fs/cgroup/timer_slack.max_slack_ns+# cat /sys/fs/cgroup/timer_slack.{min,max}_slack_ns+50000+1000000++Timer slack value of all tasks of the cgroup will be adjusted to fit+min-max range.++If a task will try to call prctl() to change timer slack value out of+the range it get -EPERM.++You can change timer slack value of all tasks of the cgroup at once:++# echo 70000 > /sys/fs/cgroup/timer_slack.set_slack_ns++Timer slack controller supports hierarchical groups. The only rule:+parent's limit range should be wider or equal to child's. Sibling+cgroups can have overlapping min-max range.++ (root: 50000 - 1000000)+ / \+ (a: 50000 - 50000) (b: 500000 - 1000000)+ / \+ (c: 500000 - 900000) (d: 700000 - 800000)++# mkdir /sys/fs/cgroup/a+# echo 50000 > /sys/fs/cgroup/a/timer_slack.max_slack_ns+# cat /sys/fs/cgroup/a/timer_slack.{min,max}_slack_ns+50000+50000+# mkdir /sys/fs/cgroup/b+# echo 500000 > /sys/fs/cgroup/b/timer_slack.min_slack_ns+# cat /sys/fs/cgroup/b/timer_slack.{min,max}_slack_ns+500000+1000000+# mkdir /sys/fs/cgroup/b/c+# echo 900000 > /sys/fs/cgroup/b/c/timer_slack.max_slack_ns+# cat /sys/fs/cgroup/b/c/timer_slack.{min,max}_slack_ns+500000+900000+# mkdir /sys/fs/cgroup/b/d+# echo 700000 > /sys/fs/cgroup/b/d/timer_slack.min_slack_ns+# echo 800000 > /sys/fs/cgroup/b/d/timer_slack.max_slack_ns+# cat /sys/fs/cgroup/b/d/timer_slack.{min,max}_slack_ns+700000+800000+
@@ -0,0 +1,285 @@+/*+*cgroup_timer_slack.c-controlgrouptimerslacksubsystem+*+*CopyrightNokiaCorparation,2011+*Author:KirillA.Shutemov+*+*Thisprogramisfreesoftware;youcanredistributeitand/ormodify+*itunderthetermsoftheGNUGeneralPublicLicenseaspublishedby+*theFreeSoftwareFoundation;eitherversion2oftheLicense,or+*(atyouroption)anylaterversion.+*+*Thisprogramisdistributedinthehopethatitwillbeuseful,+*butWITHOUTANYWARRANTY;withouteventheimpliedwarrantyof+*MERCHANTABILITYorFITNESSFORAPARTICULARPURPOSE.Seethe+*GNUGeneralPublicLicenseformoredetails.+*/+#include<linux/cgroup.h>+#include<linux/init_task.h>+#include<linux/module.h>+#include<linux/slab.h>+#include<linux/rcupdate.h>++structcgroup_subsystimer_slack_subsys;+structtimer_slack_cgroup{+structcgroup_subsys_statecss;+unsignedlongmin_slack_ns;+unsignedlongmax_slack_ns;+};++enum{+TIMER_SLACK_MIN,+TIMER_SLACK_MAX,+};++staticstructtimer_slack_cgroup*cgroup_to_tslack_cgroup(structcgroup*cgroup)+{+structcgroup_subsys_state*css;++css=cgroup_subsys_state(cgroup,timer_slack_subsys.subsys_id);+returncontainer_of(css,structtimer_slack_cgroup,css);+}++staticintis_timer_slack_allowed(structtimer_slack_cgroup*tslack_cgroup,+unsignedlongslack_ns)+{+if(slack_ns<tslack_cgroup->min_slack_ns||+slack_ns>tslack_cgroup->max_slack_ns)+returnfalse;+returntrue;+}++staticintcgroup_timer_slack_check(structnotifier_block*nb,+unsignedlongslack_ns,void*data)+{+structcgroup_subsys_state*css;+structtimer_slack_cgroup*tslack_cgroup;++/* XXX: lockdep false positive? */+rcu_read_lock();+css=task_subsys_state(current,timer_slack_subsys.subsys_id);+tslack_cgroup=container_of(css,structtimer_slack_cgroup,css);+rcu_read_unlock();++if(!is_timer_slack_allowed(tslack_cgroup,slack_ns))+returnnotifier_from_errno(-EPERM);+returnNOTIFY_OK;+}++staticstructnotifier_blockcgroup_timer_slack_nb={+.notifier_call=cgroup_timer_slack_check,+};++staticstructcgroup_subsys_state*+tslack_cgroup_create(structcgroup_subsys*subsys,structcgroup*cgroup)+{+structtimer_slack_cgroup*tslack_cgroup;++tslack_cgroup=kmalloc(sizeof(*tslack_cgroup),GFP_KERNEL);+if(!tslack_cgroup)+returnERR_PTR(-ENOMEM);++if(cgroup->parent){+structtimer_slack_cgroup*parent;+parent=cgroup_to_tslack_cgroup(cgroup->parent);+tslack_cgroup->min_slack_ns=parent->min_slack_ns;+tslack_cgroup->max_slack_ns=parent->max_slack_ns;+}else{+tslack_cgroup->min_slack_ns=0UL;+tslack_cgroup->max_slack_ns=ULONG_MAX;+}++return&tslack_cgroup->css;+}++staticvoidtslack_cgroup_destroy(structcgroup_subsys*subsys,+structcgroup*cgroup)+{+kfree(cgroup_to_tslack_cgroup(cgroup));+}++/*+*Adjust->timer_slack_nsand->default_max_slack_nsofthetasktofit+*limitsofthecgroup.+*/+staticvoidtslack_adjust_task(structtimer_slack_cgroup*tslack_cgroup,+structtask_struct*tsk)+{+if(tslack_cgroup->min_slack_ns>tsk->timer_slack_ns)+tsk->timer_slack_ns=tslack_cgroup->min_slack_ns;+elseif(tslack_cgroup->max_slack_ns<tsk->timer_slack_ns)+tsk->timer_slack_ns=tslack_cgroup->max_slack_ns;++if(tslack_cgroup->min_slack_ns>tsk->default_timer_slack_ns)+tsk->default_timer_slack_ns=tslack_cgroup->min_slack_ns;+elseif(tslack_cgroup->max_slack_ns<tsk->default_timer_slack_ns)+tsk->default_timer_slack_ns=tslack_cgroup->max_slack_ns;+}++staticvoidtslack_cgroup_attach(structcgroup_subsys*subsys,+structcgroup*cgroup,structcgroup*prev,+structtask_struct*tsk,boolthreadgroup)+{+tslack_adjust_task(cgroup_to_tslack_cgroup(cgroup),tsk);+}++staticinttslack_write_set_slack_ns(structcgroup*cgroup,structcftype*cft,+u64val)+{+structtimer_slack_cgroup*tslack_cgroup;+structcgroup_iterit;+structtask_struct*task;++tslack_cgroup=cgroup_to_tslack_cgroup(cgroup);+if(!is_timer_slack_allowed(cgroup_to_tslack_cgroup(cgroup),val))+return-EPERM;++/* Change timer slack value for all tasks in the cgroup */+cgroup_iter_start(cgroup,&it);+while((task=cgroup_iter_next(cgroup,&it)))+task->timer_slack_ns=val;+cgroup_iter_end(cgroup,&it);++return0;+}++staticu64tslack_read_range(structcgroup*cgroup,structcftype*cft)+{+structtimer_slack_cgroup*tslack_cgroup;++tslack_cgroup=cgroup_to_tslack_cgroup(cgroup);+switch(cft->private){+caseTIMER_SLACK_MIN:+returntslack_cgroup->min_slack_ns;+caseTIMER_SLACK_MAX:+returntslack_cgroup->max_slack_ns;+default:+BUG();+}+}++staticintvalidate_change(structcgroup*cgroup,u64val,inttype)+{+structtimer_slack_cgroup*tslack_cgroup,*child;+structcgroup*cur;++BUG_ON(type!=TIMER_SLACK_MIN&&type!=TIMER_SLACK_MAX);++if(val>ULONG_MAX)+return-EINVAL;++if(cgroup->parent){+structtimer_slack_cgroup*parent;+parent=cgroup_to_tslack_cgroup(cgroup->parent);+if(!is_timer_slack_allowed(parent,val))+return-EPERM;+}++tslack_cgroup=cgroup_to_tslack_cgroup(cgroup);+if(type==TIMER_SLACK_MIN&&val>tslack_cgroup->max_slack_ns)+return-EINVAL;+if(type==TIMER_SLACK_MAX&&val<tslack_cgroup->min_slack_ns)+return-EINVAL;++list_for_each_entry(cur,&cgroup->children,sibling){+child=cgroup_to_tslack_cgroup(cur);+if(type==TIMER_SLACK_MIN&&val>child->min_slack_ns)+return-EBUSY;+if(type==TIMER_SLACK_MAX&&val<child->max_slack_ns)+return-EBUSY;+}++return0;+}++staticinttslack_write_range(structcgroup*cgroup,structcftype*cft,+u64val)+{+structtimer_slack_cgroup*tslack_cgroup;+structcgroup_iterit;+structtask_struct*task;+interr;++err=validate_change(cgroup,val,cft->private);+if(err)+returnerr;++tslack_cgroup=cgroup_to_tslack_cgroup(cgroup);+if(cft->private==TIMER_SLACK_MIN)+tslack_cgroup->min_slack_ns=val;+else+tslack_cgroup->max_slack_ns=val;++/*+*Adjusttimerslackvalueforalltasksinthecgrouptofit+*min-maxrange.+*/+cgroup_iter_start(cgroup,&it);+while((task=cgroup_iter_next(cgroup,&it)))+tslack_adjust_task(tslack_cgroup,task);+cgroup_iter_end(cgroup,&it);++return0;+}++staticstructcftypefiles[]={+{+.name="set_slack_ns",+.write_u64=tslack_write_set_slack_ns,+},+{+.name="min_slack_ns",+.private=TIMER_SLACK_MIN,+.read_u64=tslack_read_range,+.write_u64=tslack_write_range,+},+{+.name="max_slack_ns",+.private=TIMER_SLACK_MAX,+.read_u64=tslack_read_range,+.write_u64=tslack_write_range,+},+};++staticinttslack_cgroup_populate(structcgroup_subsys*subsys,+structcgroup*cgroup)+{+returncgroup_add_files(cgroup,subsys,files,ARRAY_SIZE(files));+}++structcgroup_subsystimer_slack_subsys={+.name="timer_slack",+.module=THIS_MODULE,+#ifndef CONFIG_CGROUP_TIMER_SLACK_MODULE+.subsys_id=timer_slack_subsys_id,+#endif+.create=tslack_cgroup_create,+.destroy=tslack_cgroup_destroy,+.attach=tslack_cgroup_attach,+.populate=tslack_cgroup_populate,+};++staticint__initinit_cgroup_timer_slack(void)+{+interr;++err=register_timer_slack_notifier(&cgroup_timer_slack_nb);+if(err)+returnerr;++err=cgroup_load_subsys(&timer_slack_subsys);+if(err)+unregister_timer_slack_notifier(&cgroup_timer_slack_nb);++returnerr;+}++staticvoid__exitexit_cgroup_timer_slack(void)+{+unregister_timer_slack_notifier(&cgroup_timer_slack_nb);+cgroup_unload_subsys(&timer_slack_subsys);+}++module_init(init_cgroup_timer_slack);+module_exit(exit_cgroup_timer_slack);+MODULE_LICENSE("GPL");
From: Thomas Gleixner <hidden> Date: 2011-02-14 13:32:58
On Mon, 14 Feb 2011, Kirill A. Shutsemov wrote:
From: Kirill A. Shutemov <redacted>
Process can change its timer slack using prctl(). Timer slack notifier
call chain allows to react on such change or forbid it.
So we add a notifier call chain and more exports to allow what ?
From: Matt Helsley <hidden> Date: 2011-02-14 13:59:48
On Mon, Feb 14, 2011 at 03:06:27PM +0200, Kirill A. Shutsemov wrote:
quoted hunk
From: Kirill A. Shutemov <redacted>
Every task_struct has timer_slack_ns value. This value uses to round up
poll() and select() timeout values. This feature can be useful in
mobile environment where combined wakeups are desired.
cgroup subsys "timer_slack" implement timer slack controller. It
provides a way to group tasks by timer slack value and manage the
value of group's tasks.
Idea-by: Jacob Pan [off-list ref]
Signed-off-by: Kirill A. Shutemov <redacted>
---
Documentation/cgroups/timer_slack.txt | 93 +++++++++++
include/linux/cgroup_subsys.h | 6 +
init/Kconfig | 10 ++
kernel/Makefile | 1 +
kernel/cgroup_timer_slack.c | 285 +++++++++++++++++++++++++++++++++
5 files changed, 395 insertions(+), 0 deletions(-)
create mode 100644 Documentation/cgroups/timer_slack.txt
create mode 100644 kernel/cgroup_timer_slack.c
@@ -0,0 +1,93 @@+Timer Slack Controller+=====================++Overview+--------++Every task_struct has timer_slack_ns value. This value uses to round up+poll() and select() timeout values. This feature can be useful in+mobile environment where combined wakeups are desired.++cgroup subsys "timer_slack" implement timer slack controller. It+provides a way to group tasks by timer slack value and manage the+value of group's tasks.+++User interface+--------------++To get timer slack controller functionality you need to enable it in+kernel configuration:++CONFIG_CGROUP_TIMER_SLACK=y++or if you want to compile it as module:++CONFIG_CGROUP_TIMER_SLACK=m++The controller provides three files in cgroup directory:++# mount -t cgroup -o timer_slack none /sys/fs/cgroup+# ls /sys/fs/cgroup/timer_slack.*+/sys/fs/cgroup/timer_slack.max_slack_ns+/sys/fs/cgroup/timer_slack.min_slack_ns+/sys/fs/cgroup/timer_slack.set_slack_ns++timer_slack.min_slack_ns and timer_slack.set_slack_ns specify allowed+range of timer slack for tasks in cgroup. By default it unlimited:++# cat /sys/fs/cgroup/timer_slack.min_slack_ns+0+# cat /sys/fs/cgroup/timer_slack.max_slack_ns+4294967295++You can specify limits you want:++# echo 50000 > /sys/fs/cgroup/timer_slack.min_slack_ns+# echo 1000000 > /sys/fs/cgroup/timer_slack.max_slack_ns+# cat /sys/fs/cgroup/timer_slack.{min,max}_slack_ns+50000+1000000++Timer slack value of all tasks of the cgroup will be adjusted to fit+min-max range.++If a task will try to call prctl() to change timer slack value out of+the range it get -EPERM.++You can change timer slack value of all tasks of the cgroup at once:++# echo 70000 > /sys/fs/cgroup/timer_slack.set_slack_ns++Timer slack controller supports hierarchical groups. The only rule:+parent's limit range should be wider or equal to child's. Sibling+cgroups can have overlapping min-max range.++ (root: 50000 - 1000000)+ / \+ (a: 50000 - 50000) (b: 500000 - 1000000)+ / \+ (c: 500000 - 900000) (d: 700000 - 800000)++# mkdir /sys/fs/cgroup/a+# echo 50000 > /sys/fs/cgroup/a/timer_slack.max_slack_ns+# cat /sys/fs/cgroup/a/timer_slack.{min,max}_slack_ns+50000+50000+# mkdir /sys/fs/cgroup/b+# echo 500000 > /sys/fs/cgroup/b/timer_slack.min_slack_ns+# cat /sys/fs/cgroup/b/timer_slack.{min,max}_slack_ns+500000+1000000+# mkdir /sys/fs/cgroup/b/c+# echo 900000 > /sys/fs/cgroup/b/c/timer_slack.max_slack_ns+# cat /sys/fs/cgroup/b/c/timer_slack.{min,max}_slack_ns+500000+900000+# mkdir /sys/fs/cgroup/b/d+# echo 700000 > /sys/fs/cgroup/b/d/timer_slack.min_slack_ns+# echo 800000 > /sys/fs/cgroup/b/d/timer_slack.max_slack_ns+# cat /sys/fs/cgroup/b/d/timer_slack.{min,max}_slack_ns+700000+800000+
I think this test -- or at least accesses to the cgroup's min/max values
-- needs to be in the rcu_read_lock() else there is a race between the
notifier call from the context of the task calling prctl() and the context
of the task writing to the cgroup's (min|max)_slack_ns files.
It occured to me there's a macro for this in include/linux/kernel.h:
tsk->timer_slack_ns = clamp(tsk->timer_slack_ns,
tslack_cgroup->min_slack_ns,
tslack_cgroup->max_slack_ns);
+
+ if (tslack_cgroup->min_slack_ns > tsk->default_timer_slack_ns)
+ tsk->default_timer_slack_ns = tslack_cgroup->min_slack_ns;
+ else if (tslack_cgroup->max_slack_ns < tsk->default_timer_slack_ns)
+ tsk->default_timer_slack_ns = tslack_cgroup->max_slack_ns;
This doesn't look right. Child cgroups should not constrain their
parents. Instead you should allow the change and propagate the
constraint to the children.
One thing that might make reviewing such changes to these patches easier
would be to split out the arbitrary-depth hierarchy support into a
follow-on patch. You can do it like blkio does in the _create() function:
/* Currently we do not support hierarchy deeper than two level */
if (parent != cgroup->top_cgroup)
return ERR_PTR(-EPERM);
+
+ return 0;
+}
+
+static int tslack_write_range(struct cgroup *cgroup, struct cftype *cft,
+ u64 val)
+{
+ struct timer_slack_cgroup *tslack_cgroup;
+ struct cgroup_iter it;
+ struct task_struct *task;
+ int err;
+
+ err = validate_change(cgroup, val, cft->private);
+ if (err)
+ return err;
+
+ tslack_cgroup = cgroup_to_tslack_cgroup(cgroup);
+ if (cft->private == TIMER_SLACK_MIN)
+ tslack_cgroup->min_slack_ns = val;
+ else
+ tslack_cgroup->max_slack_ns = val;
+
+ /*
+ * Adjust timer slack value for all tasks in the cgroup to fit
+ * min-max range.
+ */
+ cgroup_iter_start(cgroup, &it);
+ while ((task = cgroup_iter_next(cgroup, &it)))
+ tslack_adjust_task(tslack_cgroup, task);
+ cgroup_iter_end(cgroup, &it);
So, you should "adjust" child cgroups too rather than return -EBUSY from
validate_change().
I didn't get a reply on how a max_slack_ns is useful. It seems
prudent to add as little interface as possible and only when
we clearly see the utility of it.
Cheers,
-Matt Helsley
From: Thomas Gleixner <hidden> Date: 2011-02-14 14:01:05
On Mon, 14 Feb 2011, Kirill A. Shutsemov wrote:
From: Kirill A. Shutemov <redacted>
Every task_struct has timer_slack_ns value. This value uses to round up
poll() and select() timeout values. This feature can be useful in
mobile environment where combined wakeups are desired.
cgroup subsys "timer_slack" implement timer slack controller. It
provides a way to group tasks by timer slack value and manage the
value of group's tasks.
I have no objections against the whole thing in general, but why do we
need a module for this? Why can't we add this to the cgroups muck and
compile it in?
From: Kirill A. Shutemov <hidden> Date: 2011-02-14 14:52:47
On Mon, Feb 14, 2011 at 02:32:23PM +0100, Thomas Gleixner wrote:
On Mon, 14 Feb 2011, Kirill A. Shutsemov wrote:
quoted
From: Kirill A. Shutemov <redacted>
Process can change its timer slack using prctl(). Timer slack notifier
call chain allows to react on such change or forbid it.
So we add a notifier call chain and more exports to allow what ?
From: Thomas Gleixner <hidden> Date: 2011-02-14 15:18:06
On Mon, 14 Feb 2011, Kirill A. Shutemov wrote:
On Mon, Feb 14, 2011 at 02:32:23PM +0100, Thomas Gleixner wrote:
quoted
On Mon, 14 Feb 2011, Kirill A. Shutsemov wrote:
quoted
From: Kirill A. Shutemov <redacted>
Process can change its timer slack using prctl(). Timer slack notifier
call chain allows to react on such change or forbid it.
So we add a notifier call chain and more exports to allow what ?
To allow the cgroup contoller validate the value.
So we add 5 exports and a notifier chain to have a module? Errm, I
mean there is not really a high probability that we'll add 5 more of
those validation thingies, right?
So instead of having
#ifdef CONFIG_CGROUP_MUCK
int cgroup_set_slack(....);
#else
static inline int cgroup_set_slack(...)
{
return ....
}
#endif
We add all that stuff ?
What's the point of replacing current->timer_slack_ns with a
function which does exactly the same ?
To keep it consistent. BTW, prctl_get_seccomp() does the same.
That does not make it less bloat.
quoted
quoted
+long prctl_set_timer_slack(long timer_slack_ns)
+{
+ int err;
+
+ /* Reset timer slack to default value */
+ if (timer_slack_ns <= 0) {
+ current->timer_slack_ns = current->default_timer_slack_ns;
+ return 0;
That does not make any sense at all. Why is setting
default_timer_slack_ns not subject to validation ?
Hm.. In case of cgroup_timer_slack it's always valid.
But, yes, in general, we should validate it.
quoted
Why is it treaded seperately ?
What do you mean?
Should have read:
Why is it treated seperately from the other settings?
So setting the default is probably correct to be out of the validation
thing, still the question remains, why we do not have a cgroup default
then.
Thanks,
tglx
From: Kirill A. Shutemov <hidden> Date: 2011-02-14 15:19:26
On Mon, Feb 14, 2011 at 03:00:03PM +0100, Thomas Gleixner wrote:
On Mon, 14 Feb 2011, Kirill A. Shutsemov wrote:
quoted
From: Kirill A. Shutemov <redacted>
Every task_struct has timer_slack_ns value. This value uses to round up
poll() and select() timeout values. This feature can be useful in
mobile environment where combined wakeups are desired.
cgroup subsys "timer_slack" implement timer slack controller. It
provides a way to group tasks by timer slack value and manage the
value of group's tasks.
I have no objections against the whole thing in general, but why do we
need a module for this? Why can't we add this to the cgroups muck and
compile it in?
It was easier to test and debug with module.
What is wrong with module? Do you worry about number of exports?
From: Thomas Gleixner <hidden> Date: 2011-02-14 17:02:34
B1;2401;0cOn Mon, 14 Feb 2011, Kirill A. Shutemov wrote:
On Mon, Feb 14, 2011 at 03:00:03PM +0100, Thomas Gleixner wrote:
quoted
On Mon, 14 Feb 2011, Kirill A. Shutsemov wrote:
quoted
From: Kirill A. Shutemov <redacted>
Every task_struct has timer_slack_ns value. This value uses to round up
poll() and select() timeout values. This feature can be useful in
mobile environment where combined wakeups are desired.
cgroup subsys "timer_slack" implement timer slack controller. It
provides a way to group tasks by timer slack value and manage the
value of group's tasks.
I have no objections against the whole thing in general, but why do we
need a module for this? Why can't we add this to the cgroups muck and
compile it in?
It was easier to test and debug with module.
What is wrong with module? Do you worry about number of exports?
Not only about the number. We don't want exports when they are not
techically necessary, i.e. for driver stuff.
What? Either this has a reason or not. If it's a false positive then
it needs to be fixed in lockdep. If not, ....
I was not sure about it. There is similar workaround in freezer_fork().
I don't care about workarounds in freezer_work() at all. The above
question remains and this is new code and therefor it either needs to
hold rcu_read_lock() or it does not.
I thought the whole point is to propagate values through the group.
I think silent change here is wrong. cpuset returns -EBUSY in similar
case.
And how is cpuset relevant for this ? Not at all. This is about
timer_slack and we better have a well defined scheme for all of this
and not some cobbled together thing with tons of exceptions and corner
cases. Of course undocumented as far the code goes.
Thanks,
tglx
From: Kirill A. Shutemov <hidden> Date: 2011-02-14 22:39:50
On Mon, Feb 14, 2011 at 06:01:06PM +0100, Thomas Gleixner wrote:
B1;2401;0cOn Mon, 14 Feb 2011, Kirill A. Shutemov wrote:
quoted
On Mon, Feb 14, 2011 at 03:00:03PM +0100, Thomas Gleixner wrote:
quoted
On Mon, 14 Feb 2011, Kirill A. Shutsemov wrote:
quoted
From: Kirill A. Shutemov <redacted>
Every task_struct has timer_slack_ns value. This value uses to round up
poll() and select() timeout values. This feature can be useful in
mobile environment where combined wakeups are desired.
cgroup subsys "timer_slack" implement timer slack controller. It
provides a way to group tasks by timer slack value and manage the
value of group's tasks.
I have no objections against the whole thing in general, but why do we
need a module for this? Why can't we add this to the cgroups muck and
compile it in?
It was easier to test and debug with module.
What is wrong with module? Do you worry about number of exports?
Not only about the number. We don't want exports when they are not
techically necessary, i.e. for driver stuff.
What? Either this has a reason or not. If it's a false positive then
it needs to be fixed in lockdep. If not, ....
I was not sure about it. There is similar workaround in freezer_fork().
I don't care about workarounds in freezer_work() at all. The above
question remains and this is new code and therefor it either needs to
hold rcu_read_lock() or it does not.
I thought the whole point is to propagate values through the group.
I think silent change here is wrong. cpuset returns -EBUSY in similar
case.
And how is cpuset relevant for this ? Not at all. This is about
timer_slack and we better have a well defined scheme for all of this
and not some cobbled together thing with tons of exceptions and corner
cases. Of course undocumented as far the code goes.
I don't like silent cascade changes. Userspace can implement it if
needed. -EBUSY is appropriate.
--
Kirill A. Shutemov
From: Kirill A. Shutemov <hidden> Date: 2011-02-14 22:59:45
On Mon, Feb 14, 2011 at 05:59:26AM -0800, Matt Helsley wrote:
On Mon, Feb 14, 2011 at 03:06:27PM +0200, Kirill A. Shutsemov wrote:
quoted
From: Kirill A. Shutemov <redacted>
Every task_struct has timer_slack_ns value. This value uses to round up
poll() and select() timeout values. This feature can be useful in
mobile environment where combined wakeups are desired.
cgroup subsys "timer_slack" implement timer slack controller. It
provides a way to group tasks by timer slack value and manage the
value of group's tasks.
Idea-by: Jacob Pan [off-list ref]
Signed-off-by: Kirill A. Shutemov <redacted>
---
Documentation/cgroups/timer_slack.txt | 93 +++++++++++
include/linux/cgroup_subsys.h | 6 +
init/Kconfig | 10 ++
kernel/Makefile | 1 +
kernel/cgroup_timer_slack.c | 285 +++++++++++++++++++++++++++++++++
5 files changed, 395 insertions(+), 0 deletions(-)
create mode 100644 Documentation/cgroups/timer_slack.txt
create mode 100644 kernel/cgroup_timer_slack.c
@@ -0,0 +1,93 @@+Timer Slack Controller+=====================++Overview+--------++Every task_struct has timer_slack_ns value. This value uses to round up+poll() and select() timeout values. This feature can be useful in+mobile environment where combined wakeups are desired.++cgroup subsys "timer_slack" implement timer slack controller. It+provides a way to group tasks by timer slack value and manage the+value of group's tasks.+++User interface+--------------++To get timer slack controller functionality you need to enable it in+kernel configuration:++CONFIG_CGROUP_TIMER_SLACK=y++or if you want to compile it as module:++CONFIG_CGROUP_TIMER_SLACK=m++The controller provides three files in cgroup directory:++# mount -t cgroup -o timer_slack none /sys/fs/cgroup+# ls /sys/fs/cgroup/timer_slack.*+/sys/fs/cgroup/timer_slack.max_slack_ns+/sys/fs/cgroup/timer_slack.min_slack_ns+/sys/fs/cgroup/timer_slack.set_slack_ns++timer_slack.min_slack_ns and timer_slack.set_slack_ns specify allowed+range of timer slack for tasks in cgroup. By default it unlimited:++# cat /sys/fs/cgroup/timer_slack.min_slack_ns+0+# cat /sys/fs/cgroup/timer_slack.max_slack_ns+4294967295++You can specify limits you want:++# echo 50000 > /sys/fs/cgroup/timer_slack.min_slack_ns+# echo 1000000 > /sys/fs/cgroup/timer_slack.max_slack_ns+# cat /sys/fs/cgroup/timer_slack.{min,max}_slack_ns+50000+1000000++Timer slack value of all tasks of the cgroup will be adjusted to fit+min-max range.++If a task will try to call prctl() to change timer slack value out of+the range it get -EPERM.++You can change timer slack value of all tasks of the cgroup at once:++# echo 70000 > /sys/fs/cgroup/timer_slack.set_slack_ns++Timer slack controller supports hierarchical groups. The only rule:+parent's limit range should be wider or equal to child's. Sibling+cgroups can have overlapping min-max range.++ (root: 50000 - 1000000)+ / \+ (a: 50000 - 50000) (b: 500000 - 1000000)+ / \+ (c: 500000 - 900000) (d: 700000 - 800000)++# mkdir /sys/fs/cgroup/a+# echo 50000 > /sys/fs/cgroup/a/timer_slack.max_slack_ns+# cat /sys/fs/cgroup/a/timer_slack.{min,max}_slack_ns+50000+50000+# mkdir /sys/fs/cgroup/b+# echo 500000 > /sys/fs/cgroup/b/timer_slack.min_slack_ns+# cat /sys/fs/cgroup/b/timer_slack.{min,max}_slack_ns+500000+1000000+# mkdir /sys/fs/cgroup/b/c+# echo 900000 > /sys/fs/cgroup/b/c/timer_slack.max_slack_ns+# cat /sys/fs/cgroup/b/c/timer_slack.{min,max}_slack_ns+500000+900000+# mkdir /sys/fs/cgroup/b/d+# echo 700000 > /sys/fs/cgroup/b/d/timer_slack.min_slack_ns+# echo 800000 > /sys/fs/cgroup/b/d/timer_slack.max_slack_ns+# cat /sys/fs/cgroup/b/d/timer_slack.{min,max}_slack_ns+700000+800000+
I think this test -- or at least accesses to the cgroup's min/max values
-- needs to be in the rcu_read_lock() else there is a race between the
notifier call from the context of the task calling prctl() and the context
of the task writing to the cgroup's (min|max)_slack_ns files.
It occured to me there's a macro for this in include/linux/kernel.h:
tsk->timer_slack_ns = clamp(tsk->timer_slack_ns,
tslack_cgroup->min_slack_ns,
tslack_cgroup->max_slack_ns);
Nice. Thank you.
quoted
+
+ if (tslack_cgroup->min_slack_ns > tsk->default_timer_slack_ns)
+ tsk->default_timer_slack_ns = tslack_cgroup->min_slack_ns;
+ else if (tslack_cgroup->max_slack_ns < tsk->default_timer_slack_ns)
+ tsk->default_timer_slack_ns = tslack_cgroup->max_slack_ns;
This doesn't look right. Child cgroups should not constrain their
parents. Instead you should allow the change and propagate the
constraint to the children.
See discussion with Thomas.
One thing that might make reviewing such changes to these patches easier
would be to split out the arbitrary-depth hierarchy support into a
follow-on patch. You can do it like blkio does in the _create() function:
/* Currently we do not support hierarchy deeper than two level */
if (parent != cgroup->top_cgroup)
return ERR_PTR(-EPERM);
quoted
+
+ return 0;
+}
+
+static int tslack_write_range(struct cgroup *cgroup, struct cftype *cft,
+ u64 val)
+{
+ struct timer_slack_cgroup *tslack_cgroup;
+ struct cgroup_iter it;
+ struct task_struct *task;
+ int err;
+
+ err = validate_change(cgroup, val, cft->private);
+ if (err)
+ return err;
+
+ tslack_cgroup = cgroup_to_tslack_cgroup(cgroup);
+ if (cft->private == TIMER_SLACK_MIN)
+ tslack_cgroup->min_slack_ns = val;
+ else
+ tslack_cgroup->max_slack_ns = val;
+
+ /*
+ * Adjust timer slack value for all tasks in the cgroup to fit
+ * min-max range.
+ */
+ cgroup_iter_start(cgroup, &it);
+ while ((task = cgroup_iter_next(cgroup, &it)))
+ tslack_adjust_task(tslack_cgroup, task);
+ cgroup_iter_end(cgroup, &it);
So, you should "adjust" child cgroups too rather than return -EBUSY from
validate_change().
I didn't get a reply on how a max_slack_ns is useful. It seems
prudent to add as little interface as possible and only when
we clearly see the utility of it.
For example, you can create two groups (excluding root cgroup):
default - timer slack range 50000-50000
relaxed - timer slack range 500000-unlimited.
Now you can drag tasks between these group without need to reset value on
relaxed -> default transition.
--
Kirill A. Shutemov
I thought the whole point is to propagate values through the group.
I think silent change here is wrong. cpuset returns -EBUSY in similar
case.
And how is cpuset relevant for this ? Not at all. This is about
I agree with Thomas here -- cpusets aren't relevant.
quoted
timer_slack and we better have a well defined scheme for all of this
and not some cobbled together thing with tons of exceptions and corner
cases. Of course undocumented as far the code goes.
I don't like silent cascade changes. Userspace can implement it if
It need not be totally silent. memcg has a "use_hierarchy" flag file.
Alternately, you could punt for now and disable hierarchy somewhat like
blkio does.
needed. -EBUSY is appropriate.
Hmm, I haven't thought about that method of cascading enough. The important
question to consider is how will the parent cgroup be constrained if the
owner/group of the children is different and thus disallows userspace from
implementing this cascade. I suppose it's consistent with the owner/group
ids but it hardly seems consistent with the "spirit" of using cgroups to
enable things like containers.
Cheers,
-Matt Helsley
From: Matt Helsley <hidden> Date: 2011-02-15 00:01:06
On Tue, Feb 15, 2011 at 12:59:40AM +0200, Kirill A. Shutemov wrote:
On Mon, Feb 14, 2011 at 05:59:26AM -0800, Matt Helsley wrote:
quoted
On Mon, Feb 14, 2011 at 03:06:27PM +0200, Kirill A. Shutsemov wrote:
quoted
From: Kirill A. Shutemov <redacted>
<snip>
quoted
quoted
+ list_for_each_entry(cur, &cgroup->children, sibling) {
+ child = cgroup_to_tslack_cgroup(cur);
+ if (type == TIMER_SLACK_MIN && val > child->min_slack_ns)
+ return -EBUSY;
+ if (type == TIMER_SLACK_MAX && val < child->max_slack_ns)
+ return -EBUSY;
+ }
This doesn't look right. Child cgroups should not constrain their
parents. Instead you should allow the change and propagate the
constraint to the children.
I didn't get a reply on how a max_slack_ns is useful. It seems
prudent to add as little interface as possible and only when
we clearly see the utility of it.
For example, you can create two groups (excluding root cgroup):
default - timer slack range 50000-50000
relaxed - timer slack range 500000-unlimited.
Now you can drag tasks between these group without need to reset value on
relaxed -> default transition.
Perhaps you misunderstood my point.
Yes, I can see that a maximum allows you to do counter-productive/pointless
little tricks like "setting" the timer slack when you move the task. I
just don't get the point of it. Why is setting a maximum timer slack useful?
If anything it seems like it would be quite counterproductive or pointless
*at best* because limiting the amount of timer slack would not improve
the wakeup situation -- it could easily make it worse. Are there
*any* negative consequences to allowing timer slacks as large as
userspace requests -- perhaps even up to ULLONG_MAX? If there are none then
why should we bother providing userspace a knob to set and enforce such a
limit?
Cheers,
-Matt Helsley
From: Kirill A. Shutemov <hidden> Date: 2011-02-15 00:10:09
On Mon, Feb 14, 2011 at 04:00:55PM -0800, Matt Helsley wrote:
On Tue, Feb 15, 2011 at 12:59:40AM +0200, Kirill A. Shutemov wrote:
quoted
On Mon, Feb 14, 2011 at 05:59:26AM -0800, Matt Helsley wrote:
quoted
On Mon, Feb 14, 2011 at 03:06:27PM +0200, Kirill A. Shutsemov wrote:
quoted
From: Kirill A. Shutemov <redacted>
<snip>
quoted
quoted
quoted
+ list_for_each_entry(cur, &cgroup->children, sibling) {
+ child = cgroup_to_tslack_cgroup(cur);
+ if (type == TIMER_SLACK_MIN && val > child->min_slack_ns)
+ return -EBUSY;
+ if (type == TIMER_SLACK_MAX && val < child->max_slack_ns)
+ return -EBUSY;
+ }
This doesn't look right. Child cgroups should not constrain their
parents. Instead you should allow the change and propagate the
constraint to the children.
I didn't get a reply on how a max_slack_ns is useful. It seems
prudent to add as little interface as possible and only when
we clearly see the utility of it.
For example, you can create two groups (excluding root cgroup):
default - timer slack range 50000-50000
relaxed - timer slack range 500000-unlimited.
Now you can drag tasks between these group without need to reset value on
relaxed -> default transition.
Perhaps you misunderstood my point.
Yes, I can see that a maximum allows you to do counter-productive/pointless
little tricks like "setting" the timer slack when you move the task. I
just don't get the point of it. Why is setting a maximum timer slack useful?
If anything it seems like it would be quite counterproductive or pointless
*at best* because limiting the amount of timer slack would not improve
the wakeup situation -- it could easily make it worse. Are there
*any* negative consequences to allowing timer slacks as large as
userspace requests -- perhaps even up to ULLONG_MAX? If there are none then
why should we bother providing userspace a knob to set and enforce such a
limit?
Could you describe the interface how you see it?
--
Kirill A. Shutemov
From: Thomas Gleixner <hidden> Date: 2011-02-15 06:05:33
On Tue, 15 Feb 2011, Kirill A. Shutemov wrote:
On Mon, Feb 14, 2011 at 06:01:06PM +0100, Thomas Gleixner wrote:
quoted
quoted
I think silent change here is wrong. cpuset returns -EBUSY in similar
case.
And how is cpuset relevant for this ? Not at all. This is about
timer_slack and we better have a well defined scheme for all of this
and not some cobbled together thing with tons of exceptions and corner
cases. Of course undocumented as far the code goes.
I don't like silent cascade changes. Userspace can implement it if
needed. -EBUSY is appropriate.
And I don't like totally uncommented code which follows come cobbled
together completely non obvious rules.
It's not about what you like. It's about getting useful functionality
when we add a new infrastructure like this.
So could you please explain what the rules of updating are, so that a
reviewer has a chance to understand the rationale of all this.
Thanks,
tglx