MINOR: cpu-topo: implement a sorting mechanism by CPU locality

Once we've kept only the CPUs we want, the next step will be to form
groups and these ones are based on locality. Thus we'll have to sort by
locality. For now the locality is only inferred by the index. No grouping
is made at this point. For this we add the "cpu_reorder_by_locality"
function with a locality-based comparison function.
This commit is contained in:
Willy Tarreau 2025-01-08 18:56:44 +01:00
parent 18133a054d
commit a8acdbd9fd
2 changed files with 93 additions and 0 deletions

View File

@ -43,6 +43,9 @@ int cpu_map_configured(void);
*/
void cpu_dump_topology(const struct ha_cpu_topo *topo);
/* re-order a CPU topology array by locality to help form groups. */
void cpu_reorder_by_locality(struct ha_cpu_topo *topo, int entries);
/* re-order a CPU topology array by CPU index only, to undo the function above,
* in case other calls need to be made on top of this.
*/
@ -52,5 +55,6 @@ void cpu_reorder_by_index(struct ha_cpu_topo *topo, int entries);
* outside cpu_topo).
*/
int _cmp_cpu_index(const void *a, const void *b);
int _cmp_cpu_locality(const void *a, const void *b);
#endif /* _HAPROXY_CPU_TOPO_H */

View File

@ -239,6 +239,89 @@ int _cmp_cpu_index(const void *a, const void *b)
return 0;
}
/* function used by qsort to compare two hwcpus and arrange them by vicinity
* only. -1 says a<b, 1 says a>b. The goal is to arrange the closest CPUs
* together, preferring locality over performance in order to keep latency
* as low as possible, so that when picking a fixed number of threads, the
* closest ones are used in priority. It's also used to help arranging groups
* at the end.
*/
int _cmp_cpu_locality(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, 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, L4 */
if (l->ca_id[4] >= 0 && l->ca_id[4] < r->ca_id[4])
return -1;
if (l->ca_id[4] > r->ca_id[4] && r->ca_id[4] >= 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;
/* 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, 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, thread set */
if (l->ts_id >= 0 && l->ts_id < r->ts_id)
return -1;
if (l->ts_id > r->ts_id && r->ts_id >= 0)
return 1;
/* next, L1 */
if (l->ca_id[1] >= 0 && l->ca_id[1] < r->ca_id[1])
return -1;
if (l->ca_id[1] > r->ca_id[1] && r->ca_id[1] >= 0)
return 1;
/* next, L0 */
if (l->ca_id[0] >= 0 && l->ca_id[0] < r->ca_id[0])
return -1;
if (l->ca_id[0] > r->ca_id[0] && r->ca_id[0] >= 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.
*/
@ -247,6 +330,12 @@ void cpu_reorder_by_index(struct ha_cpu_topo *topo, int entries)
qsort(topo, entries, sizeof(*topo), _cmp_cpu_index);
}
/* re-order a CPU topology array by locality to help form groups. */
void cpu_reorder_by_locality(struct ha_cpu_topo *topo, int entries)
{
qsort(topo, entries, sizeof(*topo), _cmp_cpu_locality);
}
/* 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.