Skip to content

Commit 7d84c1e

Browse files
committed
x86/aperfmperf: Replace aperfmperf_get_khz()
The frequency invariance infrastructure provides the APERF/MPERF samples already. Utilize them for the cpu frequency display in /proc/cpuinfo. The sample is considered valid for 20ms. So for idle or isolated NOHZ full CPUs the function returns 0, which is matching the previous behaviour. This gets rid of the mass IPIs and a delay of 20ms for stabilizing observed by Eric when reading /proc/cpuinfo. Reported-by: Eric Dumazet <eric.dumazet@gmail.com> Signed-off-by: Thomas Gleixner <tglx@linutronix.de> Tested-by: Eric Dumazet <edumazet@google.com> Reviewed-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com> Acked-by: Peter Zijlstra (Intel) <peterz@infradead.org> Acked-by: Paul E. McKenney <paulmck@kernel.org> Link: https://lore.kernel.org/r/20220415161206.875029458@linutronix.de
1 parent cd8c0e1 commit 7d84c1e

3 files changed

Lines changed: 35 additions & 49 deletions

File tree

arch/x86/kernel/cpu/aperfmperf.c

Lines changed: 34 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -101,49 +101,6 @@ static bool aperfmperf_snapshot_cpu(int cpu, ktime_t now, bool wait)
101101
return time_delta <= APERFMPERF_STALE_THRESHOLD_MS;
102102
}
103103

104-
unsigned int aperfmperf_get_khz(int cpu)
105-
{
106-
if (!cpu_khz)
107-
return 0;
108-
109-
if (!boot_cpu_has(X86_FEATURE_APERFMPERF))
110-
return 0;
111-
112-
if (!housekeeping_cpu(cpu, HK_TYPE_MISC))
113-
return 0;
114-
115-
if (rcu_is_idle_cpu(cpu))
116-
return 0; /* Idle CPUs are completely uninteresting. */
117-
118-
aperfmperf_snapshot_cpu(cpu, ktime_get(), true);
119-
return per_cpu(samples.khz, cpu);
120-
}
121-
122-
void arch_freq_prepare_all(void)
123-
{
124-
ktime_t now = ktime_get();
125-
bool wait = false;
126-
int cpu;
127-
128-
if (!cpu_khz)
129-
return;
130-
131-
if (!boot_cpu_has(X86_FEATURE_APERFMPERF))
132-
return;
133-
134-
for_each_online_cpu(cpu) {
135-
if (!housekeeping_cpu(cpu, HK_TYPE_MISC))
136-
continue;
137-
if (rcu_is_idle_cpu(cpu))
138-
continue; /* Idle CPUs are completely uninteresting. */
139-
if (!aperfmperf_snapshot_cpu(cpu, now, false))
140-
wait = true;
141-
}
142-
143-
if (wait)
144-
msleep(APERFMPERF_REFRESH_DELAY_MS);
145-
}
146-
147104
unsigned int arch_freq_get_on_cpu(int cpu)
148105
{
149106
struct aperfmperf_sample *s = per_cpu_ptr(&samples, cpu);
@@ -530,6 +487,40 @@ void arch_scale_freq_tick(void)
530487
scale_freq_tick(acnt, mcnt);
531488
}
532489

490+
/*
491+
* Discard samples older than the define maximum sample age of 20ms. There
492+
* is no point in sending IPIs in such a case. If the scheduler tick was
493+
* not running then the CPU is either idle or isolated.
494+
*/
495+
#define MAX_SAMPLE_AGE ((unsigned long)HZ / 50)
496+
497+
unsigned int aperfmperf_get_khz(int cpu)
498+
{
499+
struct aperfmperf *s = per_cpu_ptr(&cpu_samples, cpu);
500+
unsigned long last;
501+
unsigned int seq;
502+
u64 acnt, mcnt;
503+
504+
if (!cpu_feature_enabled(X86_FEATURE_APERFMPERF))
505+
return 0;
506+
507+
do {
508+
seq = raw_read_seqcount_begin(&s->seq);
509+
last = s->last_update;
510+
acnt = s->acnt;
511+
mcnt = s->mcnt;
512+
} while (read_seqcount_retry(&s->seq, seq));
513+
514+
/*
515+
* Bail on invalid count and when the last update was too long ago,
516+
* which covers idle and NOHZ full CPUs.
517+
*/
518+
if (!mcnt || (jiffies - last) > MAX_SAMPLE_AGE)
519+
return 0;
520+
521+
return div64_u64((cpu_khz * acnt), mcnt);
522+
}
523+
533524
static int __init bp_init_aperfmperf(void)
534525
{
535526
if (!cpu_feature_enabled(X86_FEATURE_APERFMPERF))

fs/proc/cpuinfo.c

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,10 @@
55
#include <linux/proc_fs.h>
66
#include <linux/seq_file.h>
77

8-
__weak void arch_freq_prepare_all(void)
9-
{
10-
}
11-
128
extern const struct seq_operations cpuinfo_op;
9+
1310
static int cpuinfo_open(struct inode *inode, struct file *file)
1411
{
15-
arch_freq_prepare_all();
1612
return seq_open(file, &cpuinfo_op);
1713
}
1814

include/linux/cpufreq.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1199,7 +1199,6 @@ static inline void sched_cpufreq_governor_change(struct cpufreq_policy *policy,
11991199
struct cpufreq_governor *old_gov) { }
12001200
#endif
12011201

1202-
extern void arch_freq_prepare_all(void);
12031202
extern unsigned int arch_freq_get_on_cpu(int cpu);
12041203

12051204
#ifndef arch_set_freq_scale

0 commit comments

Comments
 (0)