Skip to content

Commit 87ae610

Browse files
Pavankumar KondetiExactExampl
authored andcommitted
sched/walt: Fix stale max_capacity issue during CPU hotplug
Scheduler keeps track of the maximum capacity among all online CPUs in max_capacity. This is useful in checking if a given cluster/CPU is a max capacity CPU or not. The capacity of a CPU gets updated when its max frequency is limited by cpufreq and/or thermal. The CPUfreq limits notifications are received via CPUfreq policy notifier. However CPUfreq keeps the policy intact even when all of the CPUs governed by the policy are hotplugged out. So the CPUFREQ_REMOVE_POLICY notification never arrives and scheduler's notion of max_capacity becomes stale. The max_capacity may get corrected at some point later when CPUFREQ_NOTIFY notification comes for other online CPUs. But when the hotplugged CPUs comes online the max_capacity does not reflect since CPUFREQ_ADD_POLICY is not sent by the cpufreq. For example consider a system with 4 BIG and 4 little CPUs. Their original capacities are 2048 and 1024 respectively. The max_capacity points to 2048 when all CPUs are online. Now, 1. All 4 BIG CPUs are hotplugged out. Since there is no notification, the max_capacity still points to 2048, which is incorrect. 2. User clips the little CPUs's max_freq by 50%. CPUFREQ_NOTIFY arrives and max_capacity is updated by iterating all the online CPUs. At this point max_capacity becomes 512 which is correct. 3. User removes the above limits of little CPUs. The max_capacity becomes 1024 which is correct. 4. Now, BIG CPUs are hotplugged in. Since there is no notification, the max_capacity still points to 1024, which is incorrect. Fix this issue by wiring the max_capacity updates in WALT to scheduler hotplug callbacks. Ideally we want cpufreq domain hotplug callbacks but such notifiers are not present. So the max_capacity update is forced even when it is not necessary but that should not be a concern. Because CPU hotplug is supposed to be a rare event. The scheduler hotplug callbacks happen even before the hotplug CPU is removed from cpu_online_mask, so use cpu_active() check while evaluating the max_capacity. Since cpu_active_mask is a subset of cpu_online_mask, this is sufficient. Change-Id: I97b1974e2de1a9730285715858f1ada416d92a7a Signed-off-by: Pavankumar Kondeti <pkondeti@codeaurora.org> (cherry picked from commit 3cd81b52aedf6802aaf7b41f3550b1850c7a09a4)
1 parent 2ab58ea commit 87ae610

3 files changed

Lines changed: 11 additions & 3 deletions

File tree

kernel/sched/core.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8057,6 +8057,7 @@ int sched_cpu_activate(unsigned int cpu)
80578057
raw_spin_unlock_irqrestore(&rq->lock, flags);
80588058

80598059
update_max_interval();
8060+
walt_update_min_max_capacity();
80608061

80618062
return 0;
80628063
}
@@ -8098,6 +8099,7 @@ int sched_cpu_deactivate(unsigned int cpu)
80988099
return ret;
80998100
}
81008101
sched_domains_numa_masks_clear(cpu);
8102+
walt_update_min_max_capacity();
81018103
return 0;
81028104
}
81038105

kernel/sched/sched.h

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2513,7 +2513,11 @@ static inline void __update_min_max_capacity(void)
25132513
int i;
25142514
int max_cap = 0, min_cap = INT_MAX;
25152515

2516-
for_each_online_cpu(i) {
2516+
for_each_possible_cpu(i) {
2517+
2518+
if (!cpu_active(i))
2519+
continue;
2520+
25172521
max_cap = max(max_cap, cpu_capacity(i));
25182522
min_cap = min(min_cap, cpu_capacity(i));
25192523
}
@@ -2778,6 +2782,7 @@ static inline unsigned int power_cost(int cpu, bool max)
27782782
}
27792783

27802784
extern void walt_sched_energy_populated_callback(void);
2785+
extern void walt_update_min_max_capacity(void);
27812786

27822787
#else /* CONFIG_SCHED_WALT */
27832788

@@ -2911,6 +2916,7 @@ static inline unsigned int power_cost(int cpu, bool max)
29112916
}
29122917

29132918
static inline void walt_sched_energy_populated_callback(void) { }
2919+
static inline void walt_update_min_max_capacity(void) { }
29142920

29152921
#endif /* CONFIG_SCHED_WALT */
29162922

kernel/sched/walt.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2150,7 +2150,7 @@ static int compute_max_possible_capacity(struct sched_cluster *cluster)
21502150
return capacity;
21512151
}
21522152

2153-
static void update_min_max_capacity(void)
2153+
void walt_update_min_max_capacity(void)
21542154
{
21552155
unsigned long flags;
21562156

@@ -2376,7 +2376,7 @@ static int cpufreq_notifier_policy(struct notifier_block *nb,
23762376
return 0;
23772377

23782378
if (val == CPUFREQ_REMOVE_POLICY || val == CPUFREQ_CREATE_POLICY) {
2379-
update_min_max_capacity();
2379+
walt_update_min_max_capacity();
23802380
return 0;
23812381
}
23822382

0 commit comments

Comments
 (0)