diff --git a/include/haproxy/cpu_topo.h b/include/haproxy/cpu_topo.h index 5271af3ec..a48fee015 100644 --- a/include/haproxy/cpu_topo.h +++ b/include/haproxy/cpu_topo.h @@ -51,10 +51,14 @@ void cpu_reorder_by_locality(struct ha_cpu_topo *topo, int entries); */ void cpu_reorder_by_index(struct ha_cpu_topo *topo, int entries); +/* re-order a CPU topology array by cluster id. */ +void cpu_reorder_by_cluster(struct ha_cpu_topo *topo, int entries); + /* Functions used by qsort to compare hardware CPUs (not meant to be used from * outside cpu_topo). */ int _cmp_cpu_index(const void *a, const void *b); int _cmp_cpu_locality(const void *a, const void *b); +int _cmp_cpu_cluster(const void *a, const void *b); #endif /* _HAPROXY_CPU_TOPO_H */ diff --git a/src/cpu_topo.c b/src/cpu_topo.c index d0bf266e5..b464f09d7 100644 --- a/src/cpu_topo.c +++ b/src/cpu_topo.c @@ -322,6 +322,62 @@ int _cmp_cpu_locality(const void *a, const void *b) return 0; } +/* function used by qsort to compare two hwcpus and arrange them by cluster to + * make sure no cluster crosses L3 boundaries. -1 says ab. It's + * only used during topology detection. + */ +int _cmp_cpu_cluster(const void *a, const void *b) +{ + const struct ha_cpu_topo *l = (const struct ha_cpu_topo *)a; + const struct ha_cpu_topo *r = (const struct ha_cpu_topo *)b; + + /* first, online vs offline */ + if (!(l->st & HA_CPU_F_EXCL_MASK) && (r->st & HA_CPU_F_EXCL_MASK)) + return -1; + + if (!(r->st & HA_CPU_F_EXCL_MASK) && (l->st & HA_CPU_F_EXCL_MASK)) + return 1; + + /* next, cluster */ + if (l->cl_gid >= 0 && l->cl_gid < r->cl_gid) + return -1; + if (l->cl_gid > r->cl_gid && r->cl_gid >= 0) + return 1; + + /* next, package ID */ + if (l->pk_id >= 0 && l->pk_id < r->pk_id) + return -1; + if (l->pk_id > r->pk_id && r->pk_id >= 0) + return 1; + + /* next, node ID */ + if (l->no_id >= 0 && l->no_id < r->no_id) + return -1; + if (l->no_id > r->no_id && r->no_id >= 0) + return 1; + + /* next, L3 */ + if (l->ca_id[3] >= 0 && l->ca_id[3] < r->ca_id[3]) + return -1; + if (l->ca_id[3] > r->ca_id[3] && r->ca_id[3] >= 0) + return 1; + + /* if no L3, then L2 */ + if (l->ca_id[2] >= 0 && l->ca_id[2] < r->ca_id[2]) + return -1; + if (l->ca_id[2] > r->ca_id[2] && r->ca_id[2] >= 0) + return 1; + + /* next, IDX, so that SMT ordering is preserved */ + if (l->idx >= 0 && l->idx < r->idx) + return -1; + if (l->idx > r->idx && r->idx >= 0) + return 1; + + /* exactly the same (e.g. absent) */ + return 0; +} + /* re-order a CPU topology array by CPU index only. This is mostly used before * listing CPUs regardless of their characteristics. */ @@ -336,6 +392,12 @@ void cpu_reorder_by_locality(struct ha_cpu_topo *topo, int entries) qsort(topo, entries, sizeof(*topo), _cmp_cpu_locality); } +/* re-order a CPU topology array by cluster id. */ +void cpu_reorder_by_cluster(struct ha_cpu_topo *topo, int entries) +{ + qsort(topo, entries, sizeof(*topo), _cmp_cpu_cluster); +} + /* returns an optimal maxcpus for the current system. It will take into * account what is reported by the OS, if any, otherwise will fall back * to the cpuset size, which serves as an upper limit in any case.