Subject: cpufreq: Add cycle counter to the Intel P state driver for cpuspeed monitoring
From: Carsten Emde <[email-masked]>
Date: Sun, 31 Jan 2016 14:54:44 +0100

Most cpufreq drivers contain an interface to the cpufreq_stats plugin
that counts the time the processor stays in a given P state. The Intel P
state driver, however, does not work on discrete P states but allows to
run the processor at arbitrary clock frequencies within the allowed
range. Even if the frequencies were reduced to steps of 100 MHz, this
would result in too many P states. This patch, therefore, introduces the
additional cpufreq variable kcycles that contains the number of clock
cycles divided by 1000 since the most recent reboot. This allows to
monitor the average clock frequency during a defined time interval by
simply calculating the derivative.

Signed-off-by: Carsten Emde <[email-masked]>

---
 drivers/cpufreq/cpufreq.c      |   15 +++++++++++++++
 drivers/cpufreq/intel_pstate.c |   26 +++++++++++++++++++++++++-
 include/linux/cpufreq.h        |    2 ++
 3 files changed, 42 insertions(+), 1 deletion(-)

Index: linux-3.18.43-rt46/drivers/cpufreq/cpufreq.c
===================================================================
--- linux-3.18.43-rt46.orig/drivers/cpufreq/cpufreq.c
+++ linux-3.18.43-rt46/drivers/cpufreq/cpufreq.c
@@ -710,6 +710,19 @@ static ssize_t show_bios_limit(struct cp
 	return sprintf(buf, "%u\n", policy->cpuinfo.max_freq);
 }
 
+/**
+ * show_kcycles - show number of accmulated CPU cycles by 1000
+ */
+static ssize_t show_scaling_kcycles(struct cpufreq_policy *policy,
+					char *buf)
+{
+	if (cpufreq_driver && cpufreq_driver->kcycles) {
+		u64 kcycles = cpufreq_driver->kcycles(policy->cpu);
+		return sprintf(buf, "%llu\n", kcycles);
+	} else
+		return sprintf(buf, "<unsupported>");
+}
+
 cpufreq_freq_attr_ro_perm(cpuinfo_cur_freq, 0400);
 cpufreq_freq_attr_ro(cpuinfo_min_freq);
 cpufreq_freq_attr_ro(cpuinfo_max_freq);
@@ -724,6 +737,7 @@ cpufreq_freq_attr_rw(scaling_min_freq);
 cpufreq_freq_attr_rw(scaling_max_freq);
 cpufreq_freq_attr_rw(scaling_governor);
 cpufreq_freq_attr_rw(scaling_setspeed);
+cpufreq_freq_attr_ro(scaling_kcycles);
 
 static struct attribute *default_attrs[] = {
 	&cpuinfo_min_freq.attr,
@@ -737,6 +751,7 @@ static struct attribute *default_attrs[]
 	&scaling_driver.attr,
 	&scaling_available_governors.attr,
 	&scaling_setspeed.attr,
+	&scaling_kcycles.attr,
 	NULL
 };
 
Index: linux-3.18.43-rt46/drivers/cpufreq/intel_pstate.c
===================================================================
--- linux-3.18.43-rt46.orig/drivers/cpufreq/intel_pstate.c
+++ linux-3.18.43-rt46/drivers/cpufreq/intel_pstate.c
@@ -69,6 +69,7 @@ struct sample {
 	u64 mperf;
 	int freq;
 	ktime_t time;
+	u64 kcycles;
 };
 
 struct pstate_data {
@@ -627,7 +628,7 @@ static inline void intel_pstate_calc_bus
 
 static inline void intel_pstate_sample(struct cpudata *cpu)
 {
-	u64 aperf, mperf;
+	u64 aperf, mperf, interval;
 	unsigned long flags;
 
 	local_irq_save(flags);
@@ -644,6 +645,16 @@ static inline void intel_pstate_sample(s
 
 	intel_pstate_calc_busy(cpu);
 
+	interval = ktime_divns(cpu->sample.time, NSEC_PER_MSEC) -
+		ktime_divns(cpu->last_sample_time, NSEC_PER_MSEC);
+#ifdef CONFIG_64BIT
+        cpu->sample.kcycles += ((u64) cpu->sample.freq * interval) /
+                1000ULL;
+#else
+	cpu->sample.kcycles += (u64) ((cpu->sample.freq / 1000) *
+		interval);
+#endif
+
 	cpu->prev_aperf = aperf;
 	cpu->prev_mperf = mperf;
 }
@@ -778,6 +789,18 @@ static unsigned int intel_pstate_get(uns
 	return sample->freq;
 }
 
+static u64 intel_pstate_kcycles(unsigned int cpu_num)
+{
+	struct sample *sample;
+	struct cpudata *cpu;
+
+	cpu = all_cpu_data[cpu_num];
+	if (!cpu)
+		return 0;
+	sample = &cpu->sample;
+	return sample->kcycles;
+}
+
 static int intel_pstate_set_policy(struct cpufreq_policy *policy)
 {
 	if (!policy->cpuinfo.max_freq)
@@ -863,6 +886,7 @@ static struct cpufreq_driver intel_pstat
 	.verify		= intel_pstate_verify_policy,
 	.setpolicy	= intel_pstate_set_policy,
 	.get		= intel_pstate_get,
+	.kcycles	= intel_pstate_kcycles,
 	.init		= intel_pstate_cpu_init,
 	.stop_cpu	= intel_pstate_stop_cpu,
 	.name		= "intel_pstate",
Index: linux-3.18.43-rt46/include/linux/cpufreq.h
===================================================================
--- linux-3.18.43-rt46.orig/include/linux/cpufreq.h
+++ linux-3.18.43-rt46/include/linux/cpufreq.h
@@ -261,6 +261,8 @@ struct cpufreq_driver {
 	unsigned int	(*get)	(unsigned int cpu);
 
 	/* optional */
+	u64	(*kcycles)	(unsigned int cpu);
+
 	int	(*bios_limit)	(int cpu, unsigned int *limit);
 
 	int	(*exit)		(struct cpufreq_policy *policy);