Re: [PATCH 0/4] sched: Add CPU rate caps

From: Peter Williams
Date: Mon Jun 19 2006 - 01:03:37 EST


Peter Williams wrote:
Andrew Morton wrote:
On Sun, 18 Jun 2006 18:26:38 +1000
Peter Williams <pwil3058@xxxxxxxxxxxxxx> wrote:
5. Code size measurements:

Vanilla kernel:

text data bss dec hex filename
33800 4689 296 38785 9781 sched.o
2554 79 0 2633 a49 mutex.o
12076 2632 0 14708 3974 base.o

Patches applied:

text data bss dec hex filename
36870 4721 296 41887 a39f sched.o
2630 79 0 2709 a95 mutex.o
13011 2920 0 15931 3e3b base.o

Indicating that the size cost of the patch proper is about
3 kilobytes and the procfs costs about another 1.2 kilobytes.


hm. That seems rather a lot. I guess it's not a simple thing to do.

I suspect that a large part of that is the functions that set the caps (i.e. the equivalents of set_user_nice()) one for soft and one for hard caps. The actual capping mechanisms are quite simple.

This contribution may not be as large as I thought. Realizing that the
function to set soft caps and the function to set hard caps duplicate a
lot of code I've modified them to share code rather than duplicate.
I've also made the functions for getting caps inline and they should
just be optimized away to a field reference. But the reduction in code
size is only about 285 bytes.

Before:
text data bss dec hex filename
32820 4913 672 38405 9605 kernel/sched.o

After:
text data bss dec hex filename
32535 4913 672 38120 94e8 kernel/sched.o

Noting that these values were less than those in the original mail, I've
also checked the size for when the patches are excluded.

text data bss dec hex filename
30061 4881 672 35614 8b1e kernel/sched.o

The numbers in the e-mail were from a different computer with gcc-4.0.2
installed while these are generated with gcc-4.1.1 (also that build
would not have had CONFIG_SCHED_SMT or CONFIG_SCHED_MC set). But the
end result is that the cost is still of the order of 2.5 kilobytes.

A patch to make these changes is attached.

Signed-off-by: Peter Williams <pwil3058@xxxxxxxxxxxxxx>

Peter
--
Peter Williams pwil3058@xxxxxxxxxxxxxx

"Learning, n. The kind of ignorance distinguishing the studious."
-- Ambrose Bierce

---
include/linux/sched.h | 24 +++++++++++--
kernel/sched.c | 90 ++++++++++----------------------------------------
2 files changed, 38 insertions(+), 76 deletions(-)

Index: MM-2.6.17-rc6-mm2/include/linux/sched.h
===================================================================
--- MM-2.6.17-rc6-mm2.orig/include/linux/sched.h 2006-06-19 13:57:18.000000000 +1000
+++ MM-2.6.17-rc6-mm2/include/linux/sched.h 2006-06-19 14:28:25.000000000 +1000
@@ -1022,11 +1022,27 @@ struct task_struct {
};

#ifdef CONFIG_CPU_RATE_CAPS
-unsigned int get_cpu_rate_cap(const struct task_struct *);
-int set_cpu_rate_cap(struct task_struct *, unsigned int);
+int set_cpu_rate_cap_low(struct task_struct *, unsigned int, int);
+
+static inline unsigned int get_cpu_rate_cap(const struct task_struct *p)
+{
+ return p->cpu_rate_cap;
+}
+
+static inline int set_cpu_rate_cap(struct task_struct *p, unsigned int newcap)
+{
+ return set_cpu_rate_cap_low(p, newcap, 0);
+}
#ifdef CONFIG_CPU_RATE_HARD_CAPS
-unsigned int get_cpu_rate_hard_cap(const struct task_struct *);
-int set_cpu_rate_hard_cap(struct task_struct *, unsigned int);
+static inline unsigned int get_cpu_rate_hard_cap(const struct task_struct *p)
+{
+ return p->cpu_rate_hard_cap;
+}
+
+static inline int set_cpu_rate_hard_cap(struct task_struct *p, unsigned int newcap)
+{
+ return set_cpu_rate_cap_low(p, newcap, 1);
+}
#endif
#endif

Index: MM-2.6.17-rc6-mm2/kernel/sched.c
===================================================================
--- MM-2.6.17-rc6-mm2.orig/kernel/sched.c 2006-06-19 13:57:18.000000000 +1000
+++ MM-2.6.17-rc6-mm2/kernel/sched.c 2006-06-19 14:28:25.000000000 +1000
@@ -4614,17 +4614,11 @@ out_unlock:
}

