]> Gitweb @ Texas Instruments - Open Source Git Repositories - git.TI.com/gitweb - glsdk/meta-ti-glsdk.git/blob - recipes-bsp/linux/linux-omap-2.6.37rc/0008-Miracle-patch.patch
BSP: rename beagleboard to TI
[glsdk/meta-ti-glsdk.git] / recipes-bsp / linux / linux-omap-2.6.37rc / 0008-Miracle-patch.patch
1 From 31949867bace7945acd3ec10c822e6988613aed7 Mon Sep 17 00:00:00 2001
2 From: Mike Galbraith <efault@gmx.de>
3 Date: Fri, 19 Nov 2010 12:52:42 +0100
4 Subject: [PATCH 08/29] Miracle patch
5 MIME-Version: 1.0
6 Content-Type: text/plain; charset=UTF-8
7 Content-Transfer-Encoding: 8bit
9 On Sun, 2010-11-14 at 16:26 -0800, Linus Torvalds wrote:
10 > On Sun, Nov 14, 2010 at 4:15 PM, Linus Torvalds
11 > <torvalds@linux-foundation.org> wrote:
12 > >
13 > > THAT is why I think it's so silly to try to be so strict and walk over
14 > > all processes while holding a couple of spinlocks.
15 >
16 > Btw, let me say that I think the patch is great even with that thing
17 > in. It looks clean, the thing I'm complaining about is not a big deal,
18 > and it seems to perform very much as advertized. The difference with
19 > autogroup scheduling is very noticeable with a simple "make -j64"
20 > kernel compile.
21 >
22 > So I really don't think it's a big deal. The sysctl handler isn't even
23 > complicated. But boy does it hurt my eyes to see a spinlock held
24 > around a "do_each_thread()". And I do get the feeling that the
25 > simplest way to fix it would be to just remove the code entirely, and
26 > just say that "enabling/disabling may be delayed for old processes
27 > with existing autogroups".
29 Which is what I just did. If the oddball case isn't a big deal, the
30 patch shrinks, which is a good thing. I just wanted to cover all bases.
32 Patchlet with handler whacked:
34 A recurring complaint from CFS users is that parallel kbuild has a negative
35 impact on desktop interactivity.  This patch implements an idea from Linus,
36 to automatically create task groups.  This patch only implements Linus' per
37 tty task group suggestion, and only for fair class tasks, but leaves the way
38 open for enhancement.
40 Implementation: each task's signal struct contains an inherited pointer to a
41 refcounted autogroup struct containing a task group pointer, the default for
42 all tasks pointing to the init_task_group.  When a task calls __proc_set_tty(),
43 the process wide reference to the default group is dropped, a new task group is
44 created, and the process is moved into the new task group.  Children thereafter
45 inherit this task group, and increase it's refcount.  On exit, a reference to the
46 current task group is dropped when the last reference to each signal struct is
47 dropped.  The task group is destroyed when the last signal struct referencing
48 it is freed.   At runqueue selection time, IFF a task has no cgroup assignment,
49 it's current autogroup is used.
51 The feature is enabled from boot by default if CONFIG_SCHED_AUTOGROUP is
52 selected, but can be disabled via the boot option noautogroup, and can be
53 also be turned on/off on the fly via..
54    echo [01] > /proc/sys/kernel/sched_autogroup_enabled.
55 ..which will automatically move tasks to/from the root task group.
57 Some numbers.
59 A 100% hog overhead measurement proggy pinned to the same CPU as a make -j10
61 About measurement proggy:
62   pert/sec = perturbations/sec
63   min/max/avg = scheduler service latencies in usecs
64   sum/s = time accrued by the competition per sample period (1 sec here)
65   overhead = %CPU received by the competition per sample period
67 pert/s:       31 >40475.37us:        3 min:  0.37 max:48103.60 avg:29573.74 sum/s:916786us overhead:90.24%
68 pert/s:       23 >41237.70us:       12 min:  0.36 max:56010.39 avg:40187.01 sum/s:924301us overhead:91.99%
69 pert/s:       24 >42150.22us:       12 min:  8.86 max:61265.91 avg:39459.91 sum/s:947038us overhead:92.20%
70 pert/s:       26 >42344.91us:       11 min:  3.83 max:52029.60 avg:36164.70 sum/s:940282us overhead:91.12%
71 pert/s:       24 >44262.90us:       14 min:  5.05 max:82735.15 avg:40314.33 sum/s:967544us overhead:92.22%
73 Same load with this patch applied.
75 pert/s:      229 >5484.43us:       41 min:  0.15 max:12069.42 avg:2193.81 sum/s:502382us overhead:50.24%
76 pert/s:      222 >5652.28us:       43 min:  0.46 max:12077.31 avg:2248.56 sum/s:499181us overhead:49.92%
77 pert/s:      211 >5809.38us:       43 min:  0.16 max:12064.78 avg:2381.70 sum/s:502538us overhead:50.25%
78 pert/s:      223 >6147.92us:       43 min:  0.15 max:16107.46 avg:2282.17 sum/s:508925us overhead:50.49%
79 pert/s:      218 >6252.64us:       43 min:  0.16 max:12066.13 avg:2324.11 sum/s:506656us overhead:50.27%
81 Average service latency is an order of magnitude better with autogroup.
82 (Imagine that pert were Xorg or whatnot instead)
84 Using Mathieu Desnoyers' wakeup-latency testcase:
86 With taskset -c 3 make -j 10 running..
88 taskset -c 3 ./wakeup-latency& sleep 30;killall wakeup-latency
90 without:
91 maximum latency: 42963.2 µs
92 average latency: 9077.0 µs
93 missed timer events: 0
95 with:
96 maximum latency: 4160.7 µs
97 average latency: 149.4 µs
98 missed timer events: 0
100 Signed-off-by: Mike Galbraith <efault@gmx.de>
101 ---
102  Documentation/kernel-parameters.txt |    2 +
103  drivers/tty/tty_io.c                |    1 +
104  include/linux/sched.h               |   19 +++++
105  init/Kconfig                        |   12 +++
106  kernel/fork.c                       |    5 +-
107  kernel/sched.c                      |   25 ++++--
108  kernel/sched_autogroup.c            |  140 +++++++++++++++++++++++++++++++++++
109  kernel/sched_autogroup.h            |   18 +++++
110  kernel/sysctl.c                     |   11 +++
111  9 files changed, 224 insertions(+), 9 deletions(-)
112  create mode 100644 kernel/sched_autogroup.c
113  create mode 100644 kernel/sched_autogroup.h
115 diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt
116 index 8b61c93..9408728 100644
117 --- a/Documentation/kernel-parameters.txt
118 +++ b/Documentation/kernel-parameters.txt
119 @@ -1622,6 +1622,8 @@ and is between 256 and 4096 characters. It is defined in the file
120         noapic          [SMP,APIC] Tells the kernel to not make use of any
121                         IOAPICs that may be present in the system.
122  
123 +       noautogroup     Disable scheduler automatic task group creation.
125         nobats          [PPC] Do not use BATs for mapping kernel lowmem
126                         on "Classic" PPC cores.
127  
128 diff --git a/drivers/tty/tty_io.c b/drivers/tty/tty_io.c
129 index 35480dd..1849f4a 100644
130 --- a/drivers/tty/tty_io.c
131 +++ b/drivers/tty/tty_io.c
132 @@ -3169,6 +3169,7 @@ static void __proc_set_tty(struct task_struct *tsk, struct tty_struct *tty)
133         put_pid(tsk->signal->tty_old_pgrp);
134         tsk->signal->tty = tty_kref_get(tty);
135         tsk->signal->tty_old_pgrp = NULL;
136 +       sched_autogroup_create_attach(tsk);
137  }
138  
139  static void proc_set_tty(struct task_struct *tsk, struct tty_struct *tty)
140 diff --git a/include/linux/sched.h b/include/linux/sched.h
141 index 2238745..3a775e3 100644
142 --- a/include/linux/sched.h
143 +++ b/include/linux/sched.h
144 @@ -509,6 +509,8 @@ struct thread_group_cputimer {
145         spinlock_t lock;
146  };
147  
148 +struct autogroup;
150  /*
151   * NOTE! "signal_struct" does not have it's own
152   * locking, because a shared signal_struct always
153 @@ -576,6 +578,9 @@ struct signal_struct {
154  
155         struct tty_struct *tty; /* NULL if no tty */
156  
157 +#ifdef CONFIG_SCHED_AUTOGROUP
158 +       struct autogroup *autogroup;
159 +#endif
160         /*
161          * Cumulative resource counters for dead threads in the group,
162          * and for reaped dead child processes forked by this group.
163 @@ -1931,6 +1936,20 @@ int sched_rt_handler(struct ctl_table *table, int write,
164  
165  extern unsigned int sysctl_sched_compat_yield;
166  
167 +#ifdef CONFIG_SCHED_AUTOGROUP
168 +extern unsigned int sysctl_sched_autogroup_enabled;
170 +extern void sched_autogroup_create_attach(struct task_struct *p);
171 +extern void sched_autogroup_detach(struct task_struct *p);
172 +extern void sched_autogroup_fork(struct signal_struct *sig);
173 +extern void sched_autogroup_exit(struct signal_struct *sig);
174 +#else
175 +static inline void sched_autogroup_create_attach(struct task_struct *p) { }
176 +static inline void sched_autogroup_detach(struct task_struct *p) { }
177 +static inline void sched_autogroup_fork(struct signal_struct *sig) { }
178 +static inline void sched_autogroup_exit(struct signal_struct *sig) { }
179 +#endif
181  #ifdef CONFIG_RT_MUTEXES
182  extern int rt_mutex_getprio(struct task_struct *p);
183  extern void rt_mutex_setprio(struct task_struct *p, int prio);
184 diff --git a/init/Kconfig b/init/Kconfig
185 index c972899..a4985d9 100644
186 --- a/init/Kconfig
187 +++ b/init/Kconfig
188 @@ -741,6 +741,18 @@ config NET_NS
189  
190  endif # NAMESPACES
191  
192 +config SCHED_AUTOGROUP
193 +       bool "Automatic process group scheduling"
194 +       select CGROUPS
195 +       select CGROUP_SCHED
196 +       select FAIR_GROUP_SCHED
197 +       help
198 +         This option optimizes the scheduler for common desktop workloads by
199 +         automatically creating and populating task groups.  This separation
200 +         of workloads isolates aggressive CPU burners (like build jobs) from
201 +         desktop applications.  Task group autogeneration is currently based
202 +         upon task tty association.
204  config MM_OWNER
205         bool
206  
207 diff --git a/kernel/fork.c b/kernel/fork.c
208 index 5447dc7..70ea75f 100644
209 --- a/kernel/fork.c
210 +++ b/kernel/fork.c
211 @@ -174,8 +174,10 @@ static inline void free_signal_struct(struct signal_struct *sig)
212  
213  static inline void put_signal_struct(struct signal_struct *sig)
214  {
215 -       if (atomic_dec_and_test(&sig->sigcnt))
216 +       if (atomic_dec_and_test(&sig->sigcnt)) {
217 +               sched_autogroup_exit(sig);
218                 free_signal_struct(sig);
219 +       }
220  }
221  
222  void __put_task_struct(struct task_struct *tsk)
223 @@ -905,6 +907,7 @@ static int copy_signal(unsigned long clone_flags, struct task_struct *tsk)
224         posix_cpu_timers_init_group(sig);
225  
226         tty_audit_fork(sig);
227 +       sched_autogroup_fork(sig);
228  
229         sig->oom_adj = current->signal->oom_adj;
230         sig->oom_score_adj = current->signal->oom_score_adj;
231 diff --git a/kernel/sched.c b/kernel/sched.c
232 index 297d1a0..53ff9a1 100644
233 --- a/kernel/sched.c
234 +++ b/kernel/sched.c
235 @@ -78,6 +78,7 @@
236  
237  #include "sched_cpupri.h"
238  #include "workqueue_sched.h"
239 +#include "sched_autogroup.h"
240  
241  #define CREATE_TRACE_POINTS
242  #include <trace/events/sched.h>
243 @@ -605,11 +606,14 @@ static inline int cpu_of(struct rq *rq)
244   */
245  static inline struct task_group *task_group(struct task_struct *p)
246  {
247 +       struct task_group *tg;
248         struct cgroup_subsys_state *css;
249  
250         css = task_subsys_state_check(p, cpu_cgroup_subsys_id,
251                         lockdep_is_held(&task_rq(p)->lock));
252 -       return container_of(css, struct task_group, css);
253 +       tg = container_of(css, struct task_group, css);
255 +       return autogroup_task_group(p, tg);
256  }
257  
258  /* Change a task's cfs_rq and parent entity if it moves across CPUs/groups */
259 @@ -2063,6 +2067,7 @@ static void update_rq_clock_task(struct rq *rq, s64 delta)
260  #include "sched_idletask.c"
261  #include "sched_fair.c"
262  #include "sched_rt.c"
263 +#include "sched_autogroup.c"
264  #include "sched_stoptask.c"
265  #ifdef CONFIG_SCHED_DEBUG
266  # include "sched_debug.c"
267 @@ -8164,7 +8169,7 @@ void __init sched_init(void)
268  #ifdef CONFIG_CGROUP_SCHED
269         list_add(&init_task_group.list, &task_groups);
270         INIT_LIST_HEAD(&init_task_group.children);
272 +       autogroup_init(&init_task);
273  #endif /* CONFIG_CGROUP_SCHED */
274  
275  #if defined CONFIG_FAIR_GROUP_SCHED && defined CONFIG_SMP
276 @@ -8694,15 +8699,11 @@ void sched_destroy_group(struct task_group *tg)
277  /* change task's runqueue when it moves between groups.
278   *     The caller of this function should have put the task in its new group
279   *     by now. This function just updates tsk->se.cfs_rq and tsk->se.parent to
280 - *     reflect its new group.
281 + *     reflect its new group.  Called with the runqueue lock held.
282   */
283 -void sched_move_task(struct task_struct *tsk)
284 +void __sched_move_task(struct task_struct *tsk, struct rq *rq)
285  {
286         int on_rq, running;
287 -       unsigned long flags;
288 -       struct rq *rq;
290 -       rq = task_rq_lock(tsk, &flags);
291  
292         running = task_current(rq, tsk);
293         on_rq = tsk->se.on_rq;
294 @@ -8723,7 +8724,15 @@ void sched_move_task(struct task_struct *tsk)
295                 tsk->sched_class->set_curr_task(rq);
296         if (on_rq)
297                 enqueue_task(rq, tsk, 0);
298 +}
299  
300 +void sched_move_task(struct task_struct *tsk)
301 +{
302 +       struct rq *rq;
303 +       unsigned long flags;
305 +       rq = task_rq_lock(tsk, &flags);
306 +       __sched_move_task(tsk, rq);
307         task_rq_unlock(rq, &flags);
308  }
309  #endif /* CONFIG_CGROUP_SCHED */
310 diff --git a/kernel/sched_autogroup.c b/kernel/sched_autogroup.c
311 new file mode 100644
312 index 0000000..62f1d0e
313 --- /dev/null
314 +++ b/kernel/sched_autogroup.c
315 @@ -0,0 +1,140 @@
316 +#ifdef CONFIG_SCHED_AUTOGROUP
318 +unsigned int __read_mostly sysctl_sched_autogroup_enabled = 1;
320 +struct autogroup {
321 +       struct kref             kref;
322 +       struct task_group       *tg;
323 +};
325 +static struct autogroup autogroup_default;
327 +static void autogroup_init(struct task_struct *init_task)
328 +{
329 +       autogroup_default.tg = &init_task_group;
330 +       kref_init(&autogroup_default.kref);
331 +       init_task->signal->autogroup = &autogroup_default;
332 +}
334 +static inline void autogroup_destroy(struct kref *kref)
335 +{
336 +       struct autogroup *ag = container_of(kref, struct autogroup, kref);
337 +       struct task_group *tg = ag->tg;
339 +       kfree(ag);
340 +       sched_destroy_group(tg);
341 +}
343 +static inline void autogroup_kref_put(struct autogroup *ag)
344 +{
345 +       kref_put(&ag->kref, autogroup_destroy);
346 +}
348 +static inline struct autogroup *autogroup_kref_get(struct autogroup *ag)
349 +{
350 +       kref_get(&ag->kref);
351 +       return ag;
352 +}
354 +static inline struct autogroup *autogroup_create(void)
355 +{
356 +       struct autogroup *ag = kmalloc(sizeof(*ag), GFP_KERNEL);
358 +       if (!ag)
359 +               goto out_fail;
361 +       ag->tg = sched_create_group(&init_task_group);
362 +       kref_init(&ag->kref);
364 +       if (!(IS_ERR(ag->tg)))
365 +               return ag;
367 +out_fail:
368 +       if (ag) {
369 +               kfree(ag);
370 +               WARN_ON(1);
371 +       } else
372 +               WARN_ON(1);
374 +       return autogroup_kref_get(&autogroup_default);
375 +}
377 +static inline struct task_group *
378 +autogroup_task_group(struct task_struct *p, struct task_group *tg)
379 +{
380 +       int enabled = ACCESS_ONCE(sysctl_sched_autogroup_enabled);
382 +       enabled &= (tg == &root_task_group);
383 +       enabled &= (p->sched_class == &fair_sched_class);
384 +       enabled &= (!(p->flags & PF_EXITING));
386 +       if (enabled)
387 +               return p->signal->autogroup->tg;
389 +       return tg;
390 +}
392 +static void
393 +autogroup_move_group(struct task_struct *p, struct autogroup *ag)
394 +{
395 +       struct autogroup *prev;
396 +       struct task_struct *t;
397 +       struct rq *rq;
398 +       unsigned long flags;
400 +       rq = task_rq_lock(p, &flags);
401 +       prev = p->signal->autogroup;
402 +       if (prev == ag) {
403 +               task_rq_unlock(rq, &flags);
404 +               return;
405 +       }
407 +       p->signal->autogroup = autogroup_kref_get(ag);
408 +       __sched_move_task(p, rq);
409 +       task_rq_unlock(rq, &flags);
411 +       rcu_read_lock();
412 +       list_for_each_entry_rcu(t, &p->thread_group, thread_group) {
413 +               sched_move_task(t);
414 +       }
415 +       rcu_read_unlock();
417 +       autogroup_kref_put(prev);
418 +}
420 +void sched_autogroup_create_attach(struct task_struct *p)
421 +{
422 +       struct autogroup *ag = autogroup_create();
424 +       autogroup_move_group(p, ag);
425 +       /* drop extra refrence added by autogroup_create() */
426 +       autogroup_kref_put(ag);
427 +}
428 +EXPORT_SYMBOL(sched_autogroup_create_attach);
430 +/* currently has no users */
431 +void sched_autogroup_detach(struct task_struct *p)
432 +{
433 +       autogroup_move_group(p, &autogroup_default);
434 +}
435 +EXPORT_SYMBOL(sched_autogroup_detach);
437 +void sched_autogroup_fork(struct signal_struct *sig)
438 +{
439 +       sig->autogroup = autogroup_kref_get(current->signal->autogroup);
440 +}
442 +void sched_autogroup_exit(struct signal_struct *sig)
443 +{
444 +       autogroup_kref_put(sig->autogroup);
445 +}
447 +static int __init setup_autogroup(char *str)
448 +{
449 +       sysctl_sched_autogroup_enabled = 0;
451 +       return 1;
452 +}
454 +__setup("noautogroup", setup_autogroup);
455 +#endif
456 diff --git a/kernel/sched_autogroup.h b/kernel/sched_autogroup.h
457 new file mode 100644
458 index 0000000..6048f5d
459 --- /dev/null
460 +++ b/kernel/sched_autogroup.h
461 @@ -0,0 +1,18 @@
462 +#ifdef CONFIG_SCHED_AUTOGROUP
464 +static void __sched_move_task(struct task_struct *tsk, struct rq *rq);
466 +static inline struct task_group *
467 +autogroup_task_group(struct task_struct *p, struct task_group *tg);
469 +#else /* !CONFIG_SCHED_AUTOGROUP */
471 +static inline void autogroup_init(struct task_struct *init_task) {  }
473 +static inline struct task_group *
474 +autogroup_task_group(struct task_struct *p, struct task_group *tg)
475 +{
476 +       return tg;
477 +}
479 +#endif /* CONFIG_SCHED_AUTOGROUP */
480 diff --git a/kernel/sysctl.c b/kernel/sysctl.c
481 index 5abfa15..b162f65 100644
482 --- a/kernel/sysctl.c
483 +++ b/kernel/sysctl.c
484 @@ -382,6 +382,17 @@ static struct ctl_table kern_table[] = {
485                 .mode           = 0644,
486                 .proc_handler   = proc_dointvec,
487         },
488 +#ifdef CONFIG_SCHED_AUTOGROUP
489 +       {
490 +               .procname       = "sched_autogroup_enabled",
491 +               .data           = &sysctl_sched_autogroup_enabled,
492 +               .maxlen         = sizeof(unsigned int),
493 +               .mode           = 0644,
494 +               .proc_handler   = proc_dointvec,
495 +               .extra1         = &zero,
496 +               .extra2         = &one,
497 +       },
498 +#endif
499  #ifdef CONFIG_PROVE_LOCKING
500         {
501                 .procname       = "prove_locking",
502 -- 
503 1.6.6.1