diff --git a/doc/configuration.txt b/doc/configuration.txt index 8305515d9..664c05dfa 100644 --- a/doc/configuration.txt +++ b/doc/configuration.txt @@ -657,7 +657,7 @@ chroot with superuser privileges. It is important to ensure that is both empty and unwritable to anyone. -cpu-map <"all"|"odd"|"even"|process_num[-process_num]> ... +cpu-map [auto:]<"all"|"odd"|"even"|process_num[-process_num]> ... On Linux 2.6 and above, it is possible to bind a process to a specific CPU set. This means that the process will never run on other CPUs. The "cpu-map" directive specifies CPU sets for process sets. The first argument is the @@ -673,6 +673,28 @@ cpu-map <"all"|"odd"|"even"|process_num[-process_num]> ... of them. Obviously, multiple "cpu-map" directives may be specified. Each "cpu-map" directive will replace the previous ones when they overlap. + The prefix "auto:" can be added before the process set to let HAProxy + automatically bind a process to a CPU by incrementing process and CPU + sets. To be valid, both sets must have the same size. No matter the + declaration order of the CPU sets, it will be bound from the lower to the + higher bound. + + Examples: + # all these lines bind the process 1 to the cpu 0, the process 2 to cpu 1 + # and so on. + cpu-map auto:1-4 0-3 + cpu-map auto:1-4 0-1 2-3 + cpu-map auto:1-4 3 2 1 0 + + # bind each process to exaclty one CPU using all/odd/even keyword + cpu-map auto:all 0-63 + cpu-map auto:even 0-31 + cpu-map auto:odd 32-63 + + # invalid cpu-map because process and CPU sets have different sizes. + cpu-map auto:1-4 0 # invalid + cpu-map auto:1 0-3 # invalid + crt-base Assigns a default directory to fetch SSL certificates from when a relative path is used with "crtfile" directives. Absolute locations specified after diff --git a/include/common/cfgparse.h b/include/common/cfgparse.h index 7332bd53a..1ce7251e8 100644 --- a/include/common/cfgparse.h +++ b/include/common/cfgparse.h @@ -86,7 +86,7 @@ int too_many_args_idx(int maxarg, int index, char **args, char **msg, int *err_c int too_many_args(int maxarg, char **args, char **msg, int *err_code); int alertif_too_many_args_idx(int maxarg, int index, const char *file, int linenum, char **args, int *err_code); int alertif_too_many_args(int maxarg, const char *file, int linenum, char **args, int *err_code); -int parse_process_number(const char *arg, unsigned long *proc, char **err); +int parse_process_number(const char *arg, unsigned long *proc, int *autoinc, char **err); /* * Sends a warning if proxy does not have at least one of the diff --git a/src/cfgparse.c b/src/cfgparse.c index d4cfa8641..a7d575305 100644 --- a/src/cfgparse.c +++ b/src/cfgparse.c @@ -596,8 +596,16 @@ static int warnif_cond_conflicts(const struct acl_cond *cond, unsigned int where * Note: this function can also be used to parse a thread number or a set of * threads. */ -int parse_process_number(const char *arg, unsigned long *proc, char **err) +int parse_process_number(const char *arg, unsigned long *proc, int *autoinc, char **err) { + if (autoinc) { + *autoinc = 0; + if (strncmp(arg, "auto:", 5) == 0) { + arg += 5; + *autoinc = 1; + } + } + if (strcmp(arg, "all") == 0) *proc |= ~0UL; else if (strcmp(arg, "odd") == 0) @@ -1698,7 +1706,7 @@ int cfg_parse_global(const char *file, int linenum, char **args, int kwm) /* map a process list to a CPU set */ #ifdef USE_CPU_AFFINITY unsigned long proc = 0, cpus; - int i; + int i, n, autoinc; if (!*args[1] || !*args[2]) { Alert("parsing [%s:%d] : %s expects a process number " @@ -1709,7 +1717,7 @@ int cfg_parse_global(const char *file, int linenum, char **args, int kwm) goto out; } - if (parse_process_number(args[1], &proc, &errmsg)) { + if (parse_process_number(args[1], &proc, &autoinc, &errmsg)) { Alert("parsing [%s:%d] : %s : %s\n", file, linenum, args[0], errmsg); err_code |= ERR_ALERT | ERR_FATAL; goto out; @@ -1720,9 +1728,23 @@ int cfg_parse_global(const char *file, int linenum, char **args, int kwm) err_code |= ERR_ALERT | ERR_FATAL; goto out; } - for (i = 0; i < LONGBITS; i++) - if (proc & (1UL << i)) - global.cpu_map[i] = cpus; + + if (autoinc && my_popcountl(proc) != my_popcountl(cpus)) { + Alert("parsing [%s:%d] : %s : PROC range and CPU sets must have the same size to be auto-assigned\n", + file, linenum, args[0]); + err_code |= ERR_ALERT | ERR_FATAL; + goto out; + } + for (i = n = 0; i < LONGBITS; i++) { + if (proc & (1UL << i)) { + if (autoinc) { + n += my_ffsl(cpus >> n); + global.cpu_map[i] = (1UL << (n-1)); + } + else + global.cpu_map[i] = cpus; + } + } #else Alert("parsing [%s:%d] : '%s' is not enabled, please check build options for USE_CPU_AFFINITY.\n", file, linenum, args[0]); @@ -1747,12 +1769,12 @@ int cfg_parse_global(const char *file, int linenum, char **args, int kwm) goto out; } - if (parse_process_number(args[1], &proc, &errmsg)) { + if (parse_process_number(args[1], &proc, NULL, &errmsg)) { Alert("parsing [%s:%d] : %s : %s\n", file, linenum, args[0], errmsg); err_code |= ERR_ALERT | ERR_FATAL; goto out; } - if (parse_process_number(args[2], &thread, &errmsg)) { + if (parse_process_number(args[2], &thread, NULL, &errmsg)) { Alert("parsing [%s:%d] : %s : %s\n", file, linenum, args[0], errmsg); err_code |= ERR_ALERT | ERR_FATAL; goto out; @@ -3287,7 +3309,7 @@ int cfg_parse_listen(const char *file, int linenum, char **args, int kwm) set = 0; break; } - if (parse_process_number(args[cur_arg], &set, &errmsg)) { + if (parse_process_number(args[cur_arg], &set, NULL, &errmsg)) { Alert("parsing [%s:%d] : %s : %s\n", file, linenum, args[0], errmsg); err_code |= ERR_ALERT | ERR_FATAL; goto out; diff --git a/src/cli.c b/src/cli.c index 05cc15e1d..038bdd383 100644 --- a/src/cli.c +++ b/src/cli.c @@ -327,7 +327,7 @@ static int stats_parse_global(char **args, int section_type, struct proxy *curpx set = 0; break; } - if (parse_process_number(args[cur_arg], &set, err)) { + if (parse_process_number(args[cur_arg], &set, NULL, err)) { memprintf(err, "'%s %s' : %s", args[0], args[1], *err); return -1; } diff --git a/src/listener.c b/src/listener.c index a06a464f0..c82ba36e0 100644 --- a/src/listener.c +++ b/src/listener.c @@ -943,7 +943,7 @@ static int bind_parse_process(char **args, int cur_arg, struct proxy *px, struct { unsigned long set = 0; - if (parse_process_number(args[cur_arg + 1], &set, err)) { + if (parse_process_number(args[cur_arg + 1], &set, NULL, err)) { memprintf(err, "'%s' : %s", args[cur_arg], *err); return ERR_ALERT | ERR_FATAL; }