lkml.org 
[lkml]   [2006]   [May]   [27]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
/
Date
From
SubjectRe: [RFC 3/5] sched: Add CPU rate hard caps
On 5/26/06, Peter Williams <pwil3058@bigpond.net.au> wrote:
> This patch implements hard CPU rate caps per task as a proportion of a
> single CPU's capacity expressed in parts per thousand.
>
> Signed-off-by: Peter Williams <pwil3058@bigpond.com.au>
> include/linux/sched.h | 8 ++
> kernel/Kconfig.caps | 14 +++-
> kernel/sched.c | 154 ++++++++++++++++++++++++++++++++++++++++++++++++--
> 3 files changed, 168 insertions(+), 8 deletions(-)
>
> Index: MM-2.6.17-rc4-mm3/include/linux/sched.h
> ===================================================================
> --- MM-2.6.17-rc4-mm3.orig/include/linux/sched.h 2006-05-26 10:46:35.000000000 +1000
> +++ MM-2.6.17-rc4-mm3/include/linux/sched.h 2006-05-26 11:00:07.000000000 +1000
> @@ -796,6 +796,10 @@ struct task_struct {
> #ifdef CONFIG_CPU_RATE_CAPS
> unsigned long long avg_cpu_per_cycle, avg_cycle_length;
> unsigned int cpu_rate_cap;
> +#ifdef CONFIG_CPU_RATE_HARD_CAPS
> + unsigned int cpu_rate_hard_cap;
> + struct timer_list sinbin_timer;

Using a timer for releasing tasks from their sinbin sounds like a bit
of an overhead. Given that there could be 10s of thousands of tasks.
Is it possible to use the scheduler_tick() function take a look at all
deactivated tasks (as efficiently as possible) and activate them when
its time to activate them or just fold the functionality by defining a
time quantum after which everyone is worken up. This time quantum
could be the same as the time over which limits are honoured.

> +#endif
> #endif
> enum sleep_type sleep_type;
>
> @@ -994,6 +998,10 @@ 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);
> +#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);
> +#endif
> #endif
>
> static inline pid_t process_group(struct task_struct *tsk)
> Index: MM-2.6.17-rc4-mm3/kernel/Kconfig.caps
> ===================================================================
> --- MM-2.6.17-rc4-mm3.orig/kernel/Kconfig.caps 2006-05-26 10:45:26.000000000 +1000
> +++ MM-2.6.17-rc4-mm3/kernel/Kconfig.caps 2006-05-26 11:00:07.000000000 +1000
> @@ -3,11 +3,21 @@
> #
>
> config CPU_RATE_CAPS
> - bool "Support (soft) CPU rate caps"
> + bool "Support CPU rate caps"
> default n
> ---help---
> - Say y here if you wish to be able to put a (soft) upper limit on
> + Say y here if you wish to be able to put a soft upper limit on
> the rate of CPU usage by individual tasks. A task which has been
> allocated a soft CPU rate cap will be limited to that rate of CPU
> usage unless there is spare CPU resources available after the needs
> of uncapped tasks are met.
> +
> +config CPU_RATE_HARD_CAPS
> + bool "Support CPU rate hard caps"
> + depends on CPU_RATE_CAPS
> + default n
> + ---help---
> + Say y here if you wish to be able to put a hard upper limit on
> + the rate of CPU usage by individual tasks. A task which has been
> + allocated a hard CPU rate cap will be limited to that rate of CPU
> + usage regardless of whether there is spare CPU resources available.
> Index: MM-2.6.17-rc4-mm3/kernel/sched.c
> ===================================================================
> --- MM-2.6.17-rc4-mm3.orig/kernel/sched.c 2006-05-26 11:00:02.000000000 +1000
> +++ MM-2.6.17-rc4-mm3/kernel/sched.c 2006-05-26 13:50:11.000000000 +1000
> @@ -201,21 +201,33 @@ static inline unsigned int task_timeslic
>
> #ifdef CONFIG_CPU_RATE_CAPS
> #define CAP_STATS_OFFSET 8
> +#ifdef CONFIG_CPU_RATE_HARD_CAPS
> +static void sinbin_release_fn(unsigned long arg);
> +#define min_cpu_rate_cap(p) min((p)->cpu_rate_cap, (p)->cpu_rate_hard_cap)
> +#else
> +#define min_cpu_rate_cap(p) (p)->cpu_rate_cap
> +#endif
> #define task_has_cap(p) unlikely((p)->flags & PF_HAS_CAP)
> /* this assumes that p is not a real time task */
> #define task_is_background(p) unlikely((p)->cpu_rate_cap == 0)
> #define task_being_capped(p) unlikely((p)->prio >= CAPPED_PRIO)
> -#define cap_load_weight(p) (((p)->cpu_rate_cap * SCHED_LOAD_SCALE) / 1000)
> +#define cap_load_weight(p) ((min_cpu_rate_cap(p) * SCHED_LOAD_SCALE) / 1000)
>
> static void init_cpu_rate_caps(task_t *p)
> {
> p->cpu_rate_cap = 1000;
> p->flags &= ~PF_HAS_CAP;
> +#ifdef CONFIG_CPU_RATE_HARD_CAPS
> + p->cpu_rate_hard_cap = 1000;
> + init_timer(&p->sinbin_timer);
> + p->sinbin_timer.function = sinbin_release_fn;
> + p->sinbin_timer.data = (unsigned long) p;
> +#endif
> }
>
> static inline void set_cap_flag(task_t *p)
> {
> - if (p->cpu_rate_cap < 1000 && !has_rt_policy(p))
> + if (min_cpu_rate_cap(p) < 1000 && !has_rt_policy(p))
> p->flags |= PF_HAS_CAP;
> else
> p->flags &= ~PF_HAS_CAP;
> @@ -223,7 +235,7 @@ static inline void set_cap_flag(task_t *
>
> static inline int task_exceeding_cap(const task_t *p)
> {
> - return (p->avg_cpu_per_cycle * 1000) > (p->avg_cycle_length * p->cpu_rate_cap);
> + return (p->avg_cpu_per_cycle * 1000) > (p->avg_cycle_length * min_cpu_rate_cap(p));
> }
>
> #ifdef CONFIG_SCHED_SMT
> @@ -257,7 +269,7 @@ static int task_exceeding_cap_now(const
>
> delta = (now > p->timestamp) ? (now - p->timestamp) : 0;
> lhs = (p->avg_cpu_per_cycle + delta) * 1000;
> - rhs = (p->avg_cycle_length + delta) * p->cpu_rate_cap;
> + rhs = (p->avg_cycle_length + delta) * min_cpu_rate_cap(p);
>
> return lhs > rhs;
> }
> @@ -266,6 +278,10 @@ static inline void init_cap_stats(task_t
> {
> p->avg_cpu_per_cycle = 0;
> p->avg_cycle_length = 0;
> +#ifdef CONFIG_CPU_RATE_HARD_CAPS
> + init_timer(&p->sinbin_timer);
> + p->sinbin_timer.data = (unsigned long) p;
> +#endif
> }
>
> static inline void inc_cap_stats_cycle(task_t *p, unsigned long long now)
> @@ -1213,6 +1229,64 @@ static void deactivate_task(struct task_
> p->array = NULL;
> }
>
> +#ifdef CONFIG_CPU_RATE_HARD_CAPS
> +#define task_has_hard_cap(p) unlikely((p)->cpu_rate_hard_cap < 1000)
> +
> +/*
> + * Release a task from the sinbin
> + */
> +static void sinbin_release_fn(unsigned long arg)
> +{
> + unsigned long flags;
> + struct task_struct *p = (struct task_struct*)arg;
> + struct runqueue *rq = task_rq_lock(p, &flags);
> +
> + p->prio = effective_prio(p);
> +
> + __activate_task(p, rq);
> +
> + task_rq_unlock(rq, &flags);
> +}
> +
> +static unsigned long reqd_sinbin_ticks(const task_t *p)
> +{
> + unsigned long long res;
> +
> + res = p->avg_cpu_per_cycle * 1000;
> +
> + if (res > p->avg_cycle_length * p->cpu_rate_hard_cap) {
> + (void)do_div(res, p->cpu_rate_hard_cap);
> + res -= p->avg_cpu_per_cycle;
> + /*
> + * IF it was available we'd also subtract
> + * the average sleep per cycle here
> + */
> + res >>= CAP_STATS_OFFSET;
> + (void)do_div(res, (1000000000 / HZ));

Please use NSEC_PER_SEC if that is what 10^9 stands for in the above
calculation.

> +
> + return res ? : 1;
> + }
> +
> + return 0;
> +}
> +
> +static void sinbin_task(task_t *p, unsigned long durn)
> +{
> + if (durn == 0)
> + return;
> + deactivate_task(p, task_rq(p));
> + p->sinbin_timer.expires = jiffies + durn;
> + add_timer(&p->sinbin_timer);
> +}
> +#else
> +#define task_has_hard_cap(p) 0
> +#define reqd_sinbin_ticks(p) 0
> +
> +static inline void sinbin_task(task_t *p, unsigned long durn)
> +{
> +}
> +#endif
> +
> /*
> * resched_task - mark a task 'to be rescheduled now'.
> *
> @@ -3508,9 +3582,16 @@ need_resched_nonpreemptible:
> }
> }
>
> - /* do this now so that stats are correct for SMT code */
> - if (task_has_cap(prev))
> + if (task_has_cap(prev)) {
> inc_cap_stats_both(prev, now);
> + if (task_has_hard_cap(prev) && !prev->state &&
> + !rt_task(prev) && !signal_pending(prev)) {
> + unsigned long sinbin_ticks = reqd_sinbin_ticks(prev);
> +
> + if (sinbin_ticks)
> + sinbin_task(prev, sinbin_ticks);
> + }
> + }
>
> cpu = smp_processor_id();
> if (unlikely(!rq->nr_running)) {
> @@ -4539,6 +4620,67 @@ out:
> }
>
<snip>

Balbir
Linux Technology Center
IBM Software Labs
-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/

\
 
 \ /
  Last update: 2006-05-27 08:51    [from the cache]
©2003-2011 Jasper Spaans