lkml.org 
[lkml]   [2008]   [Oct]   [5]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
/
Date
From
SubjectRe: [PATCH -mm 2/6] introduce struct res_counter_ratelimit
Hi Andrea,

The principle seems useful, but you seem to be duplicating a lot of
the existing res_counter code.

Could you not either:

- include these two extra fields in res_counter?
- include res_counter as the first field in a res_counter_ratelimit?

Paul

On Wed, Sep 17, 2008 at 4:05 AM, Andrea Righi <righi.andrea@gmail.com> wrote:
> Introduce res_counter_ratelimit as a generic structure to implement
> throttling-based cgroup subsystems.
>
> [ Only the interfaces needed by the IO controller are implemented right now ]
>
> Signed-off-by: Andrea Righi <righi.andrea@gmail.com>
> ---
> include/linux/res_counter.h | 70 +++++++++++++++++++++++++
> kernel/res_counter.c | 118 ++++++++++++++++++++++++++++++++++++++++++-
> 2 files changed, 187 insertions(+), 1 deletions(-)
>
> diff --git a/include/linux/res_counter.h b/include/linux/res_counter.h
> index 0ab55c4..ff677d9 100644
> --- a/include/linux/res_counter.h
> +++ b/include/linux/res_counter.h
> @@ -14,6 +14,7 @@
> */
>
> #include <linux/cgroup.h>
> +#include <linux/jiffies.h>
>
> /*
> * The core object. the cgroup that wishes to account for some
> @@ -45,6 +46,38 @@ struct res_counter {
> spinlock_t lock;
> };
>
> +/* The various policies that can be used for throttling */
> +#define RATELIMIT_LEAKY_BUCKET 0
> +#define RATELIMIT_TOKEN_BUCKET 1
> +
> +struct res_counter_ratelimit {
> + /*
> + * the current resource consumption level
> + */
> + unsigned long long usage;
> + /*
> + * the maximal value of the usage from the counter creation
> + */
> + unsigned long long max_usage;
> + /*
> + * the rate limit that cannot be exceeded
> + */
> + unsigned long long limit;
> + /*
> + * the limiting policy / algorithm
> + */
> + unsigned long long policy;
> + /*
> + * timestamp of the last accounted resource request
> + */
> + unsigned long long timestamp;
> + /*
> + * the lock to protect all of the above.
> + * the routines below consider this to be IRQ-safe
> + */
> + spinlock_t lock;
> +};
> +
> /**
> * Helpers to interact with userspace
> * res_counter_read_u64() - returns the value of the specified member.
> @@ -60,10 +93,17 @@ struct res_counter {
>
> u64 res_counter_read_u64(struct res_counter *counter, int member);
>
> +u64 res_counter_ratelimit_read_u64(struct res_counter_ratelimit *counter,
> + int member);
> +
> ssize_t res_counter_read(struct res_counter *counter, int member,
> const char __user *buf, size_t nbytes, loff_t *pos,
> int (*read_strategy)(unsigned long long val, char *s));
>
> +ssize_t res_counter_ratelimit_read(struct res_counter_ratelimit *counter,
> + int member, const char __user *buf, size_t nbytes, loff_t *pos,
> + int (*read_strategy)(unsigned long long val, char *s));
> +
> typedef int (*write_strategy_fn)(const char *buf, unsigned long long *val);
>
> int res_counter_memparse_write_strategy(const char *buf,
> @@ -80,6 +120,8 @@ enum {
> RES_USAGE,
> RES_MAX_USAGE,
> RES_LIMIT,
> + RES_POLICY,
> + RES_TIMESTAMP,
> RES_FAILCNT,
> };
>
> @@ -89,6 +131,8 @@ enum {
>
> void res_counter_init(struct res_counter *counter);
>
> +void res_counter_ratelimit_init(struct res_counter_ratelimit *counter);
> +
> /*
> * charge - try to consume more resource.
> *
> @@ -126,6 +170,15 @@ static inline bool res_counter_limit_check_locked(struct res_counter *cnt)
> return false;
> }
>
> +static inline unsigned long long
> +res_counter_ratelimit_delta_t(struct res_counter_ratelimit *res)
> +{
> + return (long long)get_jiffies_64() - (long long)res->timestamp;
> +}
> +
> +unsigned long long
> +res_counter_ratelimit_sleep(struct res_counter_ratelimit *res, ssize_t val);
> +
> /*
> * Helper function to detect if the cgroup is within it's limit or
> * not. It's currently called from cgroup_rss_prepare()
> @@ -159,6 +212,23 @@ static inline void res_counter_reset_failcnt(struct res_counter *cnt)
> spin_unlock_irqrestore(&cnt->lock, flags);
> }
>
> +static inline int
> +res_counter_ratelimit_set_limit(struct res_counter_ratelimit *cnt,
> + unsigned long long policy,
> + unsigned long long limit, unsigned long long max)
> +{
> + unsigned long flags;
> +
> + spin_lock_irqsave(&cnt->lock, flags);
> + cnt->limit = limit;
> + cnt->max_usage = max;
> + cnt->policy = policy;
> + cnt->timestamp = get_jiffies_64();
> + cnt->usage = 0;
> + spin_unlock_irqrestore(&cnt->lock, flags);
> + return 0;
> +}
> +
> static inline int res_counter_set_limit(struct res_counter *cnt,
> unsigned long long limit)
> {
> diff --git a/kernel/res_counter.c b/kernel/res_counter.c
> index f275c8e..cf23205 100644
> --- a/kernel/res_counter.c
> +++ b/kernel/res_counter.c
> @@ -9,6 +9,7 @@
>
> #include <linux/types.h>
> #include <linux/parser.h>
> +#include <linux/jiffies.h>
> #include <linux/fs.h>
> #include <linux/slab.h>
> #include <linux/res_counter.h>
> @@ -21,6 +22,15 @@ void res_counter_init(struct res_counter *counter)
> counter->limit = (unsigned long long)LLONG_MAX;
> }
>
> +void res_counter_ratelimit_init(struct res_counter_ratelimit *counter)
> +{
> + spin_lock_init(&counter->lock);
> + counter->limit = (unsigned long long)LLONG_MAX;
> + counter->max_usage = (unsigned long long)LLONG_MAX;
> + counter->usage = 0;
> + counter->timestamp = get_jiffies_64();
> +}
> +
> int res_counter_charge_locked(struct res_counter *counter, unsigned long val)
> {
> if (counter->usage + val > counter->limit) {
> @@ -62,7 +72,6 @@ void res_counter_uncharge(struct res_counter *counter, unsigned long val)
> spin_unlock_irqrestore(&counter->lock, flags);
> }
>
> -
> static inline unsigned long long *
> res_counter_member(struct res_counter *counter, int member)
> {
> @@ -81,6 +90,26 @@ res_counter_member(struct res_counter *counter, int member)
> return NULL;
> }
>
> +static inline unsigned long long *
> +res_counter_ratelimit_member(struct res_counter_ratelimit *counter, int member)
> +{
> + switch (member) {
> + case RES_USAGE:
> + return &counter->usage;
> + case RES_MAX_USAGE:
> + return &counter->max_usage;
> + case RES_LIMIT:
> + return &counter->limit;
> + case RES_POLICY:
> + return &counter->policy;
> + case RES_TIMESTAMP:
> + return &counter->timestamp;
> + };
> +
> + BUG();
> + return NULL;
> +}
> +
> ssize_t res_counter_read(struct res_counter *counter, int member,
> const char __user *userbuf, size_t nbytes, loff_t *pos,
> int (*read_strategy)(unsigned long long val, char *st_buf))
> @@ -98,11 +127,35 @@ ssize_t res_counter_read(struct res_counter *counter, int member,
> pos, buf, s - buf);
> }
>
> +ssize_t res_counter_ratelimit_read(struct res_counter_ratelimit *counter,
> + int member, const char __user *userbuf, size_t nbytes,
> + loff_t *pos,
> + int (*read_strategy)(unsigned long long val, char *st_buf))
> +{
> + unsigned long long *val;
> + char buf[64], *s;
> +
> + s = buf;
> + val = res_counter_ratelimit_member(counter, member);
> + if (read_strategy)
> + s += read_strategy(*val, s);
> + else
> + s += sprintf(s, "%llu\n", *val);
> + return simple_read_from_buffer((void __user *)userbuf, nbytes,
> + pos, buf, s - buf);
> +}
> +
> u64 res_counter_read_u64(struct res_counter *counter, int member)
> {
> return *res_counter_member(counter, member);
> }
>
> +u64 res_counter_ratelimit_read_u64(struct res_counter_ratelimit *counter,
> + int member)
> +{
> + return *res_counter_ratelimit_member(counter, member);
> +}
> +
> int res_counter_memparse_write_strategy(const char *buf,
> unsigned long long *res)
> {
> @@ -137,3 +190,66 @@ int res_counter_write(struct res_counter *counter, int member,
> spin_unlock_irqrestore(&counter->lock, flags);
> return 0;
> }
> +
> +static unsigned long long
> +ratelimit_leaky_bucket(struct res_counter_ratelimit *res, ssize_t val)
> +{
> + unsigned long long delta, t;
> +
> + res->usage += val;
> + delta = res_counter_ratelimit_delta_t(res);
> + if (!delta)
> + return 0;
> + t = res->usage * USEC_PER_SEC;
> + t = usecs_to_jiffies(div_u64(t, res->limit));
> + if (t > delta)
> + return t - delta;
> + /* Reset i/o statistics */
> + res->usage = 0;
> + res->timestamp = get_jiffies_64();
> + return 0;
> +}
> +
> +static unsigned long long
> +ratelimit_token_bucket(struct res_counter_ratelimit *res, ssize_t val)
> +{
> + unsigned long long delta;
> + long long tok;
> +
> + res->usage -= val;
> + delta = jiffies_to_msecs(res_counter_ratelimit_delta_t(res));
> + res->timestamp = get_jiffies_64();
> + tok = (long long)res->usage * MSEC_PER_SEC;
> + if (delta) {
> + long long max = (long long)res->max_usage * MSEC_PER_SEC;
> +
> + tok += delta * res->limit;
> + if (tok > max)
> + tok = max;
> + res->usage = (unsigned long long)div_s64(tok, MSEC_PER_SEC);
> + }
> + return (tok < 0) ? msecs_to_jiffies(div_u64(-tok, res->limit)) : 0;
> +}
> +
> +unsigned long long
> +res_counter_ratelimit_sleep(struct res_counter_ratelimit *res, ssize_t val)
> +{
> + unsigned long long sleep = 0;
> + unsigned long flags;
> +
> + spin_lock_irqsave(&res->lock, flags);
> + if (res->limit)
> + switch (res->policy) {
> + case RATELIMIT_LEAKY_BUCKET:
> + sleep = ratelimit_leaky_bucket(res, val);
> + break;
> + case RATELIMIT_TOKEN_BUCKET:
> + sleep = ratelimit_token_bucket(res, val);
> + break;
> + default:
> + WARN_ON(1);
> + break;
> + }
> + spin_unlock_irqrestore(&res->lock, flags);
> + return sleep;
> +}
> --
> 1.5.4.3
>
>


\
 
 \ /
  Last update: 2008-10-05 20:07    [W:0.092 / U:0.044 seconds]
©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site