uint nb_cpu; /* total CPUs */
};
+/* Description of a CPU selection policy. For now it only associates an option
+ * name with a callback function that is supposed to adjust the global.nbthread
+ * and global.nbtgroups based on the policy, the topology, and the constraints
+ * on the number of threads which must be between tmin and tmax included, and
+ * the number of thread groups which must be between gmin and gmax included.
+ * The callback also takes the policy number (cpu_policy) and a pointer to a
+ * string to write an error to in case of failure (in which case ret must be
+ * < 0 and the caller will fre the location). More settings might come later.
+ */
+struct ha_cpu_policy {
+ const char *name; /* option name in the configuration */
+ const char *desc; /* short description for help messages */
+ int (*fct)(int policy, int tmin, int tmax, int gmin, int gmax, char **err);
+};
+
#endif /* _HAPROXY_CPU_TOPO_T_H */
struct hap_cpuset drop_threads;
} cpu_set_cfg;
+/* CPU policy choice */
+static int cpu_policy = 0;
+
+/* list of CPU policies for "cpu-policy". The default one is the first one. */
+static struct ha_cpu_policy ha_cpu_policy[] = {
+ { .name = "none", .desc = "use all available CPUs", .fct = NULL },
+ { 0 } /* end */
+};
+
/* Detects CPUs that are online on the system. It may rely on FS access (e.g.
* /sys on Linux). Returns the number of CPUs detected or 0 if the detection
* failed.
}
}
+/* apply the chosen CPU policy if no cpu-map was forced. Returns < 0 on failure
+ * with a message in *err that must be freed by the caller if non-null.
+ */
+int cpu_apply_policy(int tmin, int tmax, int gmin, int gmax, char **err)
+{
+ *err = NULL;
+
+ if (cpu_map_configured()) {
+ /* nothing to do */
+ return 0;
+ }
+
+ if (!ha_cpu_policy[cpu_policy].fct) {
+ /* nothing to do */
+ return 0;
+ }
+
+ if (ha_cpu_policy[cpu_policy].fct(cpu_policy, tmin, tmax, gmin, gmax, err) < 0)
+ return -1;
+
+ return 0;
+}
+
/* CPU topology detection below, OS-specific */
#if defined(__linux__)
return -1;
}
+/* Parse the "cpu-policy" global directive, which takes the name of one of the
+ * ha_cpu_policy[] names, and sets the associated index in cpu_policy.
+ */
+static int cfg_parse_cpu_policy(char **args, int section_type, struct proxy *curpx,
+ const struct proxy *defpx, const char *file, int line,
+ char **err)
+{
+ int i;
+
+ if (too_many_args(1, args, err, NULL))
+ return -1;
+
+ for (i = 0; ha_cpu_policy[i].name; i++) {
+ if (strcmp(args[1], ha_cpu_policy[i].name) == 0) {
+ cpu_policy = i;
+ return 0;
+ }
+ }
+
+ memprintf(err, "'%s' passed an unknown CPU policy '%s'. Supported values are:", args[0], args[1]);
+ for (i = 0; ha_cpu_policy[i].name; i++) {
+ memprintf(err, "%s%s '%s' (%s)%s", *err,
+ (i > 0 && ha_cpu_policy[i+1].name) ? "" : " and",
+ ha_cpu_policy[i].name,
+ ha_cpu_policy[i].desc,
+ (ha_cpu_policy[i+1].name) ? "," : ".\n");
+ }
+ return -1;
+}
+
/* Allocates everything needed to store CPU topology at boot.
* Returns non-zero on success, zero on failure.
*/
/* config keyword parsers */
static struct cfg_kw_list cfg_kws = {ILH, {
+ { CFG_GLOBAL, "cpu-policy", cfg_parse_cpu_policy, 0 },
{ CFG_GLOBAL, "cpu-set", cfg_parse_cpu_set, 0 },
{ 0, NULL, NULL }
}};
int grp_max __maybe_unused;
int cpus_avail __maybe_unused;
int cpu __maybe_unused;
+ char *err __maybe_unused;
thr_min = 1; thr_max = MAX_THREADS;
grp_min = 1; grp_max = MAX_TGROUPS;
* on the same cluster _capacity_ up to thr_max.
*/
+ if (cpu_apply_policy(thr_min, thr_max, grp_min, grp_max, &err) < 0) {
+ if (err)
+ ha_warning("cpu-policy: %s\n", err);
+ ha_free(&err);
+ return;
+ }
+
/* Let's implement here the automatic binding to the first available
* NUMA node when thread count is not set, taskset is not used and
* no cpu-map directive is present.