Skip to content

Commit d4f198c

Browse files
Frederic WeisbeckerThomas Gleixner
authored andcommitted
timers/migration: Deactivate per-capacity hierarchies under nohz_full
NOHZ_FULL CPUs global timers are guaranteed to be handled by the timekeeper CPU, which never stops its tick and therefore remains active in the hierarchy. But since the introduction of per-capacity hierarchies, this guarantee is broken because the timekeeper may not belong to the same hierarchy as all the NOHZ_FULL CPUs. Fix it with simply turning off capacity awareness when NOHZ_FULL is running and force a single hierarchy. NOHZ_FULL is not exactly optimized powerwise anyway. Fixes: 098cbaa ("timers/migration: Split per-capacity hierarchies") Signed-off-by: Frederic Weisbecker <frederic@kernel.org> Signed-off-by: Thomas Gleixner <tglx@kernel.org> Link: https://patch.msgid.link/20260519220926.63437-3-frederic@kernel.org
1 parent e4a70f5 commit d4f198c

1 file changed

Lines changed: 23 additions & 7 deletions

File tree

kernel/time/timer_migration.c

Lines changed: 23 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1464,8 +1464,24 @@ static long tmigr_trigger_active(void *unused)
14641464
return 0;
14651465
}
14661466

1467-
static struct tmigr_hierarchy *__tmigr_get_hierarchy(unsigned int capacity)
1467+
static unsigned int tmigr_get_capacity(int cpu)
14681468
{
1469+
/*
1470+
* nohz_full CPUs need to make sure there is always an available (online)
1471+
* and never idle migrator to handle all their global timers. That duty
1472+
* is served by the timekeeper which then never stops its tick. But the
1473+
* timekeeper must then belong to the same hierarchy as all the nohz_full
1474+
* CPUs. Simply turn off capacity awareness when nohz_full is running.
1475+
*/
1476+
if (tick_nohz_full_enabled())
1477+
return SCHED_CAPACITY_SCALE;
1478+
else
1479+
return arch_scale_cpu_capacity(cpu);
1480+
}
1481+
1482+
static struct tmigr_hierarchy *__tmigr_get_hierarchy(int cpu)
1483+
{
1484+
unsigned int capacity = tmigr_get_capacity(cpu);
14691485
struct tmigr_hierarchy *iter;
14701486

14711487
list_for_each_entry(iter, &tmigr_hierarchy_list, node) {
@@ -1500,7 +1516,7 @@ static int tmigr_clear_cpu_available(unsigned int cpu)
15001516
}
15011517

15021518
if (firstexp != KTIME_MAX) {
1503-
struct tmigr_hierarchy *hier = __tmigr_get_hierarchy(arch_scale_cpu_capacity(cpu));
1519+
struct tmigr_hierarchy *hier = __tmigr_get_hierarchy(cpu);
15041520

15051521
if (WARN_ON_ONCE(!hier))
15061522
return -EINVAL;
@@ -1938,11 +1954,11 @@ static int tmigr_setup_groups(struct tmigr_hierarchy *hier, unsigned int cpu,
19381954
return err;
19391955
}
19401956

1941-
static struct tmigr_hierarchy *tmigr_get_hierarchy(unsigned int capacity)
1957+
static struct tmigr_hierarchy *tmigr_get_hierarchy(int cpu)
19421958
{
19431959
struct tmigr_hierarchy *hier;
19441960

1945-
hier = __tmigr_get_hierarchy(capacity);
1961+
hier = __tmigr_get_hierarchy(cpu);
19461962

19471963
if (hier)
19481964
return hier;
@@ -1962,7 +1978,7 @@ static struct tmigr_hierarchy *tmigr_get_hierarchy(unsigned int capacity)
19621978
for (int i = 0; i < tmigr_hierarchy_levels; i++)
19631979
INIT_LIST_HEAD(&hier->level_list[i]);
19641980

1965-
hier->capacity = capacity;
1981+
hier->capacity = tmigr_get_capacity(cpu);
19661982
list_add_tail(&hier->node, &tmigr_hierarchy_list);
19671983

19681984
return hier;
@@ -2000,7 +2016,7 @@ static long connect_old_root_work(void *arg)
20002016
struct tmigr_hierarchy *hier;
20012017
int cpu = smp_processor_id();
20022018

2003-
hier = __tmigr_get_hierarchy(arch_scale_cpu_capacity(cpu));
2019+
hier = __tmigr_get_hierarchy(cpu);
20042020
if (WARN_ON_ONCE(!hier))
20052021
return -EINVAL;
20062022

@@ -2016,7 +2032,7 @@ static int tmigr_add_cpu(unsigned int cpu)
20162032

20172033
guard(mutex)(&tmigr_mutex);
20182034

2019-
hier = tmigr_get_hierarchy(arch_scale_cpu_capacity(cpu));
2035+
hier = tmigr_get_hierarchy(cpu);
20202036
if (IS_ERR(hier))
20212037
return PTR_ERR(hier);
20222038

0 commit comments

Comments
 (0)