All of lore.kernel.org
 help / color / mirror / Atom feed
From: Shailabh Nagar <nagar@watson.ibm.com>
To: linux-kernel <linux-kernel@vger.kernel.org>,
	ckrm-tech <ckrm-tech@lists.sourceforge.net>
Subject: [PATCH 4/6] CKRM numtasks resource controller
Date: Thu, 29 Apr 2004 04:25:05 -0400	[thread overview]
Message-ID: <4090BBE1.4080106@watson.ibm.com> (raw)

[-- Attachment #1: Type: text/plain, Size: 0 bytes --]



[-- Attachment #2: 03-numtasks.ckrm-E12.patch --]
[-- Type: text/plain, Size: 15037 bytes --]

diff -Nru a/include/linux/ckrm_tsk.h b/include/linux/ckrm_tsk.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/include/linux/ckrm_tsk.h	Wed Apr 28 22:41:05 2004
@@ -0,0 +1,41 @@
+/* ckrm_tsk.h - No. of tasks resource controller for CKRM
+ *
+ * Copyright (C) Chandra Seetharaman, IBM Corp. 2003
+ * 
+ * Provides No. of tasks resource controller for CKRM
+ *
+ * Latest version, more details at http://ckrm.sf.net
+ * 
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ */
+
+/* Changes
+ *
+ * 31 Mar 2004
+ *    Created.
+ */
+
+#ifndef _LINUX_CKRM_TSK_H
+#define _LINUX_CKRM_TSK_H
+
+#include <linux/ckrm_rc.h>
+
+#ifdef CONFIG_CKRM_RES_NUMTASKS
+
+extern int numtasks_get_ref(void *, int);
+extern int numtasks_get_ref_resid(void *, int, int);
+extern void numtasks_put_ref(void *);
+
+#else
+
+#define numtasks_get_ref(a, b)		1
+#define numtasks_get_ref_resid(a, b, c)		1
+#define numtasks_put_ref(a)
+
+#endif
+
+#endif // _LINUX_CKRM_RES_H
diff -Nru a/kernel/ckrm/ckrm_tasks.c b/kernel/ckrm/ckrm_tasks.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/kernel/ckrm/ckrm_tasks.c	Wed Apr 28 22:41:05 2004
@@ -0,0 +1,509 @@
+/* ckrm_numtasks.c - "Number of tasks" resource controller for CKRM
+ *
+ * Copyright (C) Chandra Seetharaman,  IBM Corp. 2003
+ * 
+ * Latest version, more details at http://ckrm.sf.net
+ * 
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ */
+
+/* Changes
+ * 
+ * 31 Mar 2004: Created
+ * 
+ */
+
+/*
+ * Code Description: TBD
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <asm/errno.h>
+#include <linux/list.h>
+#include <linux/spinlock.h>
+#include <linux/ckrm.h>
+#include <linux/ckrm_rc.h>
+#include <linux/ckrm_tc.h>
+
+#define TOTAL_NUM_TASKS (131072) // 128 K
+#define NUMTASKS_DEBUG
+#define NUMTASKS_NAME "numtasks"
+
+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_shares shares;
+	spinlock_t cnt_lock; // always grab parent's lock first and then 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; // no. of failures 'cause the request was over the limit
+	int borrow_sucesses; // no. of successful borrows
+	int borrow_failures; // no. of borrow faileures
+
+	// Maximum the specific statictics has reached.
+	int max_limit_failures;
+	int max_borrow_sucesses;
+	int max_borrow_failures;
+
+	// Total number of specific statistics
+	int tot_limit_failures;
+	int tot_borrow_sucesses;
+	int tot_borrow_failures;
+} ckrm_numtasks_t;
+
+struct ckrm_res_ctlr numtasks_rcbs;
+
+/* Initialize rescls values
+ * May be called on each rcfs unmount or as part of error recovery
+ * to make share values sane.
+ * Does not traverse hierarchy reinitializing children.
+ */
+static void
+numtasks_res_initcls_one(ckrm_numtasks_t *res)
+{
+	res->shares.my_guarantee     = CKRM_SHARE_DONTCARE;
+	res->shares.my_limit         = CKRM_SHARE_DONTCARE;
+	res->shares.total_guarantee  = CKRM_SHARE_DFLT_TOTAL_GUARANTEE;
+	res->shares.max_limit        = CKRM_SHARE_DFLT_MAX_LIMIT;
+	res->shares.unused_guarantee = CKRM_SHARE_DFLT_TOTAL_GUARANTEE;
+	res->shares.cur_max_limit    = 0;
+
+	res->cnt_guarantee           = CKRM_SHARE_DONTCARE;
+	res->cnt_unused              = CKRM_SHARE_DONTCARE;
+	res->cnt_limit               = CKRM_SHARE_DONTCARE;
+
+	res->over_guarantee          = 0;
+
+	res->limit_failures          = 0;
+	res->borrow_sucesses         = 0;
+	res->borrow_failures         = 0;
+
+	res->max_limit_failures      = 0;
+	res->max_borrow_sucesses     = 0;
+	res->max_borrow_failures     = 0;
+
+	res->tot_limit_failures      = 0;
+	res->tot_borrow_sucesses     = 0;
+	res->tot_borrow_failures     = 0;
+
+	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
+
+int
+numtasks_get_ref(void *arg, int force)
+{
+	int rc, resid = numtasks_rcbs.resid;
+	ckrm_numtasks_t *res;
+	ckrm_core_class_t *core = arg;
+
+	if ((resid < 0) || (core == NULL))
+		return 1;
+
+	res = ckrm_get_res_class(core, resid, ckrm_numtasks_t);
+	if (res == NULL) 
+		return 1;
+
+	atomic_inc(&res->cnt_cur_alloc);
+
+	rc = 1;
+	if (((res->parent) && (res->cnt_unused == CKRM_SHARE_DONTCARE)) ||
+			(atomic_read(&res->cnt_cur_alloc) > res->cnt_unused)) {
+
+		rc = 0;
+		if (!force && (res->cnt_limit != CKRM_SHARE_DONTCARE) && 
+				(atomic_read(&res->cnt_cur_alloc) > res->cnt_limit)) {
+			res->limit_failures++;
+			res->tot_limit_failures++;
+		} else if (res->parent != NULL) {
+			if ((rc = numtasks_get_ref(res->parent, force)) == 1) {
+				atomic_inc(&res->cnt_borrowed);
+				res->borrow_sucesses++;
+				res->tot_borrow_sucesses++;
+				res->over_guarantee = 1;
+			} else {
+				res->borrow_failures++;
+				res->tot_borrow_failures++;
+			}
+		} else {
+			rc = force;
+		}
+	} else if (res->over_guarantee) {
+		res->over_guarantee = 0;
+
+		if (res->max_limit_failures < res->limit_failures) {
+			res->max_limit_failures = res->limit_failures;
+		}
+		if (res->max_borrow_sucesses < res->borrow_sucesses) {
+			res->max_borrow_sucesses = res->borrow_sucesses;
+		}
+		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) {
+		atomic_dec(&res->cnt_cur_alloc);
+	}
+	return rc;
+}
+
+void
+numtasks_put_ref(void *arg)
+{
+	int resid = numtasks_rcbs.resid;
+	ckrm_numtasks_t *res;
+	ckrm_core_class_t *core = arg;
+
+	if ((resid == -1) || (core == NULL)) {
+		return;
+	}
+
+	res = ckrm_get_res_class(core, resid, ckrm_numtasks_t);
+	if (res == NULL) 
+		return;
+	atomic_dec(&res->cnt_cur_alloc);
+	if (atomic_read(&res->cnt_borrowed) > 0) {
+		atomic_dec(&res->cnt_borrowed);
+		numtasks_put_ref(res->parent);
+	}
+	return;
+}
+
+static void *
+numtasks_res_alloc(struct ckrm_core_class *core, struct ckrm_core_class *parent)
+{
+	ckrm_numtasks_t *res;
+	
+	res = kmalloc(sizeof(ckrm_numtasks_t), GFP_ATOMIC);
+	
+	if (res) {
+		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_NUM_TASKS;
+			res->cnt_unused =  TOTAL_NUM_TASKS;
+			res->cnt_limit = TOTAL_NUM_TASKS;
+		}
+	} else {
+		printk(KERN_ERR "numtasks_res_alloc: failed GFP_ATOMIC alloc\n");
+	}
+	return res;
+}
+
+/*
+ * No locking of this resource class object necessary as we are not
+ * supposed to be assigned (or used) when/after this function is called.
+ */
+static void
+numtasks_res_free(void *my_res)
+{
+	ckrm_numtasks_t *res = my_res, *parres, *childres;
+	ckrm_core_class_t *child = NULL;
+	int i, borrowed, maxlimit, resid = numtasks_rcbs.resid;
+
+	if (!res) 
+		return;
+
+	// Assuming there will be no children when this function is called
+	
+	parres = ckrm_get_res_class(res->parent, resid, ckrm_numtasks_t);
+
+	if (unlikely(atomic_read(&res->cnt_cur_alloc) != 0 ||
+				atomic_read(&res->cnt_borrowed))) {
+		printk(KERN_ERR "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(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
+	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) {
+			maxlimit = childres->shares.my_limit;
+		}
+	}
+	ckrm_unlock_hier(parres->core);
+	if (parres->shares.cur_max_limit < maxlimit) {
+		parres->shares.cur_max_limit = maxlimit;
+	}
+
+	spin_unlock(&parres->cnt_lock);
+	kfree(res);
+	return;
+}
+/*
+ * 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)
+{
+	ckrm_core_class_t *child = NULL;
+	ckrm_numtasks_t *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
+		//
+		if (parres->cnt_guarantee == CKRM_SHARE_DONTCARE) {
+			res->cnt_guarantee = CKRM_SHARE_DONTCARE;
+		} else {
+			res->cnt_guarantee = (self->my_guarantee * parres->cnt_guarantee) 
+					/ par->total_guarantee;
+		}
+		if (parres->cnt_limit == CKRM_SHARE_DONTCARE) {
+			res->cnt_limit = CKRM_SHARE_DONTCARE;
+		} else {
+			res->cnt_limit = (self->my_limit * parres->cnt_limit)
+					/ par->max_limit;
+		}
+
+		// Calculate unused units
+		if (res->cnt_guarantee == CKRM_SHARE_DONTCARE) {
+			res->cnt_unused = CKRM_SHARE_DONTCARE;
+		} else {
+			res->cnt_unused = (self->unused_guarantee *
+					res->cnt_guarantee) / self->total_guarantee;
+		}
+	}
+
+	// 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);
+
+		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_shares *cur = &res->shares, *par;
+	int rc = -EINVAL, resid = numtasks_rcbs.resid;
+
+	if (!res) 
+		return rc;
+
+	if (res->parent) {
+		parres = ckrm_get_res_class(res->parent, resid, ckrm_numtasks_t);
+		spin_lock(&parres->cnt_lock);
+		spin_lock(&res->cnt_lock);
+		par = &parres->shares;
+	} else {
+		spin_lock(&res->cnt_lock);
+		par = NULL;
+		parres = NULL;
+	}
+
+	rc = set_shares(new, cur, par);
+
+	if ((rc == 0) && parres) {
+		// Calculate parent's unused units
+		if (parres->cnt_guarantee == CKRM_SHARE_DONTCARE) {
+			parres->cnt_unused = CKRM_SHARE_DONTCARE;
+		} else {
+			parres->cnt_unused = (par->unused_guarantee *
+					parres->cnt_guarantee) / par->total_guarantee;
+		}
+
+		recalc_and_propagate(res, parres);
+	}
+	spin_unlock(&res->cnt_lock);
+	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;
+
+	if (!res) 
+		return -EINVAL;
+	*shares = res->shares;
+	return 0;
+}
+
+static int  
+numtasks_get_stats(void *my_res, struct seq_file *sfile)
+{
+	ckrm_numtasks_t *res = my_res;
+
+	if (!res) 
+		return -EINVAL;
+
+	seq_printf(sfile, "Number of tasks resource:\n");
+	seq_printf(sfile, "Total Over limit failures: %d\n",
+			res->tot_limit_failures);
+	seq_printf(sfile, "Total Over guarantee sucesses: %d\n",
+			res->tot_borrow_sucesses);
+	seq_printf(sfile, "Total Over guarantee failures: %d\n",
+			res->tot_borrow_failures);
+
+	seq_printf(sfile, "Maximum Over limit failures: %d\n",
+			res->max_limit_failures);
+	seq_printf(sfile, "Maximum Over guarantee sucesses: %d\n",
+			res->max_borrow_sucesses);
+	seq_printf(sfile, "Maximum Over guarantee failures: %d\n",
+			res->max_borrow_failures);
+#ifdef NUMTASKS_DEBUG
+	seq_printf(sfile, "cur_alloc %d; borrowed %d; cnt_guar %d; cnt_limit %d "
+			"unused_guarantee %d, cur_max_limit %d\n",
+			atomic_read(&res->cnt_cur_alloc),
+			atomic_read(&res->cnt_borrowed),
+			res->cnt_guarantee,
+			res->cnt_limit,
+			res->shares.unused_guarantee,
+			res->shares.cur_max_limit);
+#endif
+
+	return 0;
+}
+
+static int  
+numtasks_show_config(void *my_res, struct seq_file *sfile)
+{
+	ckrm_numtasks_t *res = my_res;
+
+	if (!res) 
+		return -EINVAL;
+
+	seq_printf(sfile, "res=%s,parameter=somevalue\n",NUMTASKS_NAME);
+	return 0;
+}
+
+static int  
+numtasks_set_config(void *my_res, const char *cfgstr)
+{
+	ckrm_numtasks_t *res = my_res;
+
+	if (!res) 
+		return -EINVAL;
+	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;
+
+	if (oldres != (void *) -1) {
+		struct task_struct *tsk = task;
+		if (!oldres) {
+			struct ckrm_core_class *old_core = &(tsk->parent->taskclass->core);
+			oldres = ckrm_get_res_class(old_core, numtasks_rcbs.resid,
+					ckrm_numtasks_t);
+		}
+		numtasks_put_ref(oldres->core);
+	}
+	if (newres) {
+		(void) numtasks_get_ref(newres->core, 1);
+	}
+}
+
+struct ckrm_res_ctlr numtasks_rcbs = {
+	.res_name          = NUMTASKS_NAME,
+	.res_hdepth        = 1,
+	.resid             = -1,
+	.res_alloc         = numtasks_res_alloc,
+	.res_free          = numtasks_res_free,
+	.set_share_values  = numtasks_set_share_values,
+	.get_share_values  = numtasks_get_share_values,
+	.get_stats         = numtasks_get_stats,
+	.show_config       = numtasks_show_config,
+	.set_config        = numtasks_set_config,
+	.change_resclass   = numtasks_change_resclass,
+};
+
+int __init
+init_ckrm_numtasks_res(void)
+{
+	struct ckrm_classtype *clstype;
+	int resid = numtasks_rcbs.resid;
+
+	clstype = ckrm_find_classtype_by_name("taskclass");
+	if (clstype == NULL) {
+		printk(KERN_INFO " Unknown ckrm classtype<taskclass>");
+		return -ENOENT;
+	}
+
+	if (resid == -1) {
+		resid = ckrm_register_res_ctlr(clstype,&numtasks_rcbs);
+		printk("........init_ckrm_numtasks_res -> %d\n",resid);
+	}
+	return 0;
+}	
+
+void __exit
+exit_ckrm_numtasks_res(void)
+{
+	ckrm_unregister_res_ctlr(&numtasks_rcbs);
+	numtasks_rcbs.resid = -1;
+}
+
+module_init(init_ckrm_numtasks_res)
+module_exit(exit_ckrm_numtasks_res)
+
+EXPORT_SYMBOL(numtasks_get_ref);
+EXPORT_SYMBOL(numtasks_put_ref);
+
+MODULE_LICENSE("GPL");
+

                 reply	other threads:[~2004-04-29  8:31 UTC|newest]

Thread overview: [no followups] expand[flat|nested]  mbox.gz  Atom feed

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=4090BBE1.4080106@watson.ibm.com \
    --to=nagar@watson.ibm.com \
    --cc=ckrm-tech@lists.sourceforge.net \
    --cc=linux-kernel@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.