diff mbox series

[v6,7/7] PM / EM: Mark inefficiencies in CPUFreq

Message ID 1630405453-275784-8-git-send-email-vincent.donnefort@arm.com
State New
Headers show
Series Inefficient OPPs | expand

Commit Message

Vincent Donnefort Aug. 31, 2021, 10:24 a.m. UTC
The Energy Model has a 1:1 mapping between OPPs and performance states
(em_perf_state). If a CPUFreq driver registers an Energy Model,
inefficiencies found by the latter can be applied to CPUFreq.

Signed-off-by: Vincent Donnefort <vincent.donnefort@arm.com>

Comments

Viresh Kumar Sept. 1, 2021, 5:31 a.m. UTC | #1
On 31-08-21, 11:24, Vincent Donnefort wrote:
> The Energy Model has a 1:1 mapping between OPPs and performance states

> (em_perf_state). If a CPUFreq driver registers an Energy Model,

> inefficiencies found by the latter can be applied to CPUFreq.

> 

> Signed-off-by: Vincent Donnefort <vincent.donnefort@arm.com>

> 

> diff --git a/include/linux/cpufreq.h b/include/linux/cpufreq.h

> index cb09afbf01e2..153ddc7b0506 100644

> --- a/include/linux/cpufreq.h

> +++ b/include/linux/cpufreq.h

> @@ -1121,7 +1121,6 @@ void cpufreq_generic_init(struct cpufreq_policy *policy,

>  

>  static inline void cpufreq_register_em_with_opp(struct cpufreq_policy *policy)

>  {

> -	dev_pm_opp_of_register_em(get_cpu_device(policy->cpu),

> -				  policy->related_cpus);

> +	dev_pm_opp_of_register_em(get_cpu_device(policy->cpu), policy->related_cpus);

>  }

>  #endif /* _LINUX_CPUFREQ_H */

> diff --git a/kernel/power/energy_model.c b/kernel/power/energy_model.c

> index d353ef29e37f..dfcbb2deb794 100644

> --- a/kernel/power/energy_model.c

> +++ b/kernel/power/energy_model.c

> @@ -10,6 +10,7 @@

>  #define pr_fmt(fmt) "energy_model: " fmt

>  

>  #include <linux/cpu.h>

> +#include <linux/cpufreq.h>

>  #include <linux/cpumask.h>

>  #include <linux/debugfs.h>

>  #include <linux/energy_model.h>

> @@ -231,6 +232,46 @@ static int em_create_pd(struct device *dev, int nr_states,

>  	return 0;

>  }

>  

> +static void em_cpufreq_update_efficiencies(struct device *dev)

> +{

> +	struct em_perf_domain *pd = dev->em_pd;

> +	struct em_perf_state *table;

> +	struct cpufreq_policy *policy;

> +	bool found = false;

> +	int i;

> +

> +	if (!_is_cpu_device(dev) || !pd)

> +		return;

> +

> +	policy = cpufreq_cpu_get(cpumask_first(em_span_cpus(pd)));

> +	if (!policy) {

> +		dev_warn(dev, "EM: Access to CPUFreq policy failed");

> +		return;

> +	}

> +

> +	table = pd->table;

> +

> +	for (i = 0; i < pd->nr_perf_states; i++) {

> +		if (!(table[i].flags & EM_PERF_STATE_INEFFICIENT))

> +			continue;

> +

> +		cpufreq_table_set_inefficient(policy, table[i].frequency);

> +		found = true;

> +	}

> +

> +	if (!found)

> +		return;

> +

> +	if (cpufreq_table_update_efficiencies(policy))

> +		return;

> +

> +	/*

> +	 * Efficiencies have been installed in CPUFreq, inefficient frequencies

> +	 * will be skipped. The EM can do the same.

> +	 */

> +	pd->flags |= EM_PERF_DOMAIN_SKIP_INEFFICIENCIES;

> +}

> +

>  /**

>   * em_pd_get() - Return the performance domain for a device

>   * @dev : Device to find the performance domain for

> @@ -347,6 +388,8 @@ int em_dev_register_perf_domain(struct device *dev, unsigned int nr_states,

>  	if (milliwatts)

>  		dev->em_pd->flags |= EM_PERF_DOMAIN_MILLIWATTS;

>  

> +	em_cpufreq_update_efficiencies(dev);


This is how I always wanted this to be :)

-- 
viresh
diff mbox series

Patch

diff --git a/include/linux/cpufreq.h b/include/linux/cpufreq.h
index cb09afbf01e2..153ddc7b0506 100644
--- a/include/linux/cpufreq.h
+++ b/include/linux/cpufreq.h
@@ -1121,7 +1121,6 @@  void cpufreq_generic_init(struct cpufreq_policy *policy,
 
 static inline void cpufreq_register_em_with_opp(struct cpufreq_policy *policy)
 {
-	dev_pm_opp_of_register_em(get_cpu_device(policy->cpu),
-				  policy->related_cpus);
+	dev_pm_opp_of_register_em(get_cpu_device(policy->cpu), policy->related_cpus);
 }
 #endif /* _LINUX_CPUFREQ_H */
diff --git a/kernel/power/energy_model.c b/kernel/power/energy_model.c
index d353ef29e37f..dfcbb2deb794 100644
--- a/kernel/power/energy_model.c
+++ b/kernel/power/energy_model.c
@@ -10,6 +10,7 @@ 
 #define pr_fmt(fmt) "energy_model: " fmt
 
 #include <linux/cpu.h>
+#include <linux/cpufreq.h>
 #include <linux/cpumask.h>
 #include <linux/debugfs.h>
 #include <linux/energy_model.h>
@@ -231,6 +232,46 @@  static int em_create_pd(struct device *dev, int nr_states,
 	return 0;
 }
 
+static void em_cpufreq_update_efficiencies(struct device *dev)
+{
+	struct em_perf_domain *pd = dev->em_pd;
+	struct em_perf_state *table;
+	struct cpufreq_policy *policy;
+	bool found = false;
+	int i;
+
+	if (!_is_cpu_device(dev) || !pd)
+		return;
+
+	policy = cpufreq_cpu_get(cpumask_first(em_span_cpus(pd)));
+	if (!policy) {
+		dev_warn(dev, "EM: Access to CPUFreq policy failed");
+		return;
+	}
+
+	table = pd->table;
+
+	for (i = 0; i < pd->nr_perf_states; i++) {
+		if (!(table[i].flags & EM_PERF_STATE_INEFFICIENT))
+			continue;
+
+		cpufreq_table_set_inefficient(policy, table[i].frequency);
+		found = true;
+	}
+
+	if (!found)
+		return;
+
+	if (cpufreq_table_update_efficiencies(policy))
+		return;
+
+	/*
+	 * Efficiencies have been installed in CPUFreq, inefficient frequencies
+	 * will be skipped. The EM can do the same.
+	 */
+	pd->flags |= EM_PERF_DOMAIN_SKIP_INEFFICIENCIES;
+}
+
 /**
  * em_pd_get() - Return the performance domain for a device
  * @dev : Device to find the performance domain for
@@ -347,6 +388,8 @@  int em_dev_register_perf_domain(struct device *dev, unsigned int nr_states,
 	if (milliwatts)
 		dev->em_pd->flags |= EM_PERF_DOMAIN_MILLIWATTS;
 
+	em_cpufreq_update_efficiencies(dev);
+
 	em_debug_create_pd(dev);
 	dev_info(dev, "EM: created perf domain\n");