]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
MINOR: cpu-topo: boost the capacity of performance cores with cpufreq
authorWilly Tarreau <w@1wt.eu>
Fri, 14 Mar 2025 16:06:00 +0000 (17:06 +0100)
committerWilly Tarreau <w@1wt.eu>
Fri, 14 Mar 2025 17:30:30 +0000 (18:30 +0100)
Cpufreq alone isn't a good metric on heterogenous CPUs because efficient
cores can reach almost as high frequencies as performant ones. Tests have
shown that majoring performance cores by 50% gives a pretty accurate
estimate of the performance to expect on modern CPUs, and that counting
+33% per extra SMT thread is reasonable as well. We don't have the info
about the core's quality, but using the presence of SMT is a reasonable
approach in this case, given that efficiency cores will not use it.

As an example, using one thread of each of the 8 P-cores of an intel
i9-14900k gives 395k rps for a corrected total capacity of 69.3k, using
the 16 E-cores gives 40.5k for a total capacity of 70.4k, and using both
threads of 6 P-cores gives 41.1k for a total capacity of 69.6k. Thus the
3 same scores deliver the same performance in various combinations.

src/cpu_topo.c

index 3a7253e51c966ab4c05dc3f71025b600817381e3..d59c0c888814685cdc87ef93f0a6a41435ec044f 100644 (file)
@@ -419,13 +419,20 @@ int cpu_detect_topology(void)
                 * start just due to this. Thus we start with cpufreq and fall
                 * back to acpi_cppc. If it becomes an issue, we could imagine
                 * forcing the value to all members of the same core and even
-                * cluster.
+                * cluster. Since the frequency alone is not a good criterion
+                * to qualify the CPU quality (perf vs efficiency core), instead
+                * we rely on the thread count to gauge if it's a performant or
+                * an efficient core, and we major performant cores' capacity
+                * by 50% (shown to be roughly correct on modern CPUs).
                 */
                if (ha_cpu_topo[cpu].capa < 0 &&
                    read_line_to_trash(NUMA_DETECT_SYSTEM_SYSFS_PATH "/cpu/cpu%d/cpufreq/scaling_max_freq", cpu) >= 0) {
                        /* This is in kHz, turn it to MHz to stay below 32k */
-                       if (trash.data)
+                       if (trash.data) {
                                ha_cpu_topo[cpu].capa = (str2uic(trash.area) + 999U) / 1000U;
+                               if (ha_cpu_topo[cpu].th_cnt > 1)
+                                       ha_cpu_topo[cpu].capa = ha_cpu_topo[cpu].capa * 3 / 2;
+                       }
                }
 
                if (ha_cpu_topo[cpu].capa < 0 &&