cpufreq: transition-latency cleanups
Subsystems (3)
Viresh Kumar
maintainerv2 cover cpufreq: transition-latency cleanups
Hi Rafael,
Here is the V2 and sending it as RFC this time.
This series tries to cleanup the code around transition-latency and its users. Some of the old legacy code, which may not make much sense now, is dropped as well.
Some code consolidation also done across governors.
Based of: pm/linux-next
Tested on: ARM64 Hikey board.
V1->V2:
- While we still get rid of the limitation of 10ms for using ondemand/conservative, but we preserve the earlier behavior where the transition latency set to CPUFREQ_ETERNAL would not allow use of ondemand/conservative governors. Thanks to Dominik for his feedback on that.
--
viresh
Viresh Kumar (6):
cpufreq: Replace "max_transition_latency" with "dynamic_switching"
cpufreq: schedutil: Set dynamic_switching to true
cpufreq: governor: Drop min_sampling_rate
cpufreq: Use transition_delay_us for legacy governors as well
cpufreq: Cap the default transition delay value to 10 ms
cpufreq: arm_big_little: Make ->get_transition_latency() mandatory
Documentation/admin-guide/pm/cpufreq.rst | 8 ------- drivers/cpufreq/arm_big_little.c | 10 ++++----- drivers/cpufreq/cpufreq.c | 8 +++---- drivers/cpufreq/cpufreq_conservative.c | 6 ------ drivers/cpufreq/cpufreq_governor.c | 17 ++------------- drivers/cpufreq/cpufreq_governor.h | 3 +-- drivers/cpufreq/cpufreq_ondemand.c | 12 ----------- include/linux/cpufreq.h | 36 ++++++++++++++++++++++++-------- kernel/sched/cpufreq_schedutil.c | 12 ++--------- 9 files changed, 40 insertions(+), 72 deletions(-)
Signature · 1 line
2.13.0.71.gd7076ec9c9cb
Viresh Kumar
maintainerRFC v2 1/6 cpufreq: Replace "max_transition_latency" with "dynamic_switching"
There is no limitation in the ondemand or conservative governors which disallow the transition_latency to be greater than 10 ms.
The max_transition_latency field is rather used to disallow automatic dynamic frequency switching for platforms which didn't wanted these governors to run.
Replace max_transition_latency with a boolean (dynamic_switching) and check for transition_latency == CPUFREQ_ETERNAL along with that. This makes it pretty straight forward to read/understand now.
--- drivers/cpufreq/cpufreq.c | 8 ++++---- drivers/cpufreq/cpufreq_governor.h | 2 +- include/linux/cpufreq.h | 9 ++------- 3 files changed, 7 insertions(+), 12 deletions(-)
drivers/cpufreq/cpufreq.c +4 -4
@@ -1988,13 +1988,13 @@ static int cpufreq_init_governor(struct cpufreq_policy *policy)if (!policy->governor)return -EINVAL ; -if (policy->governor->max_transition_latency && - policy->cpuinfo.transition_latency > - policy->governor->max_transition_latency) { +/* Platform doesn't want dynamic frequency switching ? */ +if (policy->governor->dynamic_switching && + policy->cpuinfo.transition_latency ==CPUFREQ_ETERNAL ) {struct cpufreq_governor *gov =cpufreq_fallback_governor ();if (gov) { -pr_warn ("%s governor failed, too long transition latency of HW, fallback to %s governor\n" , +pr_warn ("Transition latency set to CPUFREQ_ETERNAL, can't use %s governor. Fallback to %s governor\n" , policy->governor->name, gov->name); policy->governor = gov; }else {
drivers/cpufreq/cpufreq_governor.h +1 -1
@@ -160,7 +160,7 @@ void cpufreq_dbs_governor_limits(struct cpufreq_policy *policy);#define CPUFREQ_DBS_GOVERNOR_INITIALIZER (_name_) \ { \ .name = _name_, \ - .max_transition_latency = TRANSITION_LATENCY_LIMIT, \ + .dynamic_switching = true, \ .owner = THIS_MODULE, \ .init = cpufreq_dbs_governor_init, \ .exit = cpufreq_dbs_governor_exit, \
include/linux/cpufreq.h +2 -7
@@ -487,14 +487,10 @@ static inline unsigned long cpufreq_scale(unsigned long old, u_int div,* polling frequency is 1000 times the transition latency of the processor. The * ondemand governor will work on any processor with transition latency <= 10ms, * using appropriate sampling rate. -* -* For CPUs with transition latency > 10ms (mostly drivers with CPUFREQ_ETERNAL) -* the ondemand governor will not work. All times here are in us (microseconds). */ #define MIN_SAMPLING_RATE_RATIO (2)#define LATENCY_MULTIPLIER (1000)#define MIN_LATENCY_MULTIPLIER (20) -#define TRANSITION_LATENCY_LIMIT (10 * 1000 * 1000)struct cpufreq_governor {char name[CPUFREQ_NAME_LEN ];
@@ -507,9 +503,8 @@ struct cpufreq_governor { char *buf);int (*store_setspeed) (struct cpufreq_policy *policy,unsigned int freq); -unsigned int max_transition_latency;/* HW must be able to switch to -next freq faster than this value in nano secs or we -will fallback to performance governor */ +/* For governors which change frequency dynamically by themselves */ +bool dynamic_switching;struct list_head governor_list;struct module *owner; };
Signature · 1 line
2.13.0.71.gd7076ec9c9cb
Rafael J. Wysocki
maintainerRe: [RFC V2 1/6] cpufreq: Replace "max_transition_latency" with "dynamic_switching"
Quoted 10 lines · Viresh Kumar
There is no limitation in the ondemand or conservative governors which disallow the
transition_latencyto be greater than 10 ms.The
max_transition_latencyfield is rather used to disallow automatic dynamic frequency switching for platforms which didn't wanted these governors to run.Replace
max_transition_latencywith a boolean (dynamic_switching) and check fortransition_latency==CPUFREQ_ETERNALalong with that. This makes it pretty straight forward to read/understand now.
Well, using CPUFREQ_ETERNAL for that on the driver side is still not particularly straightforward IMO, so maybe add a "no_dynamic_switching" to the driver structure and set it to "true" for the one driver in question?
Thanks,
Rafael
Re: [RFC V2 1/6] cpufreq: Replace "max_transition_latency" with "dynamic_switching"
Quoted 8 lines · Rafael J. Wysocki
Quoted 7 lines · Viresh Kumar
There is no limitation in the ondemand or conservative governors which disallow the
transition_latencyto be greater than 10 ms.The
max_transition_latencyfield is rather used to disallow automatic dynamic frequency switching for platforms which didn't wanted these governors to run.
Quoted 8 lines
Quoted 3 lines
Replace
max_transition_latencywith a boolean (dynamic_switching) and check fortransition_latency==CPUFREQ_ETERNALalong with that. This makes it pretty straight forward to read/understand now.Well, using
CPUFREQ_ETERNALfor that on the driver side is still not particularly straightforward IMO, so maybe add a "no_dynamic_switching" to the driver structure and set it to "true" for the one driver in question?
IIRC it's not just one driver which sets the latency to CPUFREQ_ETERNAL, and where dynamic switching might be harmful or at least lead to undefined behavior.
Best,
Dominik
Rafael J. Wysocki
maintainerRe: [RFC V2 1/6] cpufreq: Replace "max_transition_latency" with "dynamic_switching"
Quoted 13 lines · Dominik Brodowski
Quoted 12 lines · Rafael J. Wysocki
Quoted 10 lines · Viresh Kumar
There is no limitation in the ondemand or conservative governors which disallow the
transition_latencyto be greater than 10 ms.The
max_transition_latencyfield is rather used to disallow automatic dynamic frequency switching for platforms which didn't wanted these governors to run.Replace
max_transition_latencywith a boolean (dynamic_switching) and check fortransition_latency==CPUFREQ_ETERNALalong with that. This makes it pretty straight forward to read/understand now.
Quoted 8 lines
Quoted 4 lines
Well, using
CPUFREQ_ETERNALfor that on the driver side is still not particularly straightforward IMO, so maybe add a "no_dynamic_switching" to the driver structure and set it to "true" for the one driver in question?IIRC it's not just one driver which sets the latency to
CPUFREQ_ETERNAL, and where dynamic switching might be harmful or at least lead to undefined behavior.
OK
Still, though, using CPUFREQ_ETERNAL to indicate the "no dynamic switching" condition is somewhat convoluted, so why don't we have a flag to *explicitly* say that instead?
Do you know which drivers they are or is it just all drivers that use CPUFREQ_ETERNAL?
Thanks,
Rafael
Re: [RFC V2 1/6] cpufreq: Replace "max_transition_latency" with "dynamic_switching"
Quoted 24 lines · Rafael J. Wysocki
Quoted 13 lines · Dominik Brodowski
Quoted 12 lines · Rafael J. Wysocki
Quoted 10 lines · Viresh Kumar
There is no limitation in the ondemand or conservative governors which disallow the
transition_latencyto be greater than 10 ms.The
max_transition_latencyfield is rather used to disallow automatic dynamic frequency switching for platforms which didn't wanted these governors to run.Replace
max_transition_latencywith a boolean (dynamic_switching) and check fortransition_latency==CPUFREQ_ETERNALalong with that. This makes it pretty straight forward to read/understand now.Quoted 8 lines
Quoted 4 lines
Well, using
CPUFREQ_ETERNALfor that on the driver side is still not particularly straightforward IMO, so maybe add a "no_dynamic_switching" to the driver structure and set it to "true" for the one driver in question?IIRC it's not just one driver which sets the latency to
CPUFREQ_ETERNAL, and where dynamic switching might be harmful or at least lead to undefined behavior.
Quoted 8 lines
OK
Still, though, using
CPUFREQ_ETERNALto indicate the "no dynamic switching" condition is somewhat convoluted, so why don't we have a flag to *explicitly* say that instead?Do you know which drivers they are or is it just all drivers that use
CPUFREQ_ETERNAL?
Well, after the $subject patch it effectively is all drivers that use CPUFREQ_ETERNAL anyway, so it looks like we actually can do a complete switch-over.
Thanks,
Rafael
Re: [RFC V2 1/6] cpufreq: Replace "max_transition_latency" with "dynamic_switching"
Quoted 31 lines · Rafael J. Wysocki
Quoted 30 lines · Rafael J. Wysocki
Quoted 13 lines · Dominik Brodowski
Quoted 12 lines · Rafael J. Wysocki
Quoted 10 lines · Viresh Kumar
There is no limitation in the ondemand or conservative governors which disallow the
transition_latencyto be greater than 10 ms.The
max_transition_latencyfield is rather used to disallow automatic dynamic frequency switching for platforms which didn't wanted these governors to run.Replace
max_transition_latencywith a boolean (dynamic_switching) and check fortransition_latency==CPUFREQ_ETERNALalong with that. This makes it pretty straight forward to read/understand now.Quoted 8 lines
Quoted 4 lines
Well, using
CPUFREQ_ETERNALfor that on the driver side is still not particularly straightforward IMO, so maybe add a "no_dynamic_switching" to the driver structure and set it to "true" for the one driver in question?IIRC it's not just one driver which sets the latency to
CPUFREQ_ETERNAL, and where dynamic switching might be harmful or at least lead to undefined behavior.OK
Still, though, using
CPUFREQ_ETERNALto indicate the "no dynamic switching" condition is somewhat convoluted, so why don't we have a flag to *explicitly* say that instead?
Quoted 6 lines
Quoted 2 lines
Do you know which drivers they are or is it just all drivers that use
CPUFREQ_ETERNAL?Well, after the $subject patch it effectively is all drivers that use
CPUFREQ_ETERNALanyway, so it looks like we actually can do a complete switch-over.
Exactly. But lets take a quick look at the drivers ussing CPUFREQ_ETERNAL:
Using CPUFREQ_ETERNAL, as policy-setting drivers:
- intel_pstate.c - for the intel_pstate driver, which defers to the hardware to do frequency selection.
- longrun.c - hardware-based frequency selection.
=> Those drivers are not interested in kernel-based dynamic frequency selection anyway.
Using CPUFREQ_ETERNAL as a fallback if transition_latency is unknown:
- arm_big_little.c
- arm_big_little_dt.c
- cpufreq-dt.c
- imx6q-cpufreq.c
- spear_cpufreq.c
=> As it seems to be an error case, it seems best to bail out on the safe side and disallow dynamic frequency scaling. Platform experts might know better, though.
Using CPUFREQ_ETERNAL unconditionally:
- cpufreq-nforce2.c - over a decade old driver; has a commented-out hack to mdelay(10ms) after each frequency transition. This smells like it might be unsafe to do dynamic switching more often than that.
- elanfreq.c - Has udelay(1ms+10ms) in transition path, so the same terms and conditions seem to apply.
- gx-suspmod.c - works by a mechanism which reminds me of CPU frequency throttling, but chipset- and not CPU-based.
- pmac32-cpufreq.c - for some models, it sets latency to ETERNAL. In some frequency switchign code, it has mdelay(10ms) calls.
- speedsstep-smi.c - this case was discussed previously.
=> For those drivers, dynamic frequency scaling should not be enabled IMO.
- sa1100-cpufreq.c and
- sa1110-cpufreq.c - If I remember correctly, those drivers were used for fast user-space based frequency scaling in the past.
=> For these two drivers, enabling DFVS might be an option.
- sh-cpufreq.c - looks fast, but I have no clue.
- unicore2-cpufreq.c - same.
=> For those drivers, I have no clue. So to be on the safe side, I'd opt for dynamic frequency scaling to be set to off.
To summarize: At first, I'd propose a *complete* switch-over from CPUFREQ_ETERNAL to setting the flag "no DVFS" you have proposed. Then, one might discuss with the maintainers of individual drivers/platforms on whether to relax this rule for a few of those drivers (sa11x0, sh-cpufreq, unicore2-cpufreq and the drivers using CPUFREQ_ETERNAL as a fallback).
Best,
Dominik
Re: [RFC V2 1/6] cpufreq: Replace "max_transition_latency" with "dynamic_switching"
Quoted 39 lines · Dominik Brodowski
Quoted 31 lines · Rafael J. Wysocki
Quoted 30 lines · Rafael J. Wysocki
Quoted 13 lines · Dominik Brodowski
Quoted 12 lines · Rafael J. Wysocki
Quoted 10 lines · Viresh Kumar
There is no limitation in the ondemand or conservative governors which disallow the
transition_latencyto be greater than 10 ms.The
max_transition_latencyfield is rather used to disallow automatic dynamic frequency switching for platforms which didn't wanted these governors to run.Replace
max_transition_latencywith a boolean (dynamic_switching) and check fortransition_latency==CPUFREQ_ETERNALalong with that. This makes it pretty straight forward to read/understand now.Quoted 8 lines
Quoted 4 lines
Well, using
CPUFREQ_ETERNALfor that on the driver side is still not particularly straightforward IMO, so maybe add a "no_dynamic_switching" to the driver structure and set it to "true" for the one driver in question?IIRC it's not just one driver which sets the latency to
CPUFREQ_ETERNAL, and where dynamic switching might be harmful or at least lead to undefined behavior.OK
Still, though, using
CPUFREQ_ETERNALto indicate the "no dynamic switching" condition is somewhat convoluted, so why don't we have a flag to *explicitly* say that instead?Quoted 6 lines
Quoted 2 lines
Do you know which drivers they are or is it just all drivers that use
CPUFREQ_ETERNAL?Well, after the $subject patch it effectively is all drivers that use
CPUFREQ_ETERNALanyway, so it looks like we actually can do a complete switch-over.
Quoted 8 lines
Exactly. But lets take a quick look at the drivers ussing
CPUFREQ_ETERNAL:Using
CPUFREQ_ETERNAL, as policy-setting drivers:-
intel_pstate.c- for theintel_pstatedriver, which defers to the hardware to do frequency selection.-
longrun.c- hardware-based frequency selection.
That may or may not be hardware-based, but if the ->setpolicy callback is present, transition_latency doesn't matter anyway.
Quoted 2 lines
=> Those drivers are not interested in kernel-based dynamic frequency selection anyway.
Right.
Quoted 8 lines
Using
CPUFREQ_ETERNALas a fallback iftransition_latencyis unknown:
-arm_big_little.c
-arm_big_little_dt.c
-cpufreq-dt.c
-imx6q-cpufreq.c
-spear_cpufreq.c
Quoted 4 lines
=> As it seems to be an error case, it seems best to bail out on the safe side and disallow dynamic frequency scaling. Platform experts might know better, though.
Well, Viresh should know what to do for some of them at least. :-)
Quoted 11 lines
Using
CPUFREQ_ETERNALunconditionally:
-cpufreq-nforce2.c- over a decade old driver; has a commented-out hack to mdelay(10ms) after each frequency transition. This smells like it might be unsafe to do dynamic switching more often than that.-
elanfreq.c- Has udelay(1ms+10ms) in transition path, so the same terms and conditions seem to apply.-
gx-suspmod.c- works by a mechanism which reminds me of CPU frequency throttling, but chipset- and not CPU-based.
Quoted 6 lines
-
pmac32-cpufreq.c- for some models, it sets latency to ETERNAL. In some frequency switchign code, it has mdelay(10ms) calls.-
speedsstep-smi.c- this case was discussed previously.=> For those drivers, dynamic frequency scaling should not be enabled IMO.
Agreed.
Quoted 6 lines
-
sa1100-cpufreq.cand
-sa1110-cpufreq.c- If I remember correctly, those drivers were used for fast user-space based frequency scaling in the past.=> For these two drivers, enabling DFVS might be an option.
OK, I'm not familiar with these.
Quoted 7 lines
-
sh-cpufreq.c- looks fast, but I have no clue.-
unicore2-cpufreq.c- same.=> For those drivers, I have no clue. So to be on the safe side, I'd opt for dynamic frequency scaling to be set to off.
Agreed.
Quoted 2 lines
To summarize: At first, I'd propose a *complete* switch-over from
CPUFREQ_ETERNALto setting the flag "no DVFS" you have proposed.
So we seem to be in agreement over this.
Quoted 3 lines
Then, one might discuss with the maintainers of individual
drivers/platformson whether to relax this rule for a few of those drivers (sa11x0, sh-cpufreq, unicore2-cpufreq and the drivers usingCPUFREQ_ETERNALas a fallback).
Right.
Thanks,
Rafael
Viresh Kumar
maintainerRe: [RFC V2 1/6] cpufreq: Replace "max_transition_latency" with "dynamic_switching"
Quoted 6 lines · Rafael J. Wysocki
Quoted 4 lines · Dominik Brodowski
Exactly. But lets take a quick look at the drivers ussing
CPUFREQ_ETERNAL:Using
CPUFREQ_ETERNAL, as policy-setting drivers:
Quoted 7 lines
Quoted 4 lines
-
intel_pstate.c- for theintel_pstatedriver, which defers to the hardware to do frequency selection.-
longrun.c- hardware-based frequency selection.That may or may not be hardware-based, but if the ->setpolicy callback is present,
transition_latencydoesn't matter anyway.
Right and to avoid confusion its probably better to avoid setting transition_latency completely from them. I will try to include that in my series.
Quoted 13 lines
Quoted 2 lines
=> Those drivers are not interested in kernel-based dynamic frequency selection anyway.
Right.
Quoted 8 lines
Using
CPUFREQ_ETERNALas a fallback iftransition_latencyis unknown:
-arm_big_little.c
-arm_big_little_dt.c
-cpufreq-dt.c
-imx6q-cpufreq.c
-spear_cpufreq.c
Quoted 6 lines
Quoted 4 lines
=> As it seems to be an error case, it seems best to bail out on the safe side and disallow dynamic frequency scaling. Platform experts might know better, though.
Well, Viresh should know what to do for some of them at least. :-)
Yeah, they just don't know how much time it takes to change the frequency. We shouldn't disallow DVFS for them.
Quoted 11 lines
Quoted 11 lines
Using
CPUFREQ_ETERNALunconditionally:
-cpufreq-nforce2.c- over a decade old driver; has a commented-out hack to mdelay(10ms) after each frequency transition. This smells like it might be unsafe to do dynamic switching more often than that.-
elanfreq.c- Has udelay(1ms+10ms) in transition path, so the same terms and conditions seem to apply.-
gx-suspmod.c- works by a mechanism which reminds me of CPU frequency throttling, but chipset- and not CPU-based.
Quoted 8 lines
Quoted 6 lines
-
pmac32-cpufreq.c- for some models, it sets latency to ETERNAL. In some frequency switchign code, it has mdelay(10ms) calls.-
speedsstep-smi.c- this case was discussed previously.=> For those drivers, dynamic frequency scaling should not be enabled IMO.
Agreed.
+1 and these are the drivers which should have this new variable set to avoid DVFS.
Anyone who is setting CPUFREQ_ETERNAL unconditionally should be setting the new flag.
Quoted 4 lines
Quoted 2 lines
To summarize: At first, I'd propose a *complete* switch-over from
CPUFREQ_ETERNALto setting the flag "no DVFS" you have proposed.So we seem to be in agreement over this.
The usage of CPUFREQ_ETERNAL had been confusing over the years, i.e. some use it to not allow ondemand/conservative, while others use it as they don't know their transition latencies.
A complete switch over may not be good for the later.
I would suggest we only move the platforms which set latency to CPUFREQ_ETERNAL unconditionally to the "no DVFS" list. And everyone else can still continue with CPUFREQ_ETERNAL. I have earlier proposed finding their latencies dynamically and will try to include that for them.
Signature · 1 line
viresh
Re: [RFC V2 1/6] cpufreq: Replace "max_transition_latency" with "dynamic_switching"
Quoted 68 lines · Viresh Kumar
Quoted 6 lines · Rafael J. Wysocki
Quoted 4 lines · Dominik Brodowski
Exactly. But lets take a quick look at the drivers ussing
CPUFREQ_ETERNAL:Using
CPUFREQ_ETERNAL, as policy-setting drivers:Quoted 7 lines
Quoted 4 lines
-
intel_pstate.c- for theintel_pstatedriver, which defers to the hardware to do frequency selection.-
longrun.c- hardware-based frequency selection.That may or may not be hardware-based, but if the ->setpolicy callback is present,
transition_latencydoesn't matter anyway.Right and to avoid confusion its probably better to avoid setting
transition_latencycompletely from them. I will try to include that in my series.Quoted 13 lines
Quoted 2 lines
=> Those drivers are not interested in kernel-based dynamic frequency selection anyway.
Right.
Quoted 8 lines
Using
CPUFREQ_ETERNALas a fallback iftransition_latencyis unknown:
-arm_big_little.c
-arm_big_little_dt.c
-cpufreq-dt.c
-imx6q-cpufreq.c
-spear_cpufreq.cQuoted 6 lines
Quoted 4 lines
=> As it seems to be an error case, it seems best to bail out on the safe side and disallow dynamic frequency scaling. Platform experts might know better, though.
Well, Viresh should know what to do for some of them at least. :-)
Yeah, they just don't know how much time it takes to change the frequency. We shouldn't disallow DVFS for them.
Quoted 11 lines
Quoted 11 lines
Using
CPUFREQ_ETERNALunconditionally:
-cpufreq-nforce2.c- over a decade old driver; has a commented-out hack to mdelay(10ms) after each frequency transition. This smells like it might be unsafe to do dynamic switching more often than that.-
elanfreq.c- Has udelay(1ms+10ms) in transition path, so the same terms and conditions seem to apply.-
gx-suspmod.c- works by a mechanism which reminds me of CPU frequency throttling, but chipset- and not CPU-based.Quoted 8 lines
Quoted 6 lines
-
pmac32-cpufreq.c- for some models, it sets latency to ETERNAL. In some frequency switchign code, it has mdelay(10ms) calls.-
speedsstep-smi.c- this case was discussed previously.=> For those drivers, dynamic frequency scaling should not be enabled IMO.
Agreed.
+1 and these are the drivers which should have this new variable set to avoid DVFS.
Anyone who is setting
CPUFREQ_ETERNALunconditionally should be setting the new flag.
Quoted 8 lines
Quoted 4 lines
Quoted 2 lines
To summarize: At first, I'd propose a *complete* switch-over from
CPUFREQ_ETERNALto setting the flag "no DVFS" you have proposed.So we seem to be in agreement over this.
The usage of
CPUFREQ_ETERNALhad been confusing over the years, i.e. some use it to not allow ondemand/conservative, while others use it as they don't know their transition latencies.
So if we can identify these, we can introduce something like CPUFREQ_LATENCY_UNKNOWN for them and get rid of CPUFREQ_ETERNAL.
Quoted 7 lines
A complete switch over may not be good for the later.
I would suggest we only move the platforms which set latency to
CPUFREQ_ETERNALunconditionally to the "no DVFS" list. And everyone else can still continue withCPUFREQ_ETERNAL. I have earlier proposed finding their latencies dynamically and will try to include that for them.
I have to admint I'm not a super-fan of that (mostly because I tried to do something similar in the past for genpd, but that didn't work out well IMO), but as long as that is done in drivers and not in the core, I can live with it.
Thanks,
Rafael
Viresh Kumar
maintainerRFC v2 2/6 cpufreq: schedutil: Set dynamic_switching to true
In reply to Viresh KumarSet dynamic_switching to 'true' to disallow use of schedutil governor for platforms with transition_latency set to CPUFREQ_ETERNAL, as they may not want to do automatic dynamic frequency switching.
--- kernel/sched/cpufreq_schedutil.c | 1 + 1 file changed, 1 insertion(+)
kernel/sched/cpufreq_schedutil.c +1 -0
@@ -650,6 +650,7 @@ static void sugov_limits(struct cpufreq_policy *policy)static struct cpufreq_governor schedutil_gov = { .name ="schedutil" , .owner =THIS_MODULE , + .dynamic_switching = true, .init = sugov_init, .exit = sugov_exit, .start = sugov_start,
Signature · 1 line
2.13.0.71.gd7076ec9c9cb
Viresh Kumar
maintainerRFC v2 3/6 cpufreq: governor: Drop min_sampling_rate
In reply to Viresh KumarThe cpufreq core and governors aren't supposed to set a limit on how fast we want to try changing the frequency. This is currently done for the legacy governors with help of min_sampling_rate.
At worst, we may end up setting the sampling rate to a value lower than the rate at which frequency can be changed and then one of the CPUs in the policy will be only changing frequency for ever.
But that is something for the user to decide and there is no need to have special handling for such cases in the core. Leave it for the user to figure out.
--- Documentation/admin-guide/pm/cpufreq.rst | 8 -------- drivers/cpufreq/cpufreq_conservative.c | 6 ------ drivers/cpufreq/cpufreq_governor.c | 10 ++-------- drivers/cpufreq/cpufreq_governor.h | 1 - drivers/cpufreq/cpufreq_ondemand.c | 12 ------------ include/linux/cpufreq.h | 2 -- 6 files changed, 2 insertions(+), 37 deletions(-)
Documentation/admin-guide/pm/cpufreq.rst +0 -8
@@ -471,14 +471,6 @@ it is allowed to use (the ``scaling_max_freq`` policy limit). # echo `$(($(cat cpuinfo_transition_latency) * 750 / 1000)) > ondemand/sampling_rate - -``min_sampling_rate`` - The minimum value of ``sampling_rate``. - - Equal to 10000 (10 ms) if :c:macro:`CONFIG_NO_HZ_COMMON` and - :c:data:`tick_nohz_active` are both set or to 20 times the value of - :c:data:`jiffies` in microseconds otherwise. - ``up_threshold`` If the estimated CPU load is above this value (in percent), the governor will set the frequency to the maximum value allowed for the policy.
drivers/cpufreq/cpufreq_conservative.c +0 -6
@@ -246,7 +246,6 @@ gov_show_one_common(sampling_rate);gov_show_one_common (sampling_down_factor);gov_show_one_common (up_threshold);gov_show_one_common (ignore_nice_load); -gov_show_one_common (min_sampling_rate);gov_show_one (cs, down_threshold);gov_show_one (cs, freq_step);
@@ -254,12 +253,10 @@ gov_attr_rw(sampling_rate);gov_attr_rw (sampling_down_factor);gov_attr_rw (up_threshold);gov_attr_rw (ignore_nice_load); -gov_attr_ro (min_sampling_rate);gov_attr_rw (down_threshold);gov_attr_rw (freq_step);static struct attribute *cs_attributes[] = { - &min_sampling_rate.attr, &sampling_rate.attr, &sampling_down_factor.attr, &up_threshold.attr,
@@ -297,10 +294,7 @@ static int cs_init(struct dbs_data *dbs_data) dbs_data->up_threshold =DEF_FREQUENCY_UP_THRESHOLD ; dbs_data->sampling_down_factor =DEF_SAMPLING_DOWN_FACTOR ; dbs_data->ignore_nice_load =0 ; - dbs_data->tuners = tuners; - dbs_data->min_sampling_rate =MIN_SAMPLING_RATE_RATIO * -jiffies_to_usecs (10 );return 0 ; }
drivers/cpufreq/cpufreq_governor.c +2 -8
@@ -47,14 +47,11 @@ ssize_t store_sampling_rate(struct gov_attr_set *attr_set, const char *buf, {struct dbs_data *dbs_data =to_dbs_data (attr_set);struct policy_dbs_info *policy_dbs; -unsigned int rate;int ret; - ret =sscanf (buf,"%u" , &rate); + ret =sscanf (buf,"%u" , &dbs_data->sampling_rate);if (ret !=1 )return -EINVAL ; - dbs_data->sampling_rate =max (rate, dbs_data->min_sampling_rate); -/* * We are operating under dbs_data->mutex and so the list and its * entries can't be freed concurrently.
@@ -437,10 +434,7 @@ int cpufreq_dbs_governor_init(struct cpufreq_policy *policy) latency =1 ;/* Bring kernel and HW constraints together */ - dbs_data->min_sampling_rate =max (dbs_data->min_sampling_rate, -MIN_LATENCY_MULTIPLIER * latency); - dbs_data->sampling_rate =max (dbs_data->min_sampling_rate, -LATENCY_MULTIPLIER * latency); + dbs_data->sampling_rate =LATENCY_MULTIPLIER * latency;if (!have_governor_per_policy ()) gov->gdbs_data = dbs_data;
drivers/cpufreq/cpufreq_governor.h +0 -1
@@ -41,7 +41,6 @@ enum {OD_NORMAL_SAMPLE, OD_SUB_SAMPLE};struct dbs_data {struct gov_attr_set attr_set;void *tuners; -unsigned int min_sampling_rate;unsigned int ignore_nice_load;unsigned int sampling_rate;unsigned int sampling_down_factor;
drivers/cpufreq/cpufreq_ondemand.c +0 -12
@@ -319,7 +319,6 @@ gov_show_one_common(sampling_rate);gov_show_one_common (up_threshold);gov_show_one_common (sampling_down_factor);gov_show_one_common (ignore_nice_load); -gov_show_one_common (min_sampling_rate);gov_show_one_common (io_is_busy);gov_show_one (od, powersave_bias);
@@ -329,10 +328,8 @@ gov_attr_rw(up_threshold);gov_attr_rw (sampling_down_factor);gov_attr_rw (ignore_nice_load);gov_attr_rw (powersave_bias); -gov_attr_ro (min_sampling_rate);static struct attribute *od_attributes[] = { - &min_sampling_rate.attr, &sampling_rate.attr, &up_threshold.attr, &sampling_down_factor.attr,
@@ -373,17 +370,8 @@ static int od_init(struct dbs_data *dbs_data)if (idle_time !=-1ULL ) {/* Idle micro accounting is supported. Use finer thresholds */ dbs_data->up_threshold =MICRO_FREQUENCY_UP_THRESHOLD ; -/* -* In nohz/micro accounting case we set the minimum frequency -* not depending on HZ, but fixed (very low). -*/ - dbs_data->min_sampling_rate =MICRO_FREQUENCY_MIN_SAMPLE_RATE ; }else { dbs_data->up_threshold =DEF_FREQUENCY_UP_THRESHOLD ; - -/* For correct statistics, we need 10 ticks for each measure */ - dbs_data->min_sampling_rate =MIN_SAMPLING_RATE_RATIO * -jiffies_to_usecs (10 ); } dbs_data->sampling_down_factor =DEF_SAMPLING_DOWN_FACTOR ;
include/linux/cpufreq.h +0 -2
@@ -488,9 +488,7 @@ static inline unsigned long cpufreq_scale(unsigned long old, u_int div,* ondemand governor will work on any processor with transition latency <= 10ms, * using appropriate sampling rate. */ -#define MIN_SAMPLING_RATE_RATIO (2)#define LATENCY_MULTIPLIER (1000) -#define MIN_LATENCY_MULTIPLIER (20)struct cpufreq_governor {char name[CPUFREQ_NAME_LEN ];
Signature · 1 line
2.13.0.71.gd7076ec9c9cb
Viresh Kumar
maintainerRFC v2 4/6 cpufreq: Use transition_delay_us for legacy governors as well
In reply to Viresh KumarThe policy->transition_delay_us field is used only by the schedutil governor currently, and this field describes how fast the driver wants the cpufreq governor to change CPUs frequency. It should rather be a common thing across all governors, as it doesn't have any schedutil dependency here.
Create a new helper cpufreq_policy_transition_delay_us() to get the transition delay across all governors.
--- drivers/cpufreq/cpufreq_governor.c | 9 +-------- include/linux/cpufreq.h | 15 +++++++++++++++ kernel/sched/cpufreq_schedutil.c | 11 +---------- 3 files changed, 17 insertions(+), 18 deletions(-)
drivers/cpufreq/cpufreq_governor.c +1 -8
@@ -389,7 +389,6 @@ int cpufreq_dbs_governor_init(struct cpufreq_policy *policy)struct dbs_governor *gov =dbs_governor_of (policy);struct dbs_data *dbs_data;struct policy_dbs_info *policy_dbs; -unsigned int latency;int ret =0 ;/* State should be equivalent to EXIT */
@@ -428,13 +427,7 @@ int cpufreq_dbs_governor_init(struct cpufreq_policy *policy)if (ret) goto free_policy_dbs_info; -/* policy latency is in ns. Convert it to us first */ - latency = policy->cpuinfo.transition_latency /1000 ; -if (latency ==0 ) - latency =1 ; - -/* Bring kernel and HW constraints together */ - dbs_data->sampling_rate =LATENCY_MULTIPLIER * latency; + dbs_data->sampling_rate =cpufreq_policy_transition_delay_us (policy);if (!have_governor_per_policy ()) gov->gdbs_data = dbs_data;
include/linux/cpufreq.h +15 -0
@@ -532,6 +532,21 @@ static inline void cpufreq_policy_apply_limits(struct cpufreq_policy *policy)__cpufreq_driver_target (policy, policy->min,CPUFREQ_RELATION_L ); } +static inline unsigned int +cpufreq_policy_transition_delay_us (struct cpufreq_policy *policy) +{ +unsigned int delay_us =LATENCY_MULTIPLIER , latency; + +if (policy->transition_delay_us) +return policy->transition_delay_us; + + latency = policy->cpuinfo.transition_latency /NSEC_PER_USEC ; +if (latency) + delay_us *= latency; + +return delay_us; +} +/* Governor attribute set */ struct gov_attr_set {struct kobject kobj;
kernel/sched/cpufreq_schedutil.c +1 -10
@@ -528,16 +528,7 @@ static int sugov_init(struct cpufreq_policy *policy) goto stop_kthread; } -if (policy->transition_delay_us) { - tunables->rate_limit_us = policy->transition_delay_us; - }else { -unsigned int lat; - - tunables->rate_limit_us =LATENCY_MULTIPLIER ; - lat = policy->cpuinfo.transition_latency /NSEC_PER_USEC ; -if (lat) - tunables->rate_limit_us *= lat; - } + tunables->rate_limit_us =cpufreq_policy_transition_delay_us (policy); policy->governor_data = sg_policy; sg_policy->tunables = tunables;
Signature · 1 line
2.13.0.71.gd7076ec9c9cb
Rafael J. Wysocki
maintainerRe: [RFC V2 4/6] cpufreq: Use transition_delay_us for legacy governors as well
Quoted 55 lines · Viresh Kumar
The
policy->transition_delay_usfield is used only by the schedutil governor currently, and this field describes how fast the driver wants the cpufreq governor to change CPUs frequency. It should rather be a common thing across all governors, as it doesn't have any schedutil dependency here.Create a new helper
cpufreq_policy_transition_delay_us()to get the transition delay across all governors.Signed-off-by Viresh Kumar <[email protected]>--- drivers/cpufreq/cpufreq_governor.c | 9 +-------- include/linux/cpufreq.h | 15 +++++++++++++++ kernel/sched/cpufreq_schedutil.c | 11 +---------- 3 files changed, 17 insertions(+), 18 deletions(-)drivers/cpufreq/cpufreq_governor.c +1
-8@@ -389,7 +389,6 @@ int cpufreq_dbs_governor_init(struct cpufreq_policy *policy)struct dbs_governor *gov =dbs_governor_of (policy);struct dbs_data *dbs_data;struct policy_dbs_info *policy_dbs; -unsigned int latency;int ret =0 ;/* State should be equivalent to EXIT */ @@ -428,13 +427,7 @@ int cpufreq_dbs_governor_init(struct cpufreq_policy *policy)if (ret) goto free_policy_dbs_info; -/* policy latency is in ns. Convert it to us first */ - latency = policy->cpuinfo.transition_latency /1000 ; -if (latency ==0 ) - latency =1 ; - -/* Bring kernel and HW constraints together */ - dbs_data->sampling_rate =LATENCY_MULTIPLIER * latency; + dbs_data->sampling_rate =cpufreq_policy_transition_delay_us (policy);if (!have_governor_per_policy ()) gov->gdbs_data = dbs_data;include/linux/cpufreq.h +4
-0@@ -532,6 +532,21 @@ static inline void cpufreq_policy_apply_limits(struct cpufreq_policy *policy)__cpufreq_driver_target (policy, policy->min,CPUFREQ_RELATION_L ); } +static inline unsigned int +cpufreq_policy_transition_delay_us (struct cpufreq_policy *policy) +{ +unsigned int delay_us =LATENCY_MULTIPLIER , latency;
include/linux/cpufreq.h static inline void cpufreq_policy_apply_limits(struct cpufreq_policy *policy) · line 548
Quoted 10 lines
include/linux/cpufreq.h +10
-0+ +if (policy->transition_delay_us) +return policy->transition_delay_us; + + latency = policy->cpuinfo.transition_latency /NSEC_PER_USEC ; +if (latency) + delay_us *= latency; + +return delay_us; +}
Not in the header, please, and I don't think you need delay_us:
latency = policy->cpuinfo.transition_latency / NSEC_PER_USEC;
if (latency)
return latency * LATENCY_MULTIPLIER;
return LATENCY_MULTIPLIER;Thanks,
Rafael
Viresh Kumar
maintainerRFC v2 5/6 cpufreq: Cap the default transition delay value to 10 ms
In reply to Viresh KumarIf transition_delay_us isn't defined by the cpufreq driver, the default value of transition delay (time after which the cpufreq governor will try updating the frequency again) is currently calculated by multiplying transition_latency (nsec) with LATENCY_MULTIPLIER (1000) and then converting this time to usec. That gives the exact same value as transition_latency, just that the time unit is usec instead of nsec.
With acpi-cpufreq for example, transition_latency is set to around 10 usec and we get transition delay as 10 ms. Which seems to be a reasonable amount of time to reevaluate the frequency again.
But for platforms where frequency switching isn't that fast (like ARM), the transition_latency varies from 500 usec to 3 ms, and the transition delay becomes 500 ms to 3 seconds. Of course, that is a pretty bad default value to start with.
We can try to come across a better formula (instead of multiplying with LATENCY_MULTIPLIER) to solve this problem, but will that be worth it ?
This patch tries a simple approach and caps the maximum value of default transition delay to 10 ms. Of course, userspace can still come in and change this value anytime or individual drivers can rather provide transition_delay_us instead.
--- include/linux/cpufreq.h | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-)
include/linux/cpufreq.h +11 -1
@@ -544,7 +544,17 @@ cpufreq_policy_transition_delay_us(struct cpufreq_policy *policy)if (latency) delay_us *= latency; -return delay_us; +/* +* For platforms that can change the frequency very fast (< 10 us), +* the above formula gives a decent transition delay. But for platforms +* where transition_latency is in milliseconds, it ends up giving +* unrealistic values. +* +* Cap the default transition delay to 10 ms, which seems to be a +* reasonable amount of time after which we should reevaluate the +* frequency. +*/ +return min (delay_us, (unsigned int )10000 ); }/* Governor attribute set */
Signature · 1 line
2.13.0.71.gd7076ec9c9cb
Viresh Kumar
maintainerRFC v2 6/6 cpufreq: arm_big_little: Make ->get_transition_latency() mandatory
In reply to Viresh KumarAll users of arm_big_little driver are defining it and there is no need to keep it optional.
Make it mandatory to remove the always true conditional statement.
--- drivers/cpufreq/arm_big_little.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-)
drivers/cpufreq/arm_big_little.c +4 -6
@@ -483,11 +483,8 @@ static int bL_cpufreq_init(struct cpufreq_policy *policy)return ret; } -if (arm_bL_ops->get_transition_latency) - policy->cpuinfo.transition_latency = - arm_bL_ops->get_transition_latency (cpu_dev); -else - policy->cpuinfo.transition_latency =CPUFREQ_ETERNAL ; + policy->cpuinfo.transition_latency = + arm_bL_ops->get_transition_latency (cpu_dev);if (is_bL_switching_enabled ())per_cpu (cpu_last_req_freq, policy->cpu) =clk_get_cpu_rate (policy->cpu);
@@ -622,7 +619,8 @@ int bL_cpufreq_register(struct cpufreq_arm_bL_ops *ops)return -EBUSY ; } -if (!ops || !strlen (ops->name) || !ops->init_opp_table) { +if (!ops || !strlen (ops->name) || !ops->init_opp_table || + !ops->get_transition_latency) {pr_err ("%s: Invalid arm_bL_ops, exiting\n" , __func__);return -ENODEV ; }
Signature · 1 line
2.13.0.71.gd7076ec9c9cb