Skip to content

Commit 674e754

Browse files
vireshkrafaeljw
authored andcommitted
sched: cpufreq: Allow remote cpufreq callbacks
With Android UI and benchmarks the latency of cpufreq response to certain scheduling events can become very critical. Currently, callbacks into cpufreq governors are only made from the scheduler if the target CPU of the event is the same as the current CPU. This means there are certain situations where a target CPU may not run the cpufreq governor for some time. One testcase to show this behavior is where a task starts running on CPU0, then a new task is also spawned on CPU0 by a task on CPU1. If the system is configured such that the new tasks should receive maximum demand initially, this should result in CPU0 increasing frequency immediately. But because of the above mentioned limitation though, this does not occur. This patch updates the scheduler core to call the cpufreq callbacks for remote CPUs as well. The schedutil, ondemand and conservative governors are updated to process cpufreq utilization update hooks called for remote CPUs where the remote CPU is managed by the cpufreq policy of the local CPU. The intel_pstate driver is updated to always reject remote callbacks. This is tested with couple of usecases (Android: hackbench, recentfling, galleryfling, vellamo, Ubuntu: hackbench) on ARM hikey board (64 bit octa-core, single policy). Only galleryfling showed minor improvements, while others didn't had much deviation. The reason being that this patch only targets a corner case, where following are required to be true to improve performance and that doesn't happen too often with these tests: - Task is migrated to another CPU. - The task has high demand, and should take the target CPU to higher OPPs. - And the target CPU doesn't call into the cpufreq governor until the next tick. Based on initial work from Steve Muckle. Signed-off-by: Viresh Kumar <[email protected]> Acked-by: Saravana Kannan <[email protected]> Acked-by: Peter Zijlstra (Intel) <[email protected]> Signed-off-by: Rafael J. Wysocki <[email protected]>
1 parent 251accf commit 674e754

File tree

8 files changed

+55
-18
lines changed

8 files changed

+55
-18
lines changed

