提交 1e3910c7 编写于 作者: R Rafael J. Wysocki 提交者: Cheng Jian

cpuidle: menu: Avoid computations when result will be discarded

mainline inclusion
from mainline-5.14-rc7
commit f1c8e410
category: bugfix
bugzilla: https://gitee.com/openeuler/kernel/issues/I48J5M
CVE: NA

-------------------------------------------------

bug: 73520

If the minimum interval taken into account in the average computation
loop in get_typical_interval() is less than the expected idle
duration determined so far, the resultant average cannot be greater
than that value as well and the entire return result of the function
is going to be discarded anyway going forward.

In that case, it is a waste of time to carry out the remaining
computations in get_typical_interval(), so avoid that by returning
early if the minimum interval is not below the expected idle duration.

[liuyun01@kylinos.cn: in theory, this patch did not do much work, but
due to the addition of the previous patch eee4b653 ("cpuidle:
menu: Avoid overflows when computing variance"), the value of thresh
was adjusted from UINT_MAX to INT_MAX, which led to the possibility
of dividing by 0, which eventually led to panic.]

Fixes: eee4b653 ("cpuidle: menu: Avoid overflows when computing variance")
(cherry-picked from f1c8e410)
Cc: stable
Signed-off-by: NRafael J. Wysocki <rafael.j.wysocki@intel.com>
Signed-off-by: Jackie Liu <liuyun01@kylinos.cn>		# openEuler_contributor
Tested-by: Nkernelbot <kernel-bot@kylinos.cn>
Reviewed-by: NXie XiuQi <xiexiuqi@huawei.com>
Signed-off-by: NCheng Jian <cj.chengjian@huawei.com>
上级 ff7d1fc3
......@@ -197,10 +197,11 @@ static void menu_update(struct cpuidle_driver *drv, struct cpuidle_device *dev);
* of points is below a threshold. If it is... then use the
* average of these 8 points as the estimated value.
*/
static unsigned int get_typical_interval(struct menu_device *data)
static unsigned int get_typical_interval(struct menu_device *data,
unsigned int predicted_us)
{
int i, divisor;
unsigned int max, thresh, avg;
unsigned int max, min, thresh, avg;
uint64_t sum, variance;
thresh = INT_MAX; /* Discard outliers above this value */
......@@ -208,6 +209,7 @@ static unsigned int get_typical_interval(struct menu_device *data)
again:
/* First calculate the average of past intervals */
min = UINT_MAX;
max = 0;
sum = 0;
divisor = 0;
......@@ -218,8 +220,18 @@ static unsigned int get_typical_interval(struct menu_device *data)
divisor++;
if (value > max)
max = value;
if (value < min)
min = value;
}
}
/*
* If the result of the computation is going to be discarded anyway,
* avoid the computation altogether.
*/
if (min >= predicted_us)
return UINT_MAX;
if (divisor == INTERVALS)
avg = sum >> INTERVAL_SHIFT;
else
......@@ -319,7 +331,7 @@ static int menu_select(struct cpuidle_driver *drv, struct cpuidle_device *dev,
data->correction_factor[data->bucket],
RESOLUTION * DECAY);
expected_interval = get_typical_interval(data);
expected_interval = get_typical_interval(data, data->predicted_us);
expected_interval = min(expected_interval, data->next_timer_us);
first_idx = 0;
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册