[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Xen-devel] [PATCH RFC 2/2] xen: credit2: flexible configuration of runqueues
The idea is to give user more flexibility to configure runqueue further. For most workloads and in most systems, using per-core means have too many small runqueues. Using per-socket is almost always better, but it may result in too few big runqueues. OPTION 1 : -------- The user can create runqueue per-cpu using Xen boot parameter like below: credit2_runqueue=cpu which would mean the following: - pCPU 0 belong to runqueue 0 - pCPU 1 belong to runqueue 1 - pCPU 2 belong to runqueue 2 and so on. OPTION 2 : -------- Further user can be allowed to say something shown below : credit2_runqueue=0,1,4,5;2,3,6,7;8,9,12,13;10,11,14,15 or (with exactly the same meaning, but a perhaps more clear syntax): credit2_runqueue=[[0,1,4,5][2,3,6,7][8,9,12,13][10,11,14,15]] which would mean the following: - pCPUs 0, 1, 4 and 5 belong to runqueue 0 - pCPUs 2, 3, 6 and 7 belong to runqueue 1 - pCPUs 8, 9, 12 and 13 belong to runqueue 2 - pCPUs 10, 11, 14 and 15 belong to runqueue 3 --- PATCH 2/2 enables to create runqueue based upon [OPTION 2]. --- RFC : Current implementation is parsing the data for below syntax. "credit2_runqueue=[[0,1,4,5][2,3,6,7][8,9,12,13][10,11,14,15]]" I am also working for simpler one as mentioned in above desciption. Sharing the patch to get further inputs over the changes. --- Signed-off-by: Praveen Kumar <kpraveen.lkml@xxxxxxxxx> --- diff --git a/xen/common/sched_credit2.c b/xen/common/sched_credit2.c index af457c1..505aa6b 100644 --- a/xen/common/sched_credit2.c +++ b/xen/common/sched_credit2.c @@ -318,6 +318,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]] + * + * 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. @@ -326,17 +336,62 @@ integer_param("credit2_balance_over", opt_overload_balance_tolerance); #define OPT_RUNQUEUE_SOCKET 1 #define OPT_RUNQUEUE_NODE 2 #define OPT_RUNQUEUE_ALL 3 +#define OPT_RUNQUEUE_CUSTOM 4 static const char *const opt_runqueue_str[] = { [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 int __read_mostly custom_cpu_runqueue[NR_CPUS]; + + +#define GETTOKEN( token, len, start, end ) \ +{ \ + char _tmp[len+1]; \ + int _i; \ + \ + safe_strcpy(_tmp, start); \ + _tmp[len] = '\0'; \ + \ + for ( _i = 0; _tmp[_i] != '\0'; _i++ ) \ + token = ( ( token * 10 ) + ( _tmp[_i] - '0' ) ); \ +} + +static inline int trim(const char *c, char *t, char elem) +{ + int l = strlen(c); + const char *x = c ; + int i = 0; + if ( !c || !t ) + return -1; + while ( *x != '\0' && i < l ) + { + if ( *x != elem ) + t[i++] = *x; + x++; + } + t[i] = '\0'; + return 0; +} + +static inline int getlen(char *start, char *end) +{ + if ( ( start ) && ( end ) && ( end > start ) ) + return end-start; + else + return -1; +} + static void parse_credit2_runqueue(const char *s) { unsigned int i; + const char *s_end = NULL; + char m[strlen(s)]; + char *_s = NULL; for ( i = 0; i < ARRAY_SIZE(opt_runqueue_str); i++ ) { @@ -346,8 +401,118 @@ 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; + + /* + * Format [[0,1,4,5][2,3,6,7][8,9,12,13][10,11,14,15]] + */ + i = 0; + + /* In case user have spaces included in the input */ + if ( trim(s, m, ' ') != 0 ) + { + printk ( "WARNING : %s[%d] trim failed.\n", __func__, __LINE__ ); + goto errReturn; + } + /* Starting to parse and get the cpu information on trimmed data */ + _s = m; + s_end = _s + strlen(_s); - printk("WARNING, unrecognized value of credit2_runqueue option!\n"); + /* The start and should always be in format of '[..]' */ + if ( ( '[' == *_s ) && ( ']' == *(s_end-1)) ) + { + char *start = NULL, *end = NULL; + int cpu_added_to_runqueue = 0; + _s++; + while ( ( _s != NULL ) && ( _s < s_end ) ) + { + char *token_sub_str = NULL; + start = strstr(_s, "["); + end = strstr(_s, "]"); + /* Validation checks for '[' and ']' to properly parse the entries + */ + if ( ( !start && !end ) || ( ( end == ( s_end -1 ) ) && start ) ) + goto errReturn; + /* Check for last entry */ + else if ( !start && ( end == ( s_end -1 ) ) ) + goto nextSet; + + /* If we have [] as entry, move to nextSet */ + if ( getlen ( start, end ) < 1 ) + goto nextSet; + + /* Start to parse the actual value */ + start++; + /* + * find token within the subset + */ + do + { + int token = 0; + int len = 0; + /* Get cpu ids separated by ',' within each set */ + token_sub_str = strpbrk(start, ","); + if ( ( !token_sub_str && start < end ) || + ( token_sub_str > end && token_sub_str > start ) ) + len = getlen(start, end); + else + len = getlen(start, token_sub_str); + + if ( len <= 0 ) + continue; + /* GETTOKEN will get return the parse and populate the cpu in + * token + */ + GETTOKEN(token, len, start , end ); + + if ( token >= nr_cpu_ids) + goto errReturn; + + /* If not set already */ + if ( custom_cpu_runqueue[token] == -1 ) + { + custom_cpu_runqueue[token] = i; + cpu_added_to_runqueue = 1; + } + else + goto errReturn; + + if ( !token_sub_str || token_sub_str > end ) + goto nextSet; + + start = ++token_sub_str; + } while ( start < end ); +nextSet: + if ( cpu_added_to_runqueue ) + { + i++; + cpu_added_to_runqueue = 0; + } + + _s = ++end; + } + opt_runqueue = OPT_RUNQUEUE_CUSTOM; + return; + } +errReturn: + /* 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 credit4_runqueue option!\n"); } custom_param("credit2_runqueue", parse_credit2_runqueue); @@ -656,6 +821,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; _______________________________________________ Xen-devel mailing list Xen-devel@xxxxxxxxxxxxx https://lists.xen.org/xen-devel
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |