|
Mel Gorman |
767090 |
From c3a14b0ca1837d870e8eca18cedcc1db15a36302 Mon Sep 17 00:00:00 2001
|
|
Mel Gorman |
767090 |
From: "Rafael J. Wysocki" <rafael.j.wysocki@intel.com>
|
|
Mel Gorman |
767090 |
Date: Fri, 28 Jul 2017 14:45:03 +0200
|
|
Mel Gorman |
767090 |
Subject: [PATCH] cpufreq: x86: Make scaling_cur_freq behave more as expected
|
|
Mel Gorman |
767090 |
|
|
Mel Gorman |
767090 |
References: bnc#1073583 cpufreq reporting
|
|
Mel Gorman |
767090 |
Patch-mainline: v4.13
|
|
Mel Gorman |
767090 |
Git-commit: 4815d3c56d1e10449a44089a47544d9ba84fad0d
|
|
Mel Gorman |
767090 |
|
|
Mel Gorman |
767090 |
After commit f8475cef9008 "x86: use common aperfmperf_khz_on_cpu() to
|
|
Mel Gorman |
767090 |
calculate KHz using APERF/MPERF" the scaling_cur_freq policy attribute
|
|
Mel Gorman |
767090 |
in sysfs only behaves as expected on x86 with APERF/MPERF registers
|
|
Mel Gorman |
767090 |
available when it is read from at least twice in a row. The value
|
|
Mel Gorman |
767090 |
returned by the first read may not be meaningful, because the
|
|
Mel Gorman |
767090 |
computations in there use cached values from the previous iteration
|
|
Mel Gorman |
767090 |
of aperfmperf_snapshot_khz() which may be stale.
|
|
Mel Gorman |
767090 |
|
|
Mel Gorman |
767090 |
To prevent that from happening, modify arch_freq_get_on_cpu() to
|
|
Mel Gorman |
767090 |
call aperfmperf_snapshot_khz() twice, with a short delay between
|
|
Mel Gorman |
767090 |
these calls, if the previous invocation of aperfmperf_snapshot_khz()
|
|
Mel Gorman |
767090 |
was too far back in the past (specifically, more that 1s ago).
|
|
Mel Gorman |
767090 |
|
|
Mel Gorman |
767090 |
Also, as pointed out by Doug Smythies, aperf_delta is limited now
|
|
Mel Gorman |
767090 |
and the multiplication of it by cpu_khz won't overflow, so simplify
|
|
Mel Gorman |
767090 |
the s->khz computations too.
|
|
Mel Gorman |
767090 |
|
|
Mel Gorman |
767090 |
Fixes: f8475cef9008 "x86: use common aperfmperf_khz_on_cpu() to calculate KHz using APERF/MPERF"
|
|
Mel Gorman |
767090 |
Reported-by: Doug Smythies <dsmythies@telus.net>
|
|
Mel Gorman |
767090 |
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
|
|
Mel Gorman |
767090 |
Signed-off-by: Mel Gorman <mgorman@suse.de>
|
|
Mel Gorman |
767090 |
---
|
|
Mel Gorman |
767090 |
arch/x86/kernel/cpu/aperfmperf.c | 40 ++++++++++++++++++++++++++--------------
|
|
Mel Gorman |
767090 |
1 file changed, 26 insertions(+), 14 deletions(-)
|
|
Mel Gorman |
767090 |
|
|
Mel Gorman |
767090 |
diff --git a/arch/x86/kernel/cpu/aperfmperf.c b/arch/x86/kernel/cpu/aperfmperf.c
|
|
Mel Gorman |
767090 |
index d869c8671e36..7cf7c70b6ef2 100644
|
|
Mel Gorman |
767090 |
--- a/arch/x86/kernel/cpu/aperfmperf.c
|
|
Mel Gorman |
767090 |
+++ b/arch/x86/kernel/cpu/aperfmperf.c
|
|
Mel Gorman |
767090 |
@@ -8,20 +8,25 @@
|
|
Mel Gorman |
767090 |
* This file is licensed under GPLv2.
|
|
Mel Gorman |
767090 |
*/
|
|
Mel Gorman |
767090 |
|
|
Mel Gorman |
767090 |
-#include <linux/jiffies.h>
|
|
Mel Gorman |
767090 |
+#include <linux/delay.h>
|
|
Mel Gorman |
767090 |
+#include <linux/ktime.h>
|
|
Mel Gorman |
767090 |
#include <linux/math64.h>
|
|
Mel Gorman |
767090 |
#include <linux/percpu.h>
|
|
Mel Gorman |
767090 |
#include <linux/smp.h>
|
|
Mel Gorman |
767090 |
|
|
Mel Gorman |
767090 |
struct aperfmperf_sample {
|
|
Mel Gorman |
767090 |
unsigned int khz;
|
|
Mel Gorman |
767090 |
- unsigned long jiffies;
|
|
Mel Gorman |
767090 |
+ ktime_t time;
|
|
Mel Gorman |
767090 |
u64 aperf;
|
|
Mel Gorman |
767090 |
u64 mperf;
|
|
Mel Gorman |
767090 |
};
|
|
Mel Gorman |
767090 |
|
|
Mel Gorman |
767090 |
static DEFINE_PER_CPU(struct aperfmperf_sample, samples);
|
|
Mel Gorman |
767090 |
|
|
Mel Gorman |
767090 |
+#define APERFMPERF_CACHE_THRESHOLD_MS 10
|
|
Mel Gorman |
767090 |
+#define APERFMPERF_REFRESH_DELAY_MS 20
|
|
Mel Gorman |
767090 |
+#define APERFMPERF_STALE_THRESHOLD_MS 1000
|
|
Mel Gorman |
767090 |
+
|
|
Mel Gorman |
767090 |
/*
|
|
Mel Gorman |
767090 |
* aperfmperf_snapshot_khz()
|
|
Mel Gorman |
767090 |
* On the current CPU, snapshot APERF, MPERF, and jiffies
|
|
Mel Gorman |
767090 |
@@ -33,9 +38,11 @@ static void aperfmperf_snapshot_khz(void *dummy)
|
|
Mel Gorman |
767090 |
u64 aperf, aperf_delta;
|
|
Mel Gorman |
767090 |
u64 mperf, mperf_delta;
|
|
Mel Gorman |
767090 |
struct aperfmperf_sample *s = this_cpu_ptr(&samples);
|
|
Mel Gorman |
767090 |
+ ktime_t now = ktime_get();
|
|
Mel Gorman |
767090 |
+ s64 time_delta = ktime_ms_delta(now, s->time);
|
|
Mel Gorman |
767090 |
|
|
Mel Gorman |
767090 |
- /* Don't bother re-computing within 10 ms */
|
|
Mel Gorman |
767090 |
- if (time_before(jiffies, s->jiffies + HZ/100))
|
|
Mel Gorman |
767090 |
+ /* Don't bother re-computing within the cache threshold time. */
|
|
Mel Gorman |
767090 |
+ if (time_delta < APERFMPERF_CACHE_THRESHOLD_MS)
|
|
Mel Gorman |
767090 |
return;
|
|
Mel Gorman |
767090 |
|
|
Mel Gorman |
767090 |
rdmsrl(MSR_IA32_APERF, aperf);
|
|
Mel Gorman |
767090 |
@@ -51,22 +58,21 @@ static void aperfmperf_snapshot_khz(void *dummy)
|
|
Mel Gorman |
767090 |
if (mperf_delta == 0)
|
|
Mel Gorman |
767090 |
return;
|
|
Mel Gorman |
767090 |
|
|
Mel Gorman |
767090 |
- /*
|
|
Mel Gorman |
767090 |
- * if (cpu_khz * aperf_delta) fits into ULLONG_MAX, then
|
|
Mel Gorman |
767090 |
- * khz = (cpu_khz * aperf_delta) / mperf_delta
|
|
Mel Gorman |
767090 |
- */
|
|
Mel Gorman |
767090 |
- if (div64_u64(ULLONG_MAX, cpu_khz) > aperf_delta)
|
|
Mel Gorman |
767090 |
- s->khz = div64_u64((cpu_khz * aperf_delta), mperf_delta);
|
|
Mel Gorman |
767090 |
- else /* khz = aperf_delta / (mperf_delta / cpu_khz) */
|
|
Mel Gorman |
767090 |
- s->khz = div64_u64(aperf_delta,
|
|
Mel Gorman |
767090 |
- div64_u64(mperf_delta, cpu_khz));
|
|
Mel Gorman |
767090 |
- s->jiffies = jiffies;
|
|
Mel Gorman |
767090 |
+ s->time = now;
|
|
Mel Gorman |
767090 |
s->aperf = aperf;
|
|
Mel Gorman |
767090 |
s->mperf = mperf;
|
|
Mel Gorman |
767090 |
+
|
|
Mel Gorman |
767090 |
+ /* If the previous iteration was too long ago, discard it. */
|
|
Mel Gorman |
767090 |
+ if (time_delta > APERFMPERF_STALE_THRESHOLD_MS)
|
|
Mel Gorman |
767090 |
+ s->khz = 0;
|
|
Mel Gorman |
767090 |
+ else
|
|
Mel Gorman |
767090 |
+ s->khz = div64_u64((cpu_khz * aperf_delta), mperf_delta);
|
|
Mel Gorman |
767090 |
}
|
|
Mel Gorman |
767090 |
|
|
Mel Gorman |
767090 |
unsigned int arch_freq_get_on_cpu(int cpu)
|
|
Mel Gorman |
767090 |
{
|
|
Mel Gorman |
767090 |
+ unsigned int khz;
|
|
Mel Gorman |
767090 |
+
|
|
Mel Gorman |
767090 |
if (!cpu_khz)
|
|
Mel Gorman |
767090 |
return 0;
|
|
Mel Gorman |
767090 |
|
|
Mel Gorman |
767090 |
@@ -74,6 +80,12 @@ unsigned int arch_freq_get_on_cpu(int cpu)
|
|
Mel Gorman |
767090 |
return 0;
|
|
Mel Gorman |
767090 |
|
|
Mel Gorman |
767090 |
smp_call_function_single(cpu, aperfmperf_snapshot_khz, NULL, 1);
|
|
Mel Gorman |
767090 |
+ khz = per_cpu(samples.khz, cpu);
|
|
Mel Gorman |
767090 |
+ if (khz)
|
|
Mel Gorman |
767090 |
+ return khz;
|
|
Mel Gorman |
767090 |
+
|
|
Mel Gorman |
767090 |
+ msleep(APERFMPERF_REFRESH_DELAY_MS);
|
|
Mel Gorman |
767090 |
+ smp_call_function_single(cpu, aperfmperf_snapshot_khz, NULL, 1);
|
|
Mel Gorman |
767090 |
|
|
Mel Gorman |
767090 |
return per_cpu(samples.khz, cpu);
|
|
Mel Gorman |
767090 |
}
|