#ifdef CONFIG_CPU_RATE_CAPS
-unsigned int get_cpu_rate_cap(const struct task_struct *p)
-{
- return p->cpu_rate_cap;
-}
-
-EXPORT_SYMBOL(get_cpu_rate_cap);
-
/*
- * Require: 0 <= new_cap <= CPU_CAP_ONE
+ * Require: 0 <= new_cap <= CPU_CAP_ONE for hard == 0
+ * 1 <= new_cap <= CPU_CAP_ONE otherwise
*/
-int set_cpu_rate_cap(struct task_struct *p, unsigned int new_cap)
+int set_cpu_rate_cap_low(struct task_struct *p, unsigned int new_cap, int hard)
{
int is_allowed;
unsigned long flags;
@@ -4634,13 +4628,21 @@ int set_cpu_rate_cap(struct task_struct

if (new_cap > CPU_CAP_ONE)
return -EINVAL;
+#ifdef CONFIG_CPU_RATE_HARD_CAPS
+ if (hard && new_cap < 1)
+ return -EINVAL;
+#endif
is_allowed = capable(CAP_SYS_NICE);
/*
* We have to be careful, if called from /proc code,
* the task might be in the middle of scheduling on another CPU.
*/
rq = task_rq_lock(p, &flags);
+#ifdef CONFIG_CPU_RATE_HARD_CAPS
+ delta = new_cap - (hard ? p->cpu_rate_hard_cap : p->cpu_rate_cap);
+#else
delta = new_cap - p->cpu_rate_cap;
+#endif
if (!is_allowed) {
/*
* Ordinary users can set/change caps on their own tasks
@@ -4656,7 +4658,12 @@ int set_cpu_rate_cap(struct task_struct
* set - but as expected it wont have any effect on scheduling until
* the task becomes SCHED_NORMAL/SCHED_BATCH:
*/
- p->cpu_rate_cap = new_cap;
+#ifdef CONFIG_CPU_RATE_HARD_CAPS
+ if (hard)
+ p->cpu_rate_hard_cap = new_cap;
+ else
+#endif
+ p->cpu_rate_cap = new_cap;

if (has_rt_policy(p))
goto out;
@@ -4680,68 +4687,7 @@ out:
return 0;
}

-EXPORT_SYMBOL(set_cpu_rate_cap);
-
-#ifdef CONFIG_CPU_RATE_HARD_CAPS
-unsigned int get_cpu_rate_hard_cap(const struct task_struct *p)
-{
- return p->cpu_rate_hard_cap;
-}
-
-EXPORT_SYMBOL(get_cpu_rate_hard_cap);
-
-/*
- * Require: 1 <= new_cap <= CPU_CAP_ONE
- */
-int set_cpu_rate_hard_cap(struct task_struct *p, unsigned int new_cap)
-{
- int is_allowed;
- unsigned long flags;
- struct runqueue *rq;
- int delta;
-
- if (new_cap > CPU_CAP_ONE || new_cap < 1)
- return -EINVAL;
- is_allowed = capable(CAP_SYS_NICE);
- /*
- * We have to be careful, if called from /proc code,
- * the task might be in the middle of scheduling on another CPU.
- */
- rq = task_rq_lock(p, &flags);
- delta = new_cap - p->cpu_rate_hard_cap;
- if (!is_allowed) {
- /*
- * Ordinary users can set/change caps on their own tasks
- * provided that the new setting is MORE constraining
- */
- if (((current->euid != p->uid) && (current->uid != p->uid)) || (delta > 0)) {
- task_rq_unlock(rq, &flags);
- return -EPERM;
- }
- }
- /*
- * The RT tasks don't have caps, but we still allow the caps to be
- * set - but as expected it wont have any effect on scheduling until
- * the task becomes SCHED_NORMAL/SCHED_BATCH:
- */
- p->cpu_rate_hard_cap = new_cap;
-
- if (has_rt_policy(p))
- goto out;
-
- if (p->array)
- dec_raw_weighted_load(rq, p);
- set_load_weight(p);
- if (p->array)
- inc_raw_weighted_load(rq, p);
-out:
- task_rq_unlock(rq, &flags);
-
- return 0;
-}
-
-EXPORT_SYMBOL(set_cpu_rate_hard_cap);
-#endif
+EXPORT_SYMBOL(set_cpu_rate_cap_low);
#endif

long sched_setaffinity(pid_t pid, cpumask_t new_mask)