Here is the patch
diff -urN linux-2.6.32/Documentation/kernel-parameters.txt linux/Documentation/kernel-parameters.txt
--- linux-2.6.32/Documentation/kernel-parameters.txt 2010-10-31 16:13:19.000000000 +0530
+++ linux/Documentation/kernel-parameters.txt 2010-11-18 10:05:50.027037654 +0530
@@ -1618,6 +1618,9 @@
noapic [SMP,APIC] Tells the kernel to not make use of any
IOAPICs that may be present in the system.
+ noautogroup Disable scheduler automatic task group creation.
+
+
nobats [PPC] Do not use BATs for mapping kernel lowmem
on "Classic" PPC cores.
diff -urN linux-2.6.32/drivers/char/tty_io.c linux/drivers/char/tty_io.c
--- linux-2.6.32/drivers/char/tty_io.c 2010-10-31 16:13:19.000000000 +0530
+++ linux/drivers/char/tty_io.c 2010-11-18 10:06:51.637609197 +0530
@@ -3029,6 +3029,8 @@
put_pid(tsk->signal->tty_old_pgrp);
tsk->signal->tty = tty_kref_get(tty);
tsk->signal->tty_old_pgrp = NULL;
+
+ sched_autogroup_create_attach(tsk);
}
static void proc_set_tty(struct task_struct *tsk, struct tty_struct *tty)
diff -urN linux-2.6.32/include/linux/sched.h linux/include/linux/sched.h
--- linux-2.6.32/include/linux/sched.h 2010-10-31 16:13:19.000000000 +0530
+++ linux/include/linux/sched.h 2010-11-18 09:45:08.517579562 +0530
@@ -556,6 +556,8 @@
spinlock_t lock;
};
+struct autogroup;
+
/*
* NOTE! "signal_struct" does not have it's own
* locking, because a shared signal_struct always
@@ -622,6 +624,10 @@
struct tty_struct *tty; /* NULL if no tty */
+#ifdef CONFIG_SCHED_AUTOGROUP
+ struct autogroup *autogroup;
+#endif
+
/*
* Cumulative resource counters for dead threads in the group,
* and for reaped dead child processes forked by this group.
@@ -1939,6 +1945,22 @@
extern unsigned int sysctl_sched_compat_yield;
+#ifdef CONFIG_SCHED_AUTOGROUP
+extern unsigned int sysctl_sched_autogroup_enabled;
+
+extern void sched_autogroup_create_attach(struct task_struct *p);
+extern void sched_autogroup_detach(struct task_struct *p);
+extern void sched_autogroup_fork(struct signal_struct *sig);
+extern void sched_autogroup_exit(struct signal_struct *sig);
+#else
+static inline void sched_autogroup_create_attach(struct task_struct *p) { }
+static inline void sched_autogroup_detach(struct task_struct *p) { }
+static inline void sched_autogroup_fork(struct signal_struct *sig) { }
+static inline void sched_autogroup_exit(struct signal_struct *sig) { }
+#endif
+
+
+
#ifdef CONFIG_RT_MUTEXES
extern int rt_mutex_getprio(struct task_struct *p);
extern void rt_mutex_setprio(struct task_struct *p, int prio);
diff -urN linux-2.6.32/init/Kconfig linux/init/Kconfig
--- linux-2.6.32/init/Kconfig 2010-10-31 16:13:19.000000000 +0530
+++ linux/init/Kconfig 2010-11-18 10:04:56.430328910 +0530
@@ -608,6 +608,19 @@
endif # CGROUPS
+config SCHED_AUTOGROUP
+ bool "Automatic process group scheduling"
+ select CGROUPS
+ select CGROUP_SCHED
+ select FAIR_GROUP_SCHED
+ help
+ This option optimizes the scheduler for common desktop workloads by
+ automatically creating and populating task groups. This separation
+ of workloads isolates aggressive CPU burners (like build jobs) from
+ desktop applications. Task group autogeneration is currently based
+ upon task tty association.
+
+
config MM_OWNER
bool
diff -urN linux-2.6.32/kernel/fork.c linux/kernel/fork.c
--- linux-2.6.32/kernel/fork.c 2010-10-31 16:13:19.000000000 +0530
+++ linux/kernel/fork.c 2010-11-18 10:10:19.796963164 +0530
@@ -908,6 +908,8 @@
tty_audit_fork(sig);
+ sched_autogroup_fork(sig);
+
sig->oom_adj = current->signal->oom_adj;
return 0;
diff -urN linux-2.6.32/kernel/sched_autogroup.c linux/kernel/sched_autogroup.c
--- linux-2.6.32/kernel/sched_autogroup.c 1970-01-01 05:30:00.000000000 +0530
+++ linux/kernel/sched_autogroup.c 2010-11-17 22:43:28.726509000 +0530
@@ -0,0 +1,140 @@
+#ifdef CONFIG_SCHED_AUTOGROUP
+
+unsigned int __read_mostly sysctl_sched_autogroup_enabled = 1;
+
+struct autogroup {
+ struct kref kref;
+ struct task_group *tg;
+};
+
+static struct autogroup autogroup_default;
+
+static void autogroup_init(struct task_struct *init_task)
+{
+ autogroup_default.tg = &init_task_group;
+ kref_init(&autogroup_default.kref);
+ init_task->signal->autogroup = &autogroup_default;
+}
+
+static inline void autogroup_destroy(struct kref *kref)
+{
+ struct autogroup *ag = container_of(kref, struct autogroup, kref);
+ struct task_group *tg = ag->tg;
+
+ kfree(ag);
+ sched_destroy_group(tg);
+}
+
+static inline void autogroup_kref_put(struct autogroup *ag)
+{
+ kref_put(&ag->kref, autogroup_destroy);
+}
+
+static inline struct autogroup *autogroup_kref_get(struct autogroup *ag)
+{
+ kref_get(&ag->kref);
+ return ag;
+}
+
+static inline struct autogroup *autogroup_create(void)
+{
+ struct autogroup *ag = kmalloc(sizeof(*ag), GFP_KERNEL);
+
+ if (!ag)
+ goto out_fail;
+
+ ag->tg = sched_create_group(&init_task_group);
+ kref_init(&ag->kref);
+
+ if (!(IS_ERR(ag->tg)))
+ return ag;
+
+out_fail:
+ if (ag) {
+ kfree(ag);
+ WARN_ON(1);
+ } else
+ WARN_ON(1);
+
+ return autogroup_kref_get(&autogroup_default);
+}
+
+static inline struct task_group *
+autogroup_task_group(struct task_struct *p, struct task_group *tg)
+{
+ int enabled = ACCESS_ONCE(sysctl_sched_autogroup_enabled);
+
+ enabled &= (tg == &root_task_group);
+ enabled &= (p->sched_class == &fair_sched_class);
+ enabled &= (!(p->flags & PF_EXITING));
+
+ if (enabled)
+ return p->signal->autogroup->tg;
+
+ return tg;
+}
+
+static void
+autogroup_move_group(struct task_struct *p, struct autogroup *ag)
+{
+ struct autogroup *prev;
+ struct task_struct *t;
+ struct rq *rq;
+ unsigned long flags;
+
+ rq = task_rq_lock(p, &flags);
+ prev = p->signal->autogroup;
+ if (prev == ag) {
+ task_rq_unlock(rq, &flags);
+ return;
+ }
+
+ p->signal->autogroup = autogroup_kref_get(ag);
+ __sched_move_task(p, rq);
+ task_rq_unlock(rq, &flags);
+
+ rcu_read_lock();
+ list_for_each_entry_rcu(t, &p->thread_group, thread_group) {
+ sched_move_task(t);
+ }
+ rcu_read_unlock();
+
+ autogroup_kref_put(prev);
+}
+
+void sched_autogroup_create_attach(struct task_struct *p)
+{
+ struct autogroup *ag = autogroup_create();
+
+ autogroup_move_group(p, ag);
+ /* drop extra refrence added by autogroup_create() */
+ autogroup_kref_put(ag);
+}
+EXPORT_SYMBOL(sched_autogroup_create_attach);
+
+/* currently has no users */
+void sched_autogroup_detach(struct task_struct *p)
+{
+ autogroup_move_group(p, &autogroup_default);
+}
+EXPORT_SYMBOL(sched_autogroup_detach);
+
+void sched_autogroup_fork(struct signal_struct *sig)
+{
+ sig->autogroup = autogroup_kref_get(current->signal->autogroup);
+}
+
+void sched_autogroup_exit(struct signal_struct *sig)
+{
+ autogroup_kref_put(sig->autogroup);
+}
+
+static int __init setup_autogroup(char *str)
+{
+ sysctl_sched_autogroup_enabled = 0;
+
+ return 1;
+}
+
+__setup("noautogroup", setup_autogroup);
+#endif
diff -urN linux-2.6.32/kernel/sched_autogroup.h linux/kernel/sched_autogroup.h
--- linux-2.6.32/kernel/sched_autogroup.h 1970-01-01 05:30:00.000000000 +0530
+++ linux/kernel/sched_autogroup.h 2010-11-17 22:39:46.575555000 +0530
@@ -0,0 +1,18 @@
+#ifdef CONFIG_SCHED_AUTOGROUP
+
+static void __sched_move_task(struct task_struct *tsk, struct rq *rq);
+
+static inline struct task_group *
+autogroup_task_group(struct task_struct *p, struct task_group *tg);
+
+#else /* !CONFIG_SCHED_AUTOGROUP */
+
+static inline void autogroup_init(struct task_struct *init_task) { }
+
+static inline struct task_group *
+autogroup_task_group(struct task_struct *p, struct task_group *tg)
+{
+ return tg;
+}
+
+#endif /* CONFIG_SCHED_AUTOGROUP */
diff -urN linux-2.6.32/kernel/sched.c linux/kernel/sched.c
--- linux-2.6.32/kernel/sched.c 2010-10-31 16:13:19.000000000 +0530
+++ linux/kernel/sched.c 2010-11-18 10:01:01.377697053 +0530
@@ -76,6 +76,7 @@
#include
#include "sched_cpupri.h"
+#include "sched_autogroup.h"
#define CREATE_TRACE_POINTS
#include
@@ -346,19 +347,31 @@
/* return group to which a task belongs */
static inline struct task_group *task_group(struct task_struct *p)
{
- struct task_group *tg;
#ifdef CONFIG_USER_SCHED
+ struct task_group *tg;
+
rcu_read_lock();
tg = __task_cred(p)->user->tg;
rcu_read_unlock();
+
+ return tg;
#elif defined(CONFIG_CGROUP_SCHED)
- tg = container_of(task_subsys_state(p, cpu_cgroup_subsys_id),
- struct task_group, css);
+ struct task_group *tg;
+ struct cgroup_subsys_state *css;
+
+ css = task_subsys_state(p, cpu_cgroup_subsys_id);
+
+ tg = container_of(css, struct task_group, css);
+
+ return autogroup_task_group(p, tg);
#else
+ struct task_group *tg;
+
tg = &init_task_group;
-#endif
+
return tg;
+#endif
}
/* Change a task's cfs_rq and parent entity if it moves across CPUs/groups */
@@ -1826,6 +1839,7 @@
#include "sched_idletask.c"
#include "sched_fair.c"
#include "sched_rt.c"
+#include "sched_autogroup.c"
#ifdef CONFIG_SCHED_DEBUG
# include "sched_debug.c"
#endif
@@ -9558,6 +9572,8 @@
init_task_group.parent = &root_task_group;
list_add(&init_task_group.siblings, &root_task_group.children);
#endif /* CONFIG_USER_SCHED */
+
+ autogroup_init(&init_task);
#endif /* CONFIG_GROUP_SCHED */
#if defined CONFIG_FAIR_GROUP_SCHED && defined CONFIG_SMP
@@ -10097,15 +10113,11 @@
/* change task's runqueue when it moves between groups.
* The caller of this function should have put the task in its new group
* by now. This function just updates tsk->se.cfs_rq and tsk->se.parent to
- * reflect its new group.
+ * reflect its new group. Called with the runqueue lock held.
*/
-void sched_move_task(struct task_struct *tsk)
+void __sched_move_task(struct task_struct *tsk, struct rq *rq)
{
int on_rq, running;
- unsigned long flags;
- struct rq *rq;
-
- rq = task_rq_lock(tsk, &flags);
update_rq_clock(rq);
@@ -10128,6 +10140,15 @@
tsk->sched_class->set_curr_task(rq);
if (on_rq)
enqueue_task(rq, tsk, 0);
+}
+
+void sched_move_task(struct task_struct *tsk)
+{
+ struct rq *rq;
+ unsigned long flags;
+
+ rq = task_rq_lock(tsk, &flags);
+ __sched_move_task(tsk, rq);
task_rq_unlock(rq, &flags);
}
diff -urN linux-2.6.32/kernel/sysctl.c linux/kernel/sysctl.c
--- linux-2.6.32/kernel/sysctl.c 2010-10-31 16:13:19.000000000 +0530
+++ linux/kernel/sysctl.c 2010-11-18 10:03:11.533818737 +0530
@@ -379,6 +379,18 @@
.mode = 0644,
.proc_handler = &proc_dointvec,
},
+#ifdef CONFIG_SCHED_AUTOGROUP
+ {
+ .ctl_name = CTL_UNNUMBERED,
+ .procname = "sched_autogroup_enabled",
+ .data = &sysctl_sched_autogroup_enabled,
+ .maxlen = sizeof(unsigned int),
+ .mode = 0644,
+ .proc_handler = proc_dointvec,
+ .extra1 = &zero,
+ .extra2 = &one,
+ },
+#endif
#ifdef CONFIG_PROVE_LOCKING
{
.ctl_name = CTL_UNNUMBERED,
Hey,
ReplyDeletethank you very much, it works !
copy-paste of your patch had to be reworked though
(copy paste is copy paste, not a download)
http://rapidshare.com/files/431915262/patch-task-sched-autogroup-2.6.32.tar.bz2
Big Thanks! Hopefully your backport will make it into a distro!
ReplyDeleteAny possibility of backporting the per session (v4) patch?
ReplyDeleteI am not actively following lkml, pls provide where this patch is in latest kernel, I will try to backport it
ReplyDeleteI guess, I found it, http://marc.info/?l=linux-kernel&m=129028174609578&w=2
ReplyDeletehttps://lkml.org/lkml/2010/11/20/91
ReplyDeleteThank You!
I'm also interested in a backport of the per-session-v4 patch to 2.6.32!!
ReplyDeleteAny luck with backporting the v4 patch? It's understandable if its too involved, I couldn't get it either. Willing to send a few dollars someones way if they can get it.
ReplyDeleteit is a community effort and will do it without charge, got it free, give it free.
ReplyDeleteI did not look at it, was playing with python, image processing, rebuilding ubuntu using ubuntu customization kit .... will do this patch tomorrow or tonight
I tried to patch with the v4, but ended up in compilation errors, has to do the way sched_autogroup.c is modified, I guess, anyhow here is the unsuccessful patch effort
ReplyDeletehttps://docs.google.com/leaf?id=0B_nTbpzPbbNJODExM2E4ZWMtZTNhYi00NDY5LWFjMDMtNWJhZmVlMGE0MDQz&hl=en&authkey=CKGOovAM