*
*/
-/* Changes
- *
- * 31 Mar 2004: Created
- *
- */
-
/*
- * Code Description: TBD
+ * CKRM Resource controller for tracking number of tasks in a class.
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <asm/div64.h>
#include <linux/list.h>
#include <linux/spinlock.h>
-#include <linux/parser.h>
#include <linux/ckrm_rc.h>
#include <linux/ckrm_tc.h>
#include <linux/ckrm_tsk.h>
-#define DEF_TOTAL_NUM_TASKS (131072) // 128 K
-#define DEF_FORKRATE (1000000) // 1 million tasks
-#define DEF_FORKRATE_INTERVAL (3600) // per hour
+#define TOTAL_NUM_TASKS (131072) /* 128 K */
#define NUMTASKS_DEBUG
#define NUMTASKS_NAME "numtasks"
-#define SYS_TOTAL_TASKS "sys_total_tasks"
-#define FORKRATE "forkrate"
-#define FORKRATE_INTERVAL "forkrate_interval"
-
-static int total_numtasks = DEF_TOTAL_NUM_TASKS;
-static int total_cnt_alloc = 0;
-static int forkrate = DEF_FORKRATE;
-static int forkrate_interval = DEF_FORKRATE_INTERVAL;
-static ckrm_core_class_t *root_core;
-
-typedef struct ckrm_numtasks {
- struct ckrm_core_class *core; // the core i am part of...
- struct ckrm_core_class *parent; // parent of the core above.
+
+struct ckrm_numtasks {
+ struct ckrm_core_class *core; /* the core i am part of... */
+ struct ckrm_core_class *parent; /* parent of the core above. */
struct ckrm_shares shares;
- spinlock_t cnt_lock; // always grab parent's lock before child's
- int cnt_guarantee; // num_tasks guarantee in local units
- int cnt_unused; // has to borrow if more than this is needed
- int cnt_limit; // no tasks over this limit.
- atomic_t cnt_cur_alloc; // current alloc from self
- atomic_t cnt_borrowed; // borrowed from the parent
-
- int over_guarantee; // turn on/off when cur_alloc goes
- // over/under guarantee
-
- // internally maintained statictics to compare with max numbers
- int limit_failures; // # failures as request was over the limit
- int borrow_sucesses; // # successful borrows
- int borrow_failures; // # borrow failures
-
- // Maximum the specific statictics has reached.
+ spinlock_t cnt_lock; /* always grab parent's lock before child's */
+ int cnt_guarantee; /* num_tasks guarantee in local units */
+ int cnt_unused; /* has to borrow if more than this is needed */
+ int cnt_limit; /* no tasks over this limit. */
+ atomic_t cnt_cur_alloc; /* current alloc from self */
+ atomic_t cnt_borrowed; /* borrowed from the parent */
+
+ int over_guarantee; /* turn on/off when cur_alloc goes */
+ /* over/under guarantee */
+
+ /* internally maintained statictics to compare with max numbers */
+ int limit_failures; /* # failures as request was over the limit */
+ int borrow_sucesses; /* # successful borrows */
+ int borrow_failures; /* # borrow failures */
+
+ /* Maximum the specific statictics has reached. */
int max_limit_failures;
int max_borrow_sucesses;
int max_borrow_failures;
- // Total number of specific statistics
+ /* Total number of specific statistics */
int tot_limit_failures;
int tot_borrow_sucesses;
int tot_borrow_failures;
-
- // fork rate fields
- int forks_in_period;
- unsigned long period_start;
-} ckrm_numtasks_t;
+};
struct ckrm_res_ctlr numtasks_rcbs;
* to make share values sane.
* Does not traverse hierarchy reinitializing children.
*/
-static void numtasks_res_initcls_one(ckrm_numtasks_t * res)
+static void numtasks_res_initcls_one(struct ckrm_numtasks * res)
{
res->shares.my_guarantee = CKRM_SHARE_DONTCARE;
res->shares.my_limit = CKRM_SHARE_DONTCARE;
res->tot_borrow_sucesses = 0;
res->tot_borrow_failures = 0;
- res->forks_in_period = 0;
- res->period_start = jiffies;
-
atomic_set(&res->cnt_cur_alloc, 0);
atomic_set(&res->cnt_borrowed, 0);
return;
}
-#if 0
-static void numtasks_res_initcls(void *my_res)
-{
- ckrm_numtasks_t *res = my_res;
-
- /* Write a version which propagates values all the way down
- and replace rcbs callback with that version */
-
-}
-#endif
-
-static int numtasks_get_ref_local(void *arg, int force)
+static int numtasks_get_ref_local(struct ckrm_core_class *core, int force)
{
- int rc, resid = numtasks_rcbs.resid, borrowed = 0;
- unsigned long now = jiffies, chg_at;
- ckrm_numtasks_t *res;
- ckrm_core_class_t *core = arg;
+ int rc, resid = numtasks_rcbs.resid;
+ struct ckrm_numtasks *res;
if ((resid < 0) || (core == NULL))
return 1;
- res = ckrm_get_res_class(core, resid, ckrm_numtasks_t);
+ res = ckrm_get_res_class(core, resid, struct ckrm_numtasks);
if (res == NULL)
return 1;
-#ifdef CONFIG_CKRM_RES_NUMTASKS_FORKRATE
- // force is not associated with fork. So, if force is specified
- // we don't have to bother about forkrate.
- if (!force) {
- // Take care of wraparound situation
- chg_at = res->period_start + forkrate_interval * HZ;
- if (chg_at < res->period_start) {
- chg_at += forkrate_interval * HZ;
- now += forkrate_interval * HZ;
- }
- if (chg_at <= now) {
- res->period_start = now;
- res->forks_in_period = 0;
- }
-
- if (res->forks_in_period >= forkrate) {
- return 0;
- }
- }
-#endif
-
atomic_inc(&res->cnt_cur_alloc);
rc = 1;
res->borrow_sucesses++;
res->tot_borrow_sucesses++;
res->over_guarantee = 1;
- borrowed++;
} else {
res->borrow_failures++;
res->tot_borrow_failures++;
}
- } else {
+ } else
rc = force;
- }
} else if (res->over_guarantee) {
res->over_guarantee = 0;
- if (res->max_limit_failures < res->limit_failures) {
+ if (res->max_limit_failures < res->limit_failures)
res->max_limit_failures = res->limit_failures;
- }
- if (res->max_borrow_sucesses < res->borrow_sucesses) {
+ if (res->max_borrow_sucesses < res->borrow_sucesses)
res->max_borrow_sucesses = res->borrow_sucesses;
- }
- if (res->max_borrow_failures < res->borrow_failures) {
+ if (res->max_borrow_failures < res->borrow_failures)
res->max_borrow_failures = res->borrow_failures;
- }
res->limit_failures = 0;
res->borrow_sucesses = 0;
res->borrow_failures = 0;
}
- if (!rc) {
+ if (!rc)
atomic_dec(&res->cnt_cur_alloc);
- } else if (!borrowed) {
- total_cnt_alloc++;
-#ifdef CONFIG_CKRM_RES_NUMTASKS_FORKRATE
- if (!force) { // force is not associated with a real fork.
- res->forks_in_period++;
- }
-#endif
- }
return rc;
}
-static void numtasks_put_ref_local(void *arg)
+static void numtasks_put_ref_local(struct ckrm_core_class *core)
{
int resid = numtasks_rcbs.resid;
- ckrm_numtasks_t *res;
- ckrm_core_class_t *core = arg;
+ struct ckrm_numtasks *res;
- if ((resid == -1) || (core == NULL)) {
+ if ((resid == -1) || (core == NULL))
return;
- }
- res = ckrm_get_res_class(core, resid, ckrm_numtasks_t);
+ res = ckrm_get_res_class(core, resid, struct ckrm_numtasks);
if (res == NULL)
return;
- if (unlikely(atomic_read(&res->cnt_cur_alloc) == 0)) {
- printk(KERN_WARNING "numtasks_put_ref: Trying to decrement "
- "counter below 0\n");
- return;
- }
atomic_dec(&res->cnt_cur_alloc);
if (atomic_read(&res->cnt_borrowed) > 0) {
atomic_dec(&res->cnt_borrowed);
numtasks_put_ref_local(res->parent);
- } else {
- total_cnt_alloc--;
}
-
return;
}
static void *numtasks_res_alloc(struct ckrm_core_class *core,
struct ckrm_core_class *parent)
{
- ckrm_numtasks_t *res;
+ struct ckrm_numtasks *res;
- res = kmalloc(sizeof(ckrm_numtasks_t), GFP_ATOMIC);
+ res = kmalloc(sizeof(struct ckrm_numtasks), GFP_ATOMIC);
if (res) {
- memset(res, 0, sizeof(ckrm_numtasks_t));
+ memset(res, 0, sizeof(struct ckrm_numtasks));
res->core = core;
res->parent = parent;
numtasks_res_initcls_one(res);
res->cnt_lock = SPIN_LOCK_UNLOCKED;
if (parent == NULL) {
- // I am part of root class. So set the max tasks
- // to available default
- res->cnt_guarantee = total_numtasks;
- res->cnt_unused = total_numtasks;
- res->cnt_limit = total_numtasks;
- root_core = core; // store the root core.
+ /*
+ * I am part of root class. So set the max tasks
+ * to available default.
+ */
+ res->cnt_guarantee = TOTAL_NUM_TASKS;
+ res->cnt_unused = TOTAL_NUM_TASKS;
+ res->cnt_limit = TOTAL_NUM_TASKS;
}
try_module_get(THIS_MODULE);
} else {
*/
static void numtasks_res_free(void *my_res)
{
- ckrm_numtasks_t *res = my_res, *parres, *childres;
- ckrm_core_class_t *child = NULL;
+ struct ckrm_numtasks *res = my_res, *parres, *childres;
+ struct ckrm_core_class *child = NULL;
int i, borrowed, maxlimit, resid = numtasks_rcbs.resid;
if (!res)
return;
- // Assuming there will be no children when this function is called
+ /* Assuming there will be no children when this function is called */
- parres = ckrm_get_res_class(res->parent, resid, ckrm_numtasks_t);
+ parres = ckrm_get_res_class(res->parent, resid, struct ckrm_numtasks);
- if (unlikely(atomic_read(&res->cnt_cur_alloc) < 0)) {
- printk(KERN_WARNING "numtasks_res: counter below 0\n");
- }
- if (unlikely(atomic_read(&res->cnt_cur_alloc) > 0 ||
- atomic_read(&res->cnt_borrowed) > 0)) {
- printk(KERN_WARNING "numtasks_res_free: resource still "
- "alloc'd %p\n", res);
- if ((borrowed = atomic_read(&res->cnt_borrowed)) > 0) {
- for (i = 0; i < borrowed; i++) {
- numtasks_put_ref_local(parres->core);
- }
- }
- }
- // return child's limit/guarantee to parent node
+ if ((borrowed = atomic_read(&res->cnt_borrowed)) > 0)
+ for (i = 0; i < borrowed; i++)
+ numtasks_put_ref_local(parres->core);
+
+ /* return child's limit/guarantee to parent node */
spin_lock(&parres->cnt_lock);
child_guarantee_changed(&parres->shares, res->shares.my_guarantee, 0);
- // run thru parent's children and get the new max_limit of the parent
+ /* run thru parent's children and get the new max_limit of the parent */
ckrm_lock_hier(parres->core);
maxlimit = 0;
while ((child = ckrm_get_next_child(parres->core, child)) != NULL) {
- childres = ckrm_get_res_class(child, resid, ckrm_numtasks_t);
- if (maxlimit < childres->shares.my_limit) {
+ childres = ckrm_get_res_class(child, resid, struct ckrm_numtasks);
+ if (maxlimit < childres->shares.my_limit)
maxlimit = childres->shares.my_limit;
- }
}
ckrm_unlock_hier(parres->core);
- if (parres->shares.cur_max_limit < maxlimit) {
+ if (parres->shares.cur_max_limit < maxlimit)
parres->shares.cur_max_limit = maxlimit;
- }
spin_unlock(&parres->cnt_lock);
kfree(res);
return;
}
-static inline int
-do_share_calc(int a, int b, int c)
-{
- u64 temp;
- if (a < 0) {
- temp = b;
- } else {
- temp = (u64) a * b;
- }
- do_div(temp, c);
- return (int) temp;
-}
-
/*
* Recalculate the guarantee and limit in real units... and propagate the
* same to children.
* Caller is responsible for protecting res and for the integrity of parres
*/
static void
-recalc_and_propagate(ckrm_numtasks_t * res, ckrm_numtasks_t * parres)
+recalc_and_propagate(struct ckrm_numtasks * res, struct ckrm_numtasks * parres)
{
- ckrm_core_class_t *child = NULL;
- ckrm_numtasks_t *childres;
+ struct ckrm_core_class *child = NULL;
+ struct ckrm_numtasks *childres;
int resid = numtasks_rcbs.resid;
if (parres) {
struct ckrm_shares *par = &parres->shares;
struct ckrm_shares *self = &res->shares;
- // calculate cnt_guarantee and cnt_limit
- //
+ /* calculate cnt_guarantee and cnt_limit */
if ((parres->cnt_guarantee == CKRM_SHARE_DONTCARE) ||
- (self->my_guarantee == CKRM_SHARE_DONTCARE))
- {
+ (self->my_guarantee == CKRM_SHARE_DONTCARE))
res->cnt_guarantee = CKRM_SHARE_DONTCARE;
- } else if (par->total_guarantee) {
- res->cnt_guarantee =
- do_share_calc(self->my_guarantee,
- parres->cnt_guarantee,
- par->total_guarantee);
- } else {
+ else if (par->total_guarantee) {
+ u64 temp = (u64) self->my_guarantee * parres->cnt_guarantee;
+ do_div(temp, par->total_guarantee);
+ res->cnt_guarantee = (int) temp;
+ } else
res->cnt_guarantee = 0;
- }
if ((parres->cnt_limit == CKRM_SHARE_DONTCARE) ||
- (self->my_limit == CKRM_SHARE_DONTCARE)) {
+ (self->my_limit == CKRM_SHARE_DONTCARE))
res->cnt_limit = CKRM_SHARE_DONTCARE;
- } else if (par->max_limit) {
- res->cnt_limit =
- do_share_calc(self->my_limit,
- parres->cnt_limit,
- par->max_limit);
- } else {
+ else if (par->max_limit) {
+ u64 temp = (u64) self->my_limit * parres->cnt_limit;
+ do_div(temp, par->max_limit);
+ res->cnt_limit = (int) temp;
+ } else
res->cnt_limit = 0;
- }
- // Calculate unused units
+ /* Calculate unused units */
if ((res->cnt_guarantee == CKRM_SHARE_DONTCARE) ||
- (self->my_guarantee == CKRM_SHARE_DONTCARE)) {
+ (self->my_guarantee == CKRM_SHARE_DONTCARE))
res->cnt_unused = CKRM_SHARE_DONTCARE;
- } else if (self->total_guarantee) {
- res->cnt_unused =
- do_share_calc(self->unused_guarantee,
- res->cnt_guarantee,
- par->total_guarantee);
- } else {
+ else if (self->total_guarantee) {
+ u64 temp = (u64) self->unused_guarantee * res->cnt_guarantee;
+ do_div(temp, self->total_guarantee);
+ res->cnt_unused = (int) temp;
+ } else
res->cnt_unused = 0;
- }
}
- // propagate to children
+
+ /* propagate to children */
ckrm_lock_hier(res->core);
while ((child = ckrm_get_next_child(res->core, child)) != NULL) {
- childres = ckrm_get_res_class(child, resid, ckrm_numtasks_t);
- if (childres) {
- spin_lock(&childres->cnt_lock);
- recalc_and_propagate(childres, res);
- spin_unlock(&childres->cnt_lock);
- } else {
- printk(KERN_ERR "%s: numtasks resclass missing\n",__FUNCTION__);
- }
+ childres = ckrm_get_res_class(child, resid, struct ckrm_numtasks);
+
+ spin_lock(&childres->cnt_lock);
+ recalc_and_propagate(childres, res);
+ spin_unlock(&childres->cnt_lock);
}
ckrm_unlock_hier(res->core);
return;
static int numtasks_set_share_values(void *my_res, struct ckrm_shares *new)
{
- ckrm_numtasks_t *parres, *res = my_res;
+ struct ckrm_numtasks *parres, *res = my_res;
struct ckrm_shares *cur = &res->shares, *par;
int rc = -EINVAL, resid = numtasks_rcbs.resid;
if (res->parent) {
parres =
- ckrm_get_res_class(res->parent, resid, ckrm_numtasks_t);
+ ckrm_get_res_class(res->parent, resid, struct ckrm_numtasks);
spin_lock(&parres->cnt_lock);
spin_lock(&res->cnt_lock);
par = &parres->shares;
rc = set_shares(new, cur, par);
if ((rc == 0) && parres) {
- // Calculate parent's unused units
- if (parres->cnt_guarantee == CKRM_SHARE_DONTCARE) {
+ /* Calculate parent's unused units */
+ if (parres->cnt_guarantee == CKRM_SHARE_DONTCARE)
parres->cnt_unused = CKRM_SHARE_DONTCARE;
- } else if (par->total_guarantee) {
- parres->cnt_unused =
- do_share_calc(par->unused_guarantee,
- parres->cnt_guarantee,
- par->total_guarantee);
- } else {
+ else if (par->total_guarantee) {
+ u64 temp = (u64) par->unused_guarantee * parres->cnt_guarantee;
+ do_div(temp, par->total_guarantee);
+ parres->cnt_unused = (int) temp;
+ } else
parres->cnt_unused = 0;
- }
recalc_and_propagate(res, parres);
}
spin_unlock(&res->cnt_lock);
- if (res->parent) {
+ if (res->parent)
spin_unlock(&parres->cnt_lock);
- }
return rc;
}
static int numtasks_get_share_values(void *my_res, struct ckrm_shares *shares)
{
- ckrm_numtasks_t *res = my_res;
+ struct ckrm_numtasks *res = my_res;
if (!res)
return -EINVAL;
static int numtasks_get_stats(void *my_res, struct seq_file *sfile)
{
- ckrm_numtasks_t *res = my_res;
+ struct ckrm_numtasks *res = my_res;
if (!res)
return -EINVAL;
- seq_printf(sfile, "Number of tasks resource:\n");
+ seq_printf(sfile, "---------Number of tasks stats start---------\n");
seq_printf(sfile, "Total Over limit failures: %d\n",
res->tot_limit_failures);
seq_printf(sfile, "Total Over guarantee sucesses: %d\n",
res->max_borrow_sucesses);
seq_printf(sfile, "Maximum Over guarantee failures: %d\n",
res->max_borrow_failures);
+ seq_printf(sfile, "---------Number of tasks stats end---------\n");
#ifdef NUMTASKS_DEBUG
seq_printf(sfile,
"cur_alloc %d; borrowed %d; cnt_guar %d; cnt_limit %d "
static int numtasks_show_config(void *my_res, struct seq_file *sfile)
{
- ckrm_numtasks_t *res = my_res;
+ struct ckrm_numtasks *res = my_res;
if (!res)
return -EINVAL;
- seq_printf(sfile, "res=%s,%s=%d,%s=%d,%s=%d\n", NUMTASKS_NAME,
- SYS_TOTAL_TASKS, total_numtasks,
- FORKRATE, forkrate,
- FORKRATE_INTERVAL, forkrate_interval);
+ seq_printf(sfile, "res=%s,parameter=somevalue\n", NUMTASKS_NAME);
return 0;
}
-enum numtasks_token_t {
- numtasks_token_total,
- numtasks_token_forkrate,
- numtasks_token_interval,
- numtasks_token_err
-};
-
-static match_table_t numtasks_tokens = {
- {numtasks_token_total, SYS_TOTAL_TASKS "=%d"},
- {numtasks_token_forkrate, FORKRATE "=%d"},
- {numtasks_token_interval, FORKRATE_INTERVAL "=%d"},
- {numtasks_token_err, NULL},
-};
-
-static void reset_forkrates(ckrm_core_class_t *parent, unsigned long now)
-{
- ckrm_numtasks_t *parres;
- ckrm_core_class_t *child = NULL;
-
- parres = ckrm_get_res_class(parent, numtasks_rcbs.resid,
- ckrm_numtasks_t);
- if (!parres) {
- return;
- }
- parres->forks_in_period = 0;
- parres->period_start = now;
-
- ckrm_lock_hier(parent);
- while ((child = ckrm_get_next_child(parent, child)) != NULL) {
- reset_forkrates(child, now);
- }
- ckrm_unlock_hier(parent);
-}
-
static int numtasks_set_config(void *my_res, const char *cfgstr)
{
- char *p;
- ckrm_numtasks_t *res = my_res;
- int new_total, fr = 0, itvl = 0, err = 0;
+ struct ckrm_numtasks *res = my_res;
if (!res)
return -EINVAL;
-
- while ((p = strsep((char**)&cfgstr, ",")) != NULL) {
- substring_t args[MAX_OPT_ARGS];
- int token;
- if (!*p)
- continue;
-
- token = match_token(p, numtasks_tokens, args);
- switch (token) {
- case numtasks_token_total:
- if (match_int(args, &new_total) ||
- (new_total < total_cnt_alloc)) {
- err = -EINVAL;
- } else {
- total_numtasks = new_total;
-
- // res is the default class, as config is present only
- // in that directory
- spin_lock(&res->cnt_lock);
- res->cnt_guarantee = total_numtasks;
- res->cnt_unused = total_numtasks;
- res->cnt_limit = total_numtasks;
- recalc_and_propagate(res, NULL);
- spin_unlock(&res->cnt_lock);
- }
- break;
- case numtasks_token_forkrate:
- if (match_int(args, &fr) || (fr <= 0)) {
- err = -EINVAL;
- } else {
- forkrate = fr;
- }
- break;
- case numtasks_token_interval:
- if (match_int(args, &itvl) || (itvl <= 0)) {
- err = -EINVAL;
- } else {
- forkrate_interval = itvl;
- }
- break;
- default:
- err = -EINVAL;
- }
- }
- if ((fr > 0) || (itvl > 0)) {
- reset_forkrates(root_core, jiffies);
- }
- return err;
+ printk("numtasks config='%s'\n", cfgstr);
+ return 0;
}
static void numtasks_change_resclass(void *task, void *old, void *new)
{
- ckrm_numtasks_t *oldres = old;
- ckrm_numtasks_t *newres = new;
+ struct ckrm_numtasks *oldres = old;
+ struct ckrm_numtasks *newres = new;
if (oldres != (void *)-1) {
struct task_struct *tsk = task;
&(tsk->parent->taskclass->core);
oldres =
ckrm_get_res_class(old_core, numtasks_rcbs.resid,
- ckrm_numtasks_t);
+ struct ckrm_numtasks);
}
- numtasks_put_ref_local(oldres->core);
+ if (oldres)
+ numtasks_put_ref_local(oldres->core);
}
- if (newres) {
+ if (newres)
(void)numtasks_get_ref_local(newres->core, 1);
- }
}
struct ckrm_res_ctlr numtasks_rcbs = {
if (resid == -1) {
resid = ckrm_register_res_ctlr(clstype, &numtasks_rcbs);
- printk(KERN_DEBUG "........init_ckrm_numtasks_res -> %d\n", resid);
+ printk("........init_ckrm_numtasks_res -> %d\n", resid);
if (resid != -1) {
ckrm_numtasks_register(numtasks_get_ref_local,
numtasks_put_ref_local);
void __exit exit_ckrm_numtasks_res(void)
{
- if (numtasks_rcbs.resid != -1) {
+ if (numtasks_rcbs.resid != -1)
ckrm_numtasks_register(NULL, NULL);
- }
ckrm_unregister_res_ctlr(&numtasks_rcbs);
numtasks_rcbs.resid = -1;
}
module_init(init_ckrm_numtasks_res)
- module_exit(exit_ckrm_numtasks_res)
+module_exit(exit_ckrm_numtasks_res)
- MODULE_LICENSE("GPL");
+MODULE_LICENSE("GPL");