mirror of
https://git.haproxy.org/git/haproxy.git/
synced 2026-05-04 12:41:00 +02:00
MINOR: cpu-topo: add a new "efficiency" cpu-policy
This cpu policy tries to evict performant core clusters and only focuses on efficiency-oriented ones. On an intel i9-14900k, we can get 525k rps using 8 performance cores, versus 405k when using all 24 efficiency cores. In some cases the power savings might be more desirable (e.g. scalability tests on a developer's laptop), or the performance cores might be better suited for another component (application or security component).
This commit is contained in:
parent
dcae2fa4a4
commit
ad3650c354
@ -1972,6 +1972,18 @@ cpu-policy <policy>
|
||||
systems, per thread-group. The number of thread-groups,
|
||||
if not set, will be set to 1.
|
||||
|
||||
- efficiency exactly like group-by-cluster below, except that CPU
|
||||
clusters whose performance is more than twice that of
|
||||
the next less performant one are evicted. These are
|
||||
typically "big" or "performance" cores. This means that
|
||||
if more than one type of CPU cores are detected, only
|
||||
the efficient one will be used. This can make sense for
|
||||
use with moderate loads when the most powerful cores
|
||||
need to be available to the application or a security
|
||||
component. Some modern CPUs have a large number of such
|
||||
efficient CPU cores which can collectively deliver a
|
||||
decent level of performance while using less power.
|
||||
|
||||
- first-usable-node if the CPUs were not previously restricted at boot (for
|
||||
example using the "taskset" utility), and if the
|
||||
"nbthread" directive was not set, then the first NUMA
|
||||
|
||||
@ -54,12 +54,14 @@ static int cpu_policy = 1; // "first-usable-node"
|
||||
static int cpu_policy_first_usable_node(int policy, int tmin, int tmax, int gmin, int gmax, char **err);
|
||||
static int cpu_policy_group_by_cluster(int policy, int tmin, int tmax, int gmin, int gmax, char **err);
|
||||
static int cpu_policy_performance(int policy, int tmin, int tmax, int gmin, int gmax, char **err);
|
||||
static int cpu_policy_efficiency(int policy, int tmin, int tmax, int gmin, int gmax, char **err);
|
||||
|
||||
static struct ha_cpu_policy ha_cpu_policy[] = {
|
||||
{ .name = "none", .desc = "use all available CPUs", .fct = NULL },
|
||||
{ .name = "first-usable-node", .desc = "use only first usable node if nbthreads not set", .fct = cpu_policy_first_usable_node },
|
||||
{ .name = "group-by-cluster", .desc = "make one thread group per core cluster", .fct = cpu_policy_group_by_cluster },
|
||||
{ .name = "performance", .desc = "make one thread group per perf. core cluster", .fct = cpu_policy_performance },
|
||||
{ .name = "efficiency", .desc = "make one thread group per eff. core cluster", .fct = cpu_policy_efficiency },
|
||||
{ 0 } /* end */
|
||||
};
|
||||
|
||||
@ -1135,6 +1137,45 @@ static int cpu_policy_performance(int policy, int tmin, int tmax, int gmin, int
|
||||
return cpu_policy_group_by_cluster(policy, tmin, tmax, gmin, gmax, err);
|
||||
}
|
||||
|
||||
/* the "efficiency" cpu-policy:
|
||||
* - does nothing if nbthread or thread-groups are set
|
||||
* - eliminates clusters whose total capacity is above half of others
|
||||
* - tries to create one thread-group per cluster, with as many
|
||||
* threads as CPUs in the cluster, and bind all the threads of
|
||||
* this group to all the CPUs of the cluster.
|
||||
*/
|
||||
static int cpu_policy_efficiency(int policy, int tmin, int tmax, int gmin, int gmax, char **err)
|
||||
{
|
||||
int cpu, cluster;
|
||||
int capa;
|
||||
|
||||
if (global.nbthread || global.nbtgroups)
|
||||
return 0;
|
||||
|
||||
/* sort clusters by reverse capacity */
|
||||
cpu_cluster_reorder_by_capa(ha_cpu_clusters, cpu_topo_maxcpus);
|
||||
|
||||
capa = 0;
|
||||
for (cluster = cpu_topo_maxcpus - 1; cluster >= 0; cluster--) {
|
||||
if (capa && ha_cpu_clusters[cluster].capa > capa * 2) {
|
||||
/* This cluster is more than twice as fast as the
|
||||
* previous one, we're not interested in using it.
|
||||
*/
|
||||
for (cpu = 0; cpu <= cpu_topo_lastcpu; cpu++) {
|
||||
if (ha_cpu_topo[cpu].cl_gid == ha_cpu_clusters[cluster].idx)
|
||||
ha_cpu_topo[cpu].st |= HA_CPU_F_IGNORED;
|
||||
}
|
||||
}
|
||||
else
|
||||
capa = ha_cpu_clusters[cluster].capa;
|
||||
}
|
||||
|
||||
cpu_cluster_reorder_by_index(ha_cpu_clusters, cpu_topo_maxcpus);
|
||||
|
||||
/* and finish using the group-by-cluster strategy */
|
||||
return cpu_policy_group_by_cluster(policy, tmin, tmax, gmin, gmax, err);
|
||||
}
|
||||
|
||||
/* apply the chosen CPU policy if no cpu-map was forced. Returns < 0 on failure
|
||||
* with a message in *err that must be freed by the caller if non-null.
|
||||
*/
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user