Re: [PATCH v2] PM: EM: Exclude boost frequencies from inefficiency ranking
From: Guo Chen
Date: Wed Nov 11 2026 - 07:08:05 EST
On 11/11/2026 7:24 PM, Zhongqiu Han wrote:
On 11/11/2026 5:31 PM, Lukasz Luba wrote:
On 11/11/26 06:57, Guo Chen wrote:
On 11/10/2026 10:59 PM, Rafael J. Wysocki (Intel) wrote:
On Tue, Nov 10, 2026 at 3:56 PM Zhongqiu Han
<zhongqiu.han@xxxxxxxxxxxxxxxx> wrote:
On 11/10/2026 10:05 PM, Lukasz Luba wrote:
On 11/10/26 13:43, Rafael J. Wysocki (Intel) wrote:
On Tue, Nov 10, 2026 at 2:11 PM Lukasz Luba <lukasz.luba@xxxxxxx> wrote:Hi Rafael,So maybe this is the one that needs to be fixed? What about simply
On 11/10/26 12:15, Rafael J. Wysocki (Intel) wrote:
On Tue, Nov 10, 2026 at 10:58 AM Lukasz Luba <lukasz.luba@xxxxxxx>[snip]
wrote:
The ondemand is affected by the EM setup code and set 'inefficient'That's fine, please continue.I have a couple of questions though.
First, why is the ondemand governor mentioned in the changelog? In
the mainline, the ondemand governor cannot work with EAS, so it
shouldn't matter for this issue, should it?
flags for some OPPs. The EM is also present for cooling devices
and can work w/o EAS and schedutil, w/ just ondemand governor.
Because EM marks the OPPs kind of 'globally' as inefficient, then
they become CPUFREQ_INEFFICIENT_FREQ entries in the CPUfreq fwk.
In the EM code we have:
cpufreq_table_set_inefficient(policy, table[i].frequency);
skipping boost frequencies in it?
Then ondemand check for CPUFREQ_RELATION_HE will skip them andThanks for explaining and all of that needs to be said in the patch
pass to __cpufreq_driver_target() with that flags as well.
changelog.
To be precise, the EM initialization may affect cpufreq in generalSecond, why is the issue regarded as a defect in the code and not inIMHO it was a bug in the commit mentioned in this patch fix tag.
the energy model? Arguably, boost frequencies should be more costly
than the non-boost ones. At least the idea behind the boost is making
higher-cost OPPs temporarily available. If they are sustainable,
treating them as boost OPPs is rather pointless.
It is affecting more than just EAS or EM, since the EM is working with
all generic code and all cpufreq governors.
because inefficient frequencies are used for CPU cooling. Fair
enough, but I'm not talking about this.
I'm talking about a reason for giving boost frequencies lower or equal
cost relative to non-boost frequencies in the energy model because
this doesn't make sense to me TBH.
And I get that such energy models were there before the commit in
question and now they are not working properly, but IMO they are
broken, not that commit.
There's nothing wrong with using the information from the energyTBH, I'm too comfortable with looking at cpufreq frequency from withinI think this edge case is special, as I described above.
the EM code. If that needs to be done, something is amiss at the
design level.
I'm happy to hear your view on this EM influence to some global
setting in cpufreq. Maybe it was too far to establish this
'inefficiency' flags in there for many usage?
model, when available, to amend cpufreq, but the patch goes the other
way around: It tries to amend the energy model with information taken
from cpufreq (in order to avoid making mistakes later when amending
cpufreq with the energy model information).
I think that cpufreq should simply refuse to set
CPUFREQ_INEFFICIENT_FREQ for boost frequencies. Wouldn't that work?
Got your point. Having cpufreq directly refuse to set
CPUFREQ_INEFFICIENT_FREQ might be the simplest approach. Let me
summarize my understanding. There are two cases where we can
simply avoid setting the CPUFREQ_INEFFICIENT_FREQ flag:
1. boost frequencies.
2. the highest non-boost frequency.
However, there is another issue. If we refuse to set
CPUFREQ_INEFFICIENT_FREQ for certain frequencies, I think the
corresponding EM_PERF_STATE_INEFFICIENT flags in the Energy Model
also need to be updated. Otherwise, the EM state would be inconsistent
with the frequencies used for energy estimation in the EAS path.
I think we also need to update the EM_PERF_STATE_INEFFICIENT flags
accordingly, something like the following:
for (i = 0; i < pd->nr_perf_states; i++) {
int ret;
if (!(table[i].flags & EM_PERF_STATE_INEFFICIENT))
continue;
/*Return -EOPNOTSUPP if the rejection condition is met. */
ret = cpufreq_table_set_inefficient(policy, table[i].frequency);
if (!ret)
found++;
else if (ret == -EOPNOTSUPP)
table[i].flags &= ~EM_PERF_STATE_INEFFICIENT;
}
I see your point now, about the direction. Yes, you're right.I also agree this should be fixed in cpufreq rather than by feeding
Since we are taking the information about 'boost' from the
cpufreq, then refusing to set OPPs inefficient in the first
place makes more sense.
cpufreq information into the EM. However, refusing
CPUFREQ_INEFFICIENT_FREQ for boost frequencies seems not help the
example in the changelog, because the frequency marked as inefficient
there is 4.0 GHz, which is not a boost one. The problem is not specific
to boost either: with 3.9 GHz, 4.0 GHz, 4.1 GHz and a 4.2 GHz boost OPP
at costs C - d, C, C and C + d, 4.0 GHz is rightly inefficient, but if
policy->max is capped at 4.0 GHz by scaling_max_freq, thermal or QoS,
RELATION_HE for 4.0 GHz still resolves to 3.9 GHz. I think the lookup
should not skip an inefficient frequency when the next efficient
frequency above it is beyond the max limit, which can be done in
cpufreq_frequency_table_target() without touching the EM or looking at
boost flags.
@Zhongqiu: thanks for the example. I think the two cases are different in
nature.
In the case of the changelog, the highest non-boost frequency of cluster is
marked inefficient because of the boost frequency. A sustainable frequency is
being affected by an unsustainable one, but it is not really inefficient: I
don't think these two kinds of frequencies should be compared with each other
in terms of energy. So I think this should be fixed at the source, by not
marking such frequencies as inefficient.
The case you describe looks different, as it is dynamic: policy->max is
changed at runtime by scaling_max_freq, thermal or QoS, which would mean
ignoring the inefficient flag every time policy->max lands on an inefficient
frequency. Whether this is really necessary seems to me to deserve a
discussion. Thermal and QoS limits are there to keep the frequency from going
above the cap. In your example (3.9 GHz, 4.0 GHz, 4.1 GHz), if the frequency is
limited to 4.0 GHz at some point and ends up on 3.9 GHz because 4.0 GHz is
inefficient, the original purpose of the limit, not going above the cap, is
still honoured.
Hi Guo,
Boost can be switched on and off at runtime as well, so it is no less dynamic than thermal or QoS. And with boost off, 3.9 GHz does not go above the cap either, so if that were enough, the changelog case would not need fixing; in both cases the highest allowed frequency is never reached.
Thanks, Zhongqiu, and Lukasz for the DT example.
You are right that boost can be switched at runtime like thermal or QoS,
so the key point I see is not about being dynamic. It is that a boost
frequency is not sustainable, and I don't think it makes sense to rank it
against the sustainable ones in terms of energy.
I agree with Lukasz's suggestion to address this in two steps.
For the first step, I think fixing the EM is necessary because the EM is
intended to balance performance and energy cost. The flag needs to
be corrected at the source because it is also used by the EAS path. If
we leave the flag unchanged and only adjust the cpufreq path to
select an appropriate frequency, even if that frequency is marked as
inefficient, we would end up with inconsistent behavior between EAS
and cpufreq.
For example, suppose 4.0 GHz is the highest non-boost frequency,
but it is marked as inefficient due to the presence of a 4.1 GHz boost
frequency. With only the cpufreq-side change you suggested, EAS
would still never use 4.0 GHz for energy evaluation because it
remains marked as inefficient in the EM.
So my understanding is that the first step Lukasz suggested is not
only about fixing the current impact of the EM on cpufreq, but also
about making the EM itself correct for the EAS path.
As for the separate issue where policy->max is set to an inefficient
frequency by thermal/QoS constraints and that frequency then
cannot be selected, I think that should be treated as a different
problem.
What do you think?
There are platforms which have ~20 OPPs and the difference is ~100MHz.
Those at the top frequency they are inefficient but exist for this
thermal purpose. The throttled frequency can be more stable and
predictable in time, thus also capacity delivered to randomly
scheduled tasks (which might be unfair if the freq gets lower
by a lot and some latency sensitive task got a spin at the same time).
Therefore, we do care by making each OPP (at least) available...
Agreed with Lukasz in this point.
So I am not sure that handling the dynamic case is needed, and I would like to
hear what you, Rafael and Lukasz think about it.
This becomes even more convoluted now.
1. The only call to cpufreq_table_set_inefficient() is in the EM.
2. EM works with thermal and all governors, not only EAS and schedutil
3. CPUfreq fwk holds those 'inefficient' flags in generic, global way
4. Inefficient flags were introduces mainly for EAS, now impacts
non-EAS setup (as patch states 4.0GHz is valid but not reachable).
Here is an example from mainline DT platform. The goal was to avoid
the frequencies which have the same voltage but lower freq, e.g.
those from 200MHz to 700MHz and pick 800MHz instead.
Same for 900MHz and 1200MHz.
That was the main motivation back then and research we've made
with a few platforms and EAS.
freq MHz opp-microvolt
2000 <1312500 1312500 1500000>
1900 <1262500 1262500 1500000>
1800 <1237500 1237500 1500000>
1700 <1250000 1250000 1500000>
1600 <1250000 1250000 1500000>
1500 <1100000 1100000 1500000>
1400 <1100000 1100000 1500000>
1300 <1100000 1100000 1500000>
1200 <1000000 1000000 1500000>
1100 <1000000 1000000 1500000>
1000 <1000000 1000000 1500000>
900 <1000000 1000000 1500000>
800 <900000 900000 1500000>
700 <900000 900000 1500000>
600 <900000 900000 1500000>
500 <900000 900000 1500000>
400 <900000 900000 1500000>
300 <900000 900000 1500000>
200 <900000 900000 1500000>
Therefore, I would suggest to tackle this is steps.
1st, let's go ahead with this fix which is for mainly EM.
The EM confuses the cpufreq and then the clients like ondemand, IMHO.
This can go maybe into the stable kernels, since it's small.
2nd, let's think about that 'boost' thing wider. There are
already investigations how to handle correctly the CPU's capacity
and to not confuse the task scheduler. This might create
the right infrastructure.
Hi Lukasz,
Thanks for the explanation and the DT example. Real platform data like
this is very helpful for this discussion.
May I know wouldn't it be better to handle this in cpufreq alone,
without changing the EM? The EM change may not help with thermal capping
in general: your DT example has no boost OPPs, and if policy->max is
capped at 1700 MHz, RELATION_HE for max seems to resolve to 1500 MHz, as
1600 and 1700 MHz are dominated by 1800 MHz.
When the target is at or above max, the highest frequency within the
limits is wanted. If it is marked inefficient, the frequency that
dominates it is above max and cannot be selected, so maybe it should
not be skipped. That would cover boost off, scaling_max_freq, thermal
and QoS, while targets below max are not affected.
Something like the below (compile-tested only). (Please let me know
what you and Rafael and Guo think, or if I have overlooked anything if
you would like)
diff
--- a/include/linux/cpufreq.h
+++ b/include/linux/cpufreq.h
@@ -1077,6 +1077,7 @@ static inline int cpufreq_frequency_table_target(struct cpufreq_policy *policy,
{
bool efficiencies = policy->efficiencies_available &&
(relation & CPUFREQ_RELATION_E);
+ bool capped = false;
int idx;
/* cpufreq_table_index_unsorted() has no use for this flag anyway */
@@ -1085,6 +1086,16 @@ static inline int cpufreq_frequency_table_target(struct cpufreq_policy *policy,
if (unlikely(policy->freq_table_sorted == CPUFREQ_TABLE_UNSORTED))
return cpufreq_table_index_unsorted(policy, target_freq, min,
max, relation);
+
+ /*
+ * A target at or above @max asks for the highest frequency within the
+ * limits. Whatever makes that frequency inefficient lies above @max and
+ * cannot be selected, so inefficient frequencies must not be skipped.
+ */
+ if (efficiencies && target_freq >= max) {
+ efficiencies = false;
+ capped = true;
+ }
retry:
switch (relation) {
case CPUFREQ_RELATION_L:
@@ -1102,9 +1113,18 @@ static inline int cpufreq_frequency_table_target(struct cpufreq_policy *policy,
}
/* Limit frequency index to honor min and max */
- if (!cpufreq_is_in_limits(policy, min, max, idx) && efficiencies) {
- efficiencies = false;
- goto retry;
+ if (!cpufreq_is_in_limits(policy, min, max, idx)) {
+ /* Fall back to the regular lookup over efficient frequencies */
+ if (capped) {
+ capped = false;
+ efficiencies = true;
+ goto retry;
+ }
+
+ if (efficiencies) {
+ efficiencies = false;
+ goto retry;
+ }
}
return idx;
Side note:
I personally don't like calling some frequencies 'boost', because
such frequencies were there but not labeled that way and they were
OK. In this example, 4.0GHz is non-boost freq, but 4.1GHz is 'boost'.
At the same time 4.0GHz is 'inefficient', which can only happen
when 4.1GHz has the same voltage. I have seen such platforms ~13years
ago and the 'boost' flag wasn't needed to handle them properly.