[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Xen-devel] [RFC PATCH v4] xen: credit2: provide custom option to create runqueue



The patch introduces a new, very flexible way of arranging runqueues in Credit2.
It allows to specify, explicitly and precisely, what pCPUs should belong to
which runqueue.

Signed-off-by: Praveen Kumar <kpraveen.lkml@xxxxxxxxx>
---
 docs/misc/xen-command-line.markdown |  10 ++-
 xen/common/sched_credit2.c          | 167 +++++++++++++++++++++++++++++++++++-
 2 files changed, 174 insertions(+), 3 deletions(-)

diff --git a/docs/misc/xen-command-line.markdown 
b/docs/misc/xen-command-line.markdown
index 33e54aef63..f2ee4ad972 100644
--- a/docs/misc/xen-command-line.markdown
+++ b/docs/misc/xen-command-line.markdown
@@ -525,7 +525,7 @@ also slow in responding to load changes.
 The default value of `1 sec` is rather long.
 
 ### credit2\_runqueue
-> `= cpu | core | socket | node | all`
+> `= cpu | core | socket | node | all | <custom>`
 
 > Default: `socket`
 
@@ -543,6 +543,14 @@ Available alternatives, with their meaning, are:
 * `node`: one runqueue per each NUMA node of the host;
 * `all`: just one runqueue shared by all the logical pCPUs of
          the host
+* `<custom>`: one runqueue per mentioned subset. The subset can be defined as
+              as shown in below example:
+              credit2_runqueue=[[0,1,][2,6][3,5][4,7]] , or 0,1\;2,6\;3,5\;4,7
+              which means :
+                  - pCPUs 0 and 1 belong to runqueue 0
+                  - pCPUs 2 and 6 belong to runqueue 1
+                  - pCPUs 3 and 5 belong to runqueue 2
+                  - pCPUs 4 and 7 belong to runqueue 3
 
 ### dbgp
 > `= ehci[ <integer> | @pci<bus>:<slot>.<func> ]`
diff --git a/xen/common/sched_credit2.c b/xen/common/sched_credit2.c
index b9b928347f..ebec33f450 100644
--- a/xen/common/sched_credit2.c
+++ b/xen/common/sched_credit2.c
@@ -321,6 +321,16 @@ integer_param("credit2_balance_over", 
opt_overload_balance_tolerance);
  *           (logical) processors of the host belong. This will happen if
  *           the opt_runqueue parameter is set to 'all'.
  *
+ * - custom: meaning that there will be one runqueue per subset being passed as
+ *           parameter to credit2_runqueue as shown in below example.
+ *           Example:
+ *           credit2_runqueue=[[cpu0,cpu1][cpu3][cpu4,cpu5]] or
+ *           credit2_runqueue=0,1\;3\;4,5
+ *           The example mentioned states :
+ *               cpu0 and cpu1 belongs to runqueue 0
+ *               cpu3 belongs to runqueue 1
+ *               cpu4 and cpu5 belongs to runqueue 2
+ *
  * Depending on the value of opt_runqueue, therefore, cpus that are part of
  * either the same physical core, the same physical socket, the same NUMA
  * node, or just all of them, will be put together to form runqueues.
@@ -330,15 +340,138 @@ integer_param("credit2_balance_over", 
opt_overload_balance_tolerance);
 #define OPT_RUNQUEUE_SOCKET 2
 #define OPT_RUNQUEUE_NODE   3
 #define OPT_RUNQUEUE_ALL    4
+#define OPT_RUNQUEUE_CUSTOM 5
 static const char *const opt_runqueue_str[] = {
     [OPT_RUNQUEUE_CPU] = "cpu",
     [OPT_RUNQUEUE_CORE] = "core",
     [OPT_RUNQUEUE_SOCKET] = "socket",
     [OPT_RUNQUEUE_NODE] = "node",
-    [OPT_RUNQUEUE_ALL] = "all"
+    [OPT_RUNQUEUE_ALL] = "all",
+    [OPT_RUNQUEUE_CUSTOM] = "custom"
 };
 static int __read_mostly opt_runqueue = OPT_RUNQUEUE_SOCKET;
 
