Skip to content

Commit df24014

Browse files
vireshkrafaeljw
authored andcommitted
cpufreq: Call transition notifier only once for each policy
Currently, the notifiers are called once for each CPU of the policy->cpus cpumask. It would be more optimal if the notifier can be called only once and all the relevant information be provided to it. Out of the 23 drivers that register for the transition notifiers today, only 4 of them do per-cpu updates and the callback for the rest can be called only once for the policy without any impact. This would also avoid multiple function calls to the notifier callbacks and reduce multiple iterations of notifier core's code (which does locking as well). This patch adds pointer to the cpufreq policy to the struct cpufreq_freqs, so the notifier callback has all the information available to it with a single call. The five drivers which perform per-cpu updates are updated to use the cpufreq policy. The freqs->cpu field is redundant now and is removed. Acked-by: David S. Miller <[email protected]> (sparc) Signed-off-by: Viresh Kumar <[email protected]> Signed-off-by: Rafael J. Wysocki <[email protected]>
1 parent 8f5e823 commit df24014

File tree

6 files changed

+69
-49
lines changed

6 files changed

+69
-49
lines changed

arch/arm/kernel/smp.c

Lines changed: 15 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -754,15 +754,20 @@ static int cpufreq_callback(struct notifier_block *nb,
754754
unsigned long val, void *data)
755755
{
756756
struct cpufreq_freqs *freq = data;
757-
int cpu = freq->cpu;
757+
struct cpumask *cpus = freq->policy->cpus;
758+
int cpu, first = cpumask_first(cpus);
759+
unsigned int lpj;
758760

759761
if (freq->flags & CPUFREQ_CONST_LOOPS)
760762
return NOTIFY_OK;
761763

762-
if (!per_cpu(l_p_j_ref, cpu)) {
763-
per_cpu(l_p_j_ref, cpu) =
764-
per_cpu(cpu_data, cpu).loops_per_jiffy;
765-
per_cpu(l_p_j_ref_freq, cpu) = freq->old;
764+
if (!per_cpu(l_p_j_ref, first)) {
765+
for_each_cpu(cpu, cpus) {
766+
per_cpu(l_p_j_ref, cpu) =
767+
per_cpu(cpu_data, cpu).loops_per_jiffy;
768+
per_cpu(l_p_j_ref_freq, cpu) = freq->old;
769+
}
770+
766771
if (!global_l_p_j_ref) {
767772
global_l_p_j_ref = loops_per_jiffy;
768773
global_l_p_j_ref_freq = freq->old;
@@ -774,10 +779,11 @@ static int cpufreq_callback(struct notifier_block *nb,
774779
loops_per_jiffy = cpufreq_scale(global_l_p_j_ref,
775780
global_l_p_j_ref_freq,
776781
freq->new);
777-
per_cpu(cpu_data, cpu).loops_per_jiffy =
778-
cpufreq_scale(per_cpu(l_p_j_ref, cpu),
779-
per_cpu(l_p_j_ref_freq, cpu),
780-
freq->new);
782+
783+
lpj = cpufreq_scale(per_cpu(l_p_j_ref, first),
784+
per_cpu(l_p_j_ref_freq, first), freq->new);
785+
for_each_cpu(cpu, cpus)
786+
per_cpu(cpu_data, cpu).loops_per_jiffy = lpj;
781787
}
782788
return NOTIFY_OK;
783789
}

arch/sparc/kernel/time_64.c

Lines changed: 16 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -653,19 +653,23 @@ static int sparc64_cpufreq_notifier(struct notifier_block *nb, unsigned long val
653653
void *data)
654654
{
655655
struct cpufreq_freqs *freq = data;
656-
unsigned int cpu = freq->cpu;
657-
struct freq_table *ft = &per_cpu(sparc64_freq_table, cpu);
656+
unsigned int cpu;
657+
struct freq_table *ft;
658658

659-
if (!ft->ref_freq) {
660-
ft->ref_freq = freq->old;
661-
ft->clock_tick_ref = cpu_data(cpu).clock_tick;
662-
}
663-
if ((val == CPUFREQ_PRECHANGE && freq->old < freq->new) ||
664-
(val == CPUFREQ_POSTCHANGE && freq->old > freq->new)) {
665-
cpu_data(cpu).clock_tick =
666-
cpufreq_scale(ft->clock_tick_ref,
667-
ft->ref_freq,
668-
freq->new);
659+
for_each_cpu(cpu, freq->policy->cpus) {
660+
ft = &per_cpu(sparc64_freq_table, cpu);
661+
662+
if (!ft->ref_freq) {
663+
ft->ref_freq = freq->old;
664+
ft->clock_tick_ref = cpu_data(cpu).clock_tick;
665+
}
666+
667+
if ((val == CPUFREQ_PRECHANGE && freq->old < freq->new) ||
668+
(val == CPUFREQ_POSTCHANGE && freq->old > freq->new)) {
669+
cpu_data(cpu).clock_tick =
670+
cpufreq_scale(ft->clock_tick_ref, ft->ref_freq,
671+
freq->new);
672+
}
669673
}
670674

671675
return 0;

arch/x86/kernel/tsc.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -979,7 +979,7 @@ static int time_cpufreq_notifier(struct notifier_block *nb, unsigned long val,
979979
if (!(freq->flags & CPUFREQ_CONST_LOOPS))
980980
mark_tsc_unstable("cpufreq changes");
981981

982-
set_cyc2ns_scale(tsc_khz, freq->cpu, rdtsc());
982+
set_cyc2ns_scale(tsc_khz, freq->policy->cpu, rdtsc());
983983
}
984984

985985
return 0;

arch/x86/kvm/x86.c

Lines changed: 20 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -6698,10 +6698,8 @@ static void kvm_hyperv_tsc_notifier(void)
66986698
}
66996699
#endif
67006700

6701-
static int kvmclock_cpufreq_notifier(struct notifier_block *nb, unsigned long val,
6702-
void *data)
6701+
static void __kvmclock_cpufreq_notifier(struct cpufreq_freqs *freq, int cpu)
67036702
{
6704-
struct cpufreq_freqs *freq = data;
67056703
struct kvm *kvm;
67066704
struct kvm_vcpu *vcpu;
67076705
int i, send_ipi = 0;
@@ -6745,17 +6743,12 @@ static int kvmclock_cpufreq_notifier(struct notifier_block *nb, unsigned long va
67456743
*
67466744
*/
67476745

6748-
if (val == CPUFREQ_PRECHANGE && freq->old > freq->new)
6749-
return 0;
6750-
if (val == CPUFREQ_POSTCHANGE && freq->old < freq->new)
6751-
return 0;
6752-
6753-
smp_call_function_single(freq->cpu, tsc_khz_changed, freq, 1);
6746+
smp_call_function_single(cpu, tsc_khz_changed, freq, 1);
67546747

67556748
spin_lock(&kvm_lock);
67566749
list_for_each_entry(kvm, &vm_list, vm_list) {
67576750
kvm_for_each_vcpu(i, vcpu, kvm) {
6758-
if (vcpu->cpu != freq->cpu)
6751+
if (vcpu->cpu != cpu)
67596752
continue;
67606753
kvm_make_request(KVM_REQ_CLOCK_UPDATE, vcpu);
67616754
if (vcpu->cpu != smp_processor_id())
@@ -6777,8 +6770,24 @@ static int kvmclock_cpufreq_notifier(struct notifier_block *nb, unsigned long va
67776770
* guest context is entered kvmclock will be updated,
67786771
* so the guest will not see stale values.
67796772
*/
6780-
smp_call_function_single(freq->cpu, tsc_khz_changed, freq, 1);
6773+
smp_call_function_single(cpu, tsc_khz_changed, freq, 1);
67816774
}
6775+
}
6776+
6777+
static int kvmclock_cpufreq_notifier(struct notifier_block *nb, unsigned long val,
6778+
void *data)
6779+
{
6780+
struct cpufreq_freqs *freq = data;
6781+
int cpu;
6782+
6783+
if (val == CPUFREQ_PRECHANGE && freq->old > freq->new)
6784+
return 0;
6785+
if (val == CPUFREQ_POSTCHANGE && freq->old < freq->new)
6786+
return 0;
6787+
6788+
for_each_cpu(cpu, freq->policy->cpus)
6789+
__kvmclock_cpufreq_notifier(freq, cpu);
6790+
67826791
return 0;
67836792
}
67846793

drivers/cpufreq/cpufreq.c

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -340,11 +340,14 @@ static void cpufreq_notify_transition(struct cpufreq_policy *policy,
340340
struct cpufreq_freqs *freqs,
341341
unsigned int state)
342342
{
343+
int cpu;
344+
343345
BUG_ON(irqs_disabled());
344346

345347
if (cpufreq_disabled())
346348
return;
347349

350+
freqs->policy = policy;
348351
freqs->flags = cpufreq_driver->flags;
349352
pr_debug("notification %u of frequency transition to %u kHz\n",
350353
state, freqs->new);
@@ -364,10 +367,8 @@ static void cpufreq_notify_transition(struct cpufreq_policy *policy,
364367
}
365368
}
366369

367-
for_each_cpu(freqs->cpu, policy->cpus) {
368-
srcu_notifier_call_chain(&cpufreq_transition_notifier_list,
369-
CPUFREQ_PRECHANGE, freqs);
370-
}
370+
srcu_notifier_call_chain(&cpufreq_transition_notifier_list,
371+
CPUFREQ_PRECHANGE, freqs);
371372

372373
adjust_jiffies(CPUFREQ_PRECHANGE, freqs);
373374
break;
@@ -377,11 +378,11 @@ static void cpufreq_notify_transition(struct cpufreq_policy *policy,
377378
pr_debug("FREQ: %u - CPUs: %*pbl\n", freqs->new,
378379
cpumask_pr_args(policy->cpus));
379380

380-
for_each_cpu(freqs->cpu, policy->cpus) {
381-
trace_cpu_frequency(freqs->new, freqs->cpu);
382-
srcu_notifier_call_chain(&cpufreq_transition_notifier_list,
383-
CPUFREQ_POSTCHANGE, freqs);
384-
}
381+
for_each_cpu(cpu, policy->cpus)
382+
trace_cpu_frequency(freqs->new, cpu);
383+
384+
srcu_notifier_call_chain(&cpufreq_transition_notifier_list,
385+
CPUFREQ_POSTCHANGE, freqs);
385386

386387
cpufreq_stats_record_transition(policy, freqs->new);
387388
policy->cur = freqs->new;

include/linux/cpufreq.h

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -42,13 +42,6 @@ enum cpufreq_table_sorting {
4242
CPUFREQ_TABLE_SORTED_DESCENDING
4343
};
4444

45-
struct cpufreq_freqs {
46-
unsigned int cpu; /* cpu nr */
47-
unsigned int old;
48-
unsigned int new;
49-
u8 flags; /* flags of cpufreq_driver, see below. */
50-
};
51-
5245
struct cpufreq_cpuinfo {
5346
unsigned int max_freq;
5447
unsigned int min_freq;
@@ -156,6 +149,13 @@ struct cpufreq_policy {
156149
struct thermal_cooling_device *cdev;
157150
};
158151

152+
struct cpufreq_freqs {
153+
struct cpufreq_policy *policy;
154+
unsigned int old;
155+
unsigned int new;
156+
u8 flags; /* flags of cpufreq_driver, see below. */
157+
};
158+
159159
/* Only for ACPI */
160160
#define CPUFREQ_SHARED_TYPE_NONE (0) /* None */
161161
#define CPUFREQ_SHARED_TYPE_HW (1) /* HW does needed coordination */

0 commit comments

Comments
 (0)