From a4471ea56df45bf3ea0050d035b00fc232969a38 Mon Sep 17 00:00:00 2001 From: Willy Tarreau Date: Fri, 10 Jan 2025 19:32:02 +0100 Subject: [PATCH] MINOR: cpu-topo: implement a CPU sorting mechanism by cluster ID This will be used to detect and fix incorrect setups which report the same cluster ID for multiple L3 instances. The arrangement of functions in this file is becoming a real problem. Maybe we should move all this to cpu_topo for example, and better distinguish OS-specific and generic code. --- include/haproxy/cpu_topo.h | 4 +++ src/cpu_topo.c | 62 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 66 insertions(+) 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.