+static unsigned long __read_mostly custom_cpu_runqueue[NR_CPUS];
+
+static inline int getlen(const char *start, const char *end)
+{
+    if ( ( start ) && ( end ) && ( end > start ) )
+        return end-start;
+    else
+        return -1;
+}
+
+static int parse_custom_runqueue_option(const char *s)
+{
+    const char *parse = NULL, *s_end = NULL;
+    const char *start = NULL, *end = NULL;
+    char delimiter[2] = {0};
+    int cpu_added_to_runqueue = 0;
+    int runqueue = 0;
+
+    /* Format supported :
+     * [[0,1,4,5][2,3,6,7][8,9,12,13][10,11,14,15]]
+     *                  or
+     * 0,1,4,5\;2,3,6,7\;8,9,12,13\;10,11,14,15
+     */
+    parse = s;
+    s_end = s + strlen(s);
+    /* The start and should always be in format of '[..]' */
+    if ( ( '[' == *parse ) && ( ']' == *(s_end-1)) )
+    {
+        delimiter[0] = '[';
+        delimiter[1] = '\0';
+        parse++;
+    }
+    else
+    {
+        delimiter[0] = ';';
+        delimiter[1] = '\0';
+    }
+
+    while ( ( parse != NULL ) && ( parse < s_end ) )
+    {
+        const char *token_sub_str = NULL;
+
+        while ( *parse == '[' )
+            parse++;
+
+        start = parse;
+        end = strstr(parse, delimiter);
+
+        /* Check if we don't have the delimiter */
+        if ( !end )
+        {
+            /* If we don't have delimiter, then break, if start is greater than
+             * or equal to s_end, as we have reached the end.
+             */
+            if ( start >= s_end )
+                break;
+
+            /* We need to parse till s_end, as we have the last set */
+            end = s_end;
+        }
+
+        /* Just move to next, as we have empty set like [] or ;; */
+        if ( getlen ( start, end ) < 1 )
+            goto next;
+
+        /*
+         * find token within the subset
+         */
+        do
+        {
+            unsigned long token = 0;
+
+            /* Get cpu ids separated by ',' within each set */
+            token_sub_str = strpbrk(start, ",");
+
+            /* Basic checks to validate the last entry in subset */
+            if ( ( !token_sub_str && start < end ) ||
+                ( token_sub_str > end && token_sub_str > start ) )
+            {
+                if ( ( delimiter[0] == '[' ) && ( start == s_end - 1 ) )
+                    goto next;
+
+                token_sub_str = end;
+            }
+
+            /* Just move to next, as we have empty set like [] or ;; */
+            if ( getlen(start, token_sub_str) < 1 )
+                goto next;
+
+            token = simple_strtoul(start ,&token_sub_str, 0);
+
+            if ( token >= nr_cpu_ids)
+                return -1;
+
+            /* If not set already */
+            if ( custom_cpu_runqueue[token] == -1 )
+            {
+                custom_cpu_runqueue[token] = runqueue;
+                cpu_added_to_runqueue = 1;
+            }
+            else
+                return -1;
+
+            if ( !token_sub_str || token_sub_str > end )
+                goto next;
+
+            start = ++token_sub_str;
+        } while ( start < end );
+next:
+        if ( cpu_added_to_runqueue )
+        {
+            runqueue++;
+            cpu_added_to_runqueue = 0;
+        }
+
+        parse = ++end;
+    }
+    opt_runqueue = OPT_RUNQUEUE_CUSTOM;
+    return 0;
+}
+
 static void parse_credit2_runqueue(const char *s)
 {
     unsigned int i;
@@ -351,8 +484,29 @@ static void parse_credit2_runqueue(const char *s)
             return;
         }
     }
+    /*
+     * At this stage we are either unknown value of credit2_runqueue or we can
+     * consider it to be custom cpu. Lets try parsing the same.
+     * Resetting the custom_cpu_runqueue for future use. Only the non-negative
+     * entries will be valid. The index 'i' in custom_cpu_runqueue will store
+     * the specific runqueue it belongs to.
+     * Example:
+     *     If custom_cpu_runqueue[3] == 2
+     *     Then, it means that cpu 3 belong to runqueue 2.
+     *     If custom_cpu_runqueue[4] == -1
+     *     Then, it means that cpu 4 doesn't belong to any runqueue.
+     */
+    for ( i = 0; i < nr_cpu_ids; i++ )
+        custom_cpu_runqueue[i] = -1;
 
-    printk("WARNING, unrecognized value of credit2_runqueue option!\n");
+    if ( parse_custom_runqueue_option(s) != 0 )
+    {
+        /* Resetting in case of failure, so that we don't mess-up during any 
failure
+         * due to wrong or spurious pattern passed by user.
+         */
+        opt_runqueue = OPT_RUNQUEUE_SOCKET;
+        printk("WARNING, unrecognized value of credit2_runqueue option!\n");
+    }
 }
 custom_param("credit2_runqueue", parse_credit2_runqueue);
 
@@ -662,6 +816,15 @@ cpu_to_runqueue(struct csched2_private *prv, unsigned int 
cpu)
     struct csched2_runqueue_data *rqd;
     unsigned int rqi;
 
+    if ( opt_runqueue == OPT_RUNQUEUE_CUSTOM )
+    {
+        if ( custom_cpu_runqueue[cpu] != -1 )
+        {
+            BUG_ON(custom_cpu_runqueue[cpu] >= nr_cpu_ids);
+            return custom_cpu_runqueue[cpu];
+        }
+    }
+
     for ( rqi = 0; rqi < nr_cpu_ids; rqi++ )
     {
         unsigned int peer_cpu;
-- 
2.12.0


_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxx
https://lists.xen.org/xen-devel

 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.