#define CPU_AFFINITY_PER_GROUP (1 << 0)
#define CPU_AFFINITY_PER_CORE (1 << 1)
#define CPU_AFFINITY_PER_THREAD (1 << 2)
+#define CPU_AFFINITY_PER_CCX (1 << 3)
/* CPU topology information, ha_cpuset_size() entries, allocated at boot */
int cpu_topo_maxcpus = -1; // max number of CPUs supported by OS/haproxy
{"per-core", CPU_AFFINITY_PER_CORE},
{"per-group", CPU_AFFINITY_PER_GROUP},
{"per-thread", CPU_AFFINITY_PER_THREAD},
+ {"per-ccx", CPU_AFFINITY_PER_CCX},
{"auto", 0},
{NULL, 0}
};
return -1;
}
+static int find_next_cpu_ccx(int start, int l3id)
+{
+ int cpu;
+
+ for (cpu = start; cpu <= cpu_topo_lastcpu; cpu++)
+ if (ha_cpu_topo[cpu].ca_id[3] == l3id)
+ return cpu;
+
+ return -1;
+}
+
/* the "first-usable-node" cpu-policy: historical one
* - does nothing if numa_cpu_mapping is not set
* - does nothing if nbthread is set
{
struct hap_cpuset node_cpu_set;
struct hap_cpuset visited_tsid;
+ struct hap_cpuset visited_ccx;
int first_node_id = -1;
int second_node_id = -1;
int cpu;
*/
ha_cpuset_zero(&node_cpu_set);
ha_cpuset_zero(&visited_tsid);
+ ha_cpuset_zero(&visited_ccx);
for (cpu = cpu_count = 0; cpu <= cpu_topo_lastcpu; cpu++) {
if (ha_cpu_topo[cpu].no_id != first_node_id)
ha_cpu_topo[cpu].st |= HA_CPU_F_IGNORED;
ha_cpuset_set(&node_cpu_set, ha_cpu_topo[cpu].idx);
cpu_count++;
+ ha_cpuset_set(&visited_ccx, ha_cpu_topo[cpu].ca_id[3]);
if (!(cpu_policy_conf.flags & CPU_POLICY_ONE_THREAD_PER_CORE) || !ha_cpuset_isset(&visited_tsid, ha_cpu_topo[cpu].ts_id)) {
ha_cpuset_set(&visited_tsid, ha_cpu_topo[cpu].ts_id);
thr_count++;
if (got_cpu != -1) {
ha_cpuset_set(&thrset, ha_cpu_topo[got_cpu].idx);
- ha_cpuset_clr(&thrset, ha_cpu_topo[got_cpu].idx);
}
+ ha_cpuset_clr(&visited_tsid, tsid);
} else {
int tid = ha_cpuset_ffs(&node_cpu_set) - 1;
if (ha_cpuset_ffs(&thrset) != 0)
ha_cpuset_assign(&cpu_map[0].thread[thr], &thrset);
}
+ } else if (cpu_policy_conf.affinity & CPU_AFFINITY_PER_CCX) {
+ struct hap_cpuset thrset;
+ int same_ccx = 0;
+
+ for (thr = 0; thr < thr_count; thr++) {
+ int got_cpu;
+ int next_try = 0;
+
+ if (same_ccx == 0) {
+ int l3id = ha_cpuset_ffs(&visited_ccx) - 1;
+ ha_cpuset_zero(&thrset);
+ while ((got_cpu = find_next_cpu_ccx(next_try, l3id)) != -1) {
+ next_try = got_cpu + 1;
+ same_ccx++;
+ ha_cpuset_set(&thrset, ha_cpu_topo[got_cpu].idx);
+ }
+ ha_cpuset_clr(&visited_ccx, l3id);
+ }
+ BUG_ON(same_ccx == 0);
+ if (ha_cpuset_ffs(&thrset) != 0)
+ ha_cpuset_assign(&cpu_map[0].thread[thr], &thrset);
+ same_ccx--;
+ }
} else {
/* assign all threads of all thread groups to this node */
struct hap_cpuset visited_cl_set;
struct hap_cpuset node_cpu_set;
struct hap_cpuset visited_tsid;
+ struct hap_cpuset visited_ccx;
struct hap_cpuset thrset;
int cpu, cpu_start;
int cpu_count;
while (global.nbtgroups < MAX_TGROUPS && global.nbthread < MAX_THREADS) {
ha_cpuset_zero(&node_cpu_set);
ha_cpuset_zero(&visited_tsid);
+ ha_cpuset_zero(&visited_ccx);
cid = -1; cpu_count = 0;
for (cpu = cpu_start; cpu <= cpu_topo_lastcpu; cpu++) {
/* make a mask of all of this cluster's CPUs */
ha_cpuset_set(&node_cpu_set, ha_cpu_topo[cpu].idx);
+ ha_cpuset_set(&visited_ccx, ha_cpu_topo[cpu].ca_id[3]);
if (!ha_cpuset_isset(&visited_tsid, ha_cpu_topo[cpu].ts_id)) {
cpu_count++;
ha_cpuset_set(&visited_tsid, ha_cpu_topo[cpu].ts_id);
if (ha_cpuset_ffs(&thrset) != 0)
ha_cpuset_assign(&cpu_map[global.nbtgroups].thread[thr], &thrset);
+ } else if (cpu_policy_conf.affinity & CPU_AFFINITY_PER_CCX) {
+ if (same_core == 0) {
+ int l3id = ha_cpuset_ffs(&visited_ccx) - 1;
+ int got_cpu;
+ int next_try = 0;
+ ha_cpuset_zero(&thrset);
+
+ while ((got_cpu = find_next_cpu_ccx(next_try, l3id)) != -1) {
+ next_try = got_cpu + 1;
+ same_core++;
+ ha_cpuset_set(&thrset, ha_cpu_topo[got_cpu].idx);
+ }
+ ha_cpuset_clr(&visited_ccx, l3id);
+ }
+ BUG_ON(same_core == 0);
+ if (ha_cpuset_ffs(&thrset) != 0)
+ ha_cpuset_assign(&cpu_map[global.nbtgroups].thread[thr], &thrset);
+ same_core--;
} else {
/* map these threads to all the CPUs */
ha_cpuset_assign(&cpu_map[global.nbtgroups].thread[thr], &node_cpu_set);
struct hap_cpuset visited_ccx_set;
struct hap_cpuset node_cpu_set;
struct hap_cpuset visited_tsid;
+ struct hap_cpuset visited_ccx; /* List of CCXs we'll currently use */
struct hap_cpuset thrset;
int cpu, cpu_start;
int cpu_count;
/* make a mask of all of this cluster's CPUs */
ha_cpuset_set(&node_cpu_set, ha_cpu_topo[cpu].idx);
+ ha_cpuset_set(&visited_ccx, ha_cpu_topo[cpu].ca_id[3]);
if (!ha_cpuset_isset(&visited_tsid, ha_cpu_topo[cpu].ts_id)) {
cpu_count++;
ha_cpuset_set(&visited_tsid, ha_cpu_topo[cpu].ts_id);
if (ha_cpuset_ffs(&thrset) != 0)
ha_cpuset_assign(&cpu_map[global.nbtgroups].thread[thr], &thrset);
+ } else if (cpu_policy_conf.affinity & CPU_AFFINITY_PER_CCX) {
+ if (same_core == 0) {
+ int l3id = ha_cpuset_ffs(&visited_ccx) - 1;
+ int got_cpu;
+ int next_try = 0;
+ ha_cpuset_zero(&thrset);
+ while ((got_cpu = find_next_cpu_ccx(next_try, l3id)) != -1) {
+ next_try = got_cpu + 1;
+ same_core++;
+ ha_cpuset_set(&thrset, ha_cpu_topo[got_cpu].idx);
+ }
+ ha_cpuset_clr(&visited_ccx, l3id);
+ }
+ BUG_ON(same_core == 0);
+ if (ha_cpuset_ffs(&thrset) != 0)
+ ha_cpuset_assign(&cpu_map[global.nbtgroups].thread[thr], &thrset);
+ same_core--;
} else {
/* map these threads to all the CPUs */
ha_cpuset_assign(&cpu_map[global.nbtgroups].thread[thr], &node_cpu_set);