drivers/cpufreq/cpufreq_governor.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -275,6 +275,9 @@ static void dbs_update_util_handler(struct update_util_data *data, u64 time,
275275
struct policy_dbs_info *policy_dbs = cdbs->policy_dbs;
276276
u64 delta_ns, lst;
277277

278+
if (!cpufreq_can_do_remote_dvfs(policy_dbs->policy))
279+
return;
280+
278281
/*
279282
* The work may not be allowed to be queued up right now.
280283
* Possible reasons:

drivers/cpufreq/intel_pstate.c

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1747,6 +1747,10 @@ static void intel_pstate_update_util_pid(struct update_util_data *data,
17471747
struct cpudata *cpu = container_of(data, struct cpudata, update_util);
17481748
u64 delta_ns = time - cpu->sample.time;
17491749

1750+
/* Don't allow remote callbacks */
1751+
if (smp_processor_id() != cpu->cpu)
1752+
return;
1753+
17501754
if ((s64)delta_ns < pid_params.sample_rate_ns)
17511755
return;
17521756

@@ -1764,6 +1768,10 @@ static void intel_pstate_update_util(struct update_util_data *data, u64 time,
17641768
struct cpudata *cpu = container_of(data, struct cpudata, update_util);
17651769
u64 delta_ns;
17661770

1771+
/* Don't allow remote callbacks */
1772+
if (smp_processor_id() != cpu->cpu)
1773+
return;
1774+
17671775
if (flags & SCHED_CPUFREQ_IOWAIT) {
17681776
cpu->iowait_boost = int_tofp(1);
17691777
} else if (cpu->iowait_boost) {

include/linux/cpufreq.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -562,6 +562,15 @@ struct governor_attr {
562562
size_t count);
563563
};
564564

565+
static inline bool cpufreq_can_do_remote_dvfs(struct cpufreq_policy *policy)
566+
{
567+
/* Allow remote callbacks only on the CPUs sharing cpufreq policy */
568+
if (cpumask_test_cpu(smp_processor_id(), policy->cpus))
569+
return true;
570+
571+
return false;
572+
}
573+
565574
/*********************************************************************
566575
* FREQUENCY TABLE HELPERS *
567576
*********************************************************************/

kernel/sched/cpufreq_schedutil.c

Lines changed: 26 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ struct sugov_policy {
5252
struct sugov_cpu {
5353
struct update_util_data update_util;
5454
struct sugov_policy *sg_policy;
55+
unsigned int cpu;
5556

5657
bool iowait_boost_pending;
5758
unsigned int iowait_boost;
@@ -77,6 +78,21 @@ static bool sugov_should_update_freq(struct sugov_policy *sg_policy, u64 time)
7778
{
7879
s64 delta_ns;
7980

81+
/*
82+
* Since cpufreq_update_util() is called with rq->lock held for
83+
* the @target_cpu, our per-cpu data is fully serialized.
84+
*
85+
* However, drivers cannot in general deal with cross-cpu
86+
* requests, so while get_next_freq() will work, our
87+
* sugov_update_commit() call may not.
88+
*
89+
* Hence stop here for remote requests if they aren't supported
90+
* by the hardware, as calculating the frequency is pointless if
91+
* we cannot in fact act on it.
92+
*/
93+
if (!cpufreq_can_do_remote_dvfs(sg_policy->policy))
94+
return false;
95+
8096
if (sg_policy->work_in_progress)
8197
return false;
8298

@@ -155,12 +171,12 @@ static unsigned int get_next_freq(struct sugov_policy *sg_policy,
155171
return cpufreq_driver_resolve_freq(policy, freq);
156172
}
157173

158-
static void sugov_get_util(unsigned long *util, unsigned long *max)
174+
static void sugov_get_util(unsigned long *util, unsigned long *max, int cpu)
159175
{
160-
struct rq *rq = this_rq();
176+
struct rq *rq = cpu_rq(cpu);
161177
unsigned long cfs_max;
162178

163-
cfs_max = arch_scale_cpu_capacity(NULL, smp_processor_id());
179+
cfs_max = arch_scale_cpu_capacity(NULL, cpu);
164180

165181
*util = min(rq->cfs.avg.util_avg, cfs_max);
166182
*max = cfs_max;
@@ -254,7 +270,7 @@ static void sugov_update_single(struct update_util_data *hook, u64 time,
254270
if (flags & SCHED_CPUFREQ_RT_DL) {
255271
next_f = policy->cpuinfo.max_freq;
256272
} else {
257-
sugov_get_util(&util, &max);
273+
sugov_get_util(&util, &max, sg_cpu->cpu);
258274
sugov_iowait_boost(sg_cpu, &util, &max);
259275
next_f = get_next_freq(sg_policy, util, max);
260276
/*
@@ -316,7 +332,7 @@ static void sugov_update_shared(struct update_util_data *hook, u64 time,
316332
unsigned long util, max;
317333
unsigned int next_f;
318334

319-
sugov_get_util(&util, &max);
335+
sugov_get_util(&util, &max, sg_cpu->cpu);
320336

321337
raw_spin_lock(&sg_policy->update_lock);
322338

@@ -697,6 +713,11 @@ struct cpufreq_governor *cpufreq_default_governor(void)
697713

698714
static int __init sugov_register(void)
699715
{
716+
int cpu;
717+
718+
for_each_possible_cpu(cpu)
719+
per_cpu(sugov_cpu, cpu).cpu = cpu;
720+
700721
return cpufreq_register_governor(&schedutil_gov);
701722
}
702723
fs_initcall(sugov_register);

kernel/sched/deadline.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1136,7 +1136,7 @@ static void update_curr_dl(struct rq *rq)
11361136
}
11371137

11381138
/* kick cpufreq (see the comment in kernel/sched/sched.h). */
1139-
cpufreq_update_this_cpu(rq, SCHED_CPUFREQ_DL);
1139+
cpufreq_update_util(rq, SCHED_CPUFREQ_DL);
11401140

11411141
schedstat_set(curr->se.statistics.exec_max,
11421142
max(curr->se.statistics.exec_max, delta_exec));

kernel/sched/fair.c

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3278,7 +3278,9 @@ static inline void set_tg_cfs_propagate(struct cfs_rq *cfs_rq) {}
32783278

32793279
static inline void cfs_rq_util_change(struct cfs_rq *cfs_rq)
32803280
{
3281-
if (&this_rq()->cfs == cfs_rq) {
3281+
struct rq *rq = rq_of(cfs_rq);
3282+
3283+
if (&rq->cfs == cfs_rq) {
32823284
/*
32833285
* There are a few boundary cases this might miss but it should
32843286
* get called often enough that that should (hopefully) not be
@@ -3295,7 +3297,7 @@ static inline void cfs_rq_util_change(struct cfs_rq *cfs_rq)
32953297
*
32963298
* See cpu_util().
32973299
*/
3298-
cpufreq_update_util(rq_of(cfs_rq), 0);
3300+
cpufreq_update_util(rq, 0);
32993301
}
33003302
}
33013303

@@ -4875,7 +4877,7 @@ enqueue_task_fair(struct rq *rq, struct task_struct *p, int flags)
48754877
* passed.
48764878
*/
48774879
if (p->in_iowait)
4878-
cpufreq_update_this_cpu(rq, SCHED_CPUFREQ_IOWAIT);
4880+
cpufreq_update_util(rq, SCHED_CPUFREQ_IOWAIT);
48794881

48804882
for_each_sched_entity(se) {
48814883
if (se->on_rq)

kernel/sched/rt.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -970,7 +970,7 @@ static void update_curr_rt(struct rq *rq)
970970
return;
971971

972972
/* Kick cpufreq (see the comment in kernel/sched/sched.h). */
973-
cpufreq_update_this_cpu(rq, SCHED_CPUFREQ_RT);
973+
cpufreq_update_util(rq, SCHED_CPUFREQ_RT);
974974

975975
schedstat_set(curr->se.statistics.exec_max,
976976
max(curr->se.statistics.exec_max, delta_exec));

kernel/sched/sched.h

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2070,19 +2070,13 @@ static inline void cpufreq_update_util(struct rq *rq, unsigned int flags)
20702070
{
20712071
struct update_util_data *data;
20722072

2073-
data = rcu_dereference_sched(*this_cpu_ptr(&cpufreq_update_util_data));
2073+
data = rcu_dereference_sched(*per_cpu_ptr(&cpufreq_update_util_data,
2074+
cpu_of(rq)));
20742075
if (data)
20752076
data->func(data, rq_clock(rq), flags);
20762077
}
2077-
2078-
static inline void cpufreq_update_this_cpu(struct rq *rq, unsigned int flags)
2079-
{
2080-
if (cpu_of(rq) == smp_processor_id())
2081-
cpufreq_update_util(rq, flags);
2082-
}
20832078
#else
20842079
static inline void cpufreq_update_util(struct rq *rq, unsigned int flags) {}
2085-
static inline void cpufreq_update_this_cpu(struct rq *rq, unsigned int flags) {}
20862080
#endif /* CONFIG_CPU_FREQ */
20872081

20882082
#ifdef arch_scale_freq_capacity

0 commit comments

Comments
 (0)