| From 1c6fe0364fa7bf28248488753ee0afb6b759cd04 Mon Sep 17 00:00:00 2001 |
| From: Arjan van de Ven <arjan@linux.intel.com> |
| Date: Sat, 8 May 2010 15:47:37 -0700 |
| Subject: cpuidle: Fix incorrect optimization |
| |
| From: Arjan van de Ven <arjan@linux.intel.com> |
| |
| commit 1c6fe0364fa7bf28248488753ee0afb6b759cd04 upstream. |
| |
| commit 672917dcc78 ("cpuidle: menu governor: reduce latency on exit") |
| added an optimization, where the analysis on the past idle period moved |
| from the end of idle, to the beginning of the new idle. |
| |
| Unfortunately, this optimization had a bug where it zeroed one key |
| variable for new use, that is needed for the analysis. The fix is |
| simple, zero the variable after doing the work from the previous idle. |
| |
| During the audit of the code that found this issue, another issue was |
| also found; the ->measured_us data structure member is never set, a |
| local variable is always used instead. |
| |
| Signed-off-by: Arjan van de Ven <arjan@linux.intel.com> |
| Cc: Corrado Zoccolo <czoccolo@gmail.com> |
| Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> |
| |
| --- |
| drivers/cpuidle/governors/menu.c | 9 ++++----- |
| 1 file changed, 4 insertions(+), 5 deletions(-) |
| |
| --- a/drivers/cpuidle/governors/menu.c |
| +++ b/drivers/cpuidle/governors/menu.c |
| @@ -101,7 +101,6 @@ struct menu_device { |
| |
| unsigned int expected_us; |
| u64 predicted_us; |
| - unsigned int measured_us; |
| unsigned int exit_us; |
| unsigned int bucket; |
| u64 correction_factor[BUCKETS]; |
| @@ -187,14 +186,14 @@ static int menu_select(struct cpuidle_de |
| int i; |
| int multiplier; |
| |
| - data->last_state_idx = 0; |
| - data->exit_us = 0; |
| - |
| if (data->needs_update) { |
| menu_update(dev); |
| data->needs_update = 0; |
| } |
| |
| + data->last_state_idx = 0; |
| + data->exit_us = 0; |
| + |
| /* Special case when user has set very strict latency requirement */ |
| if (unlikely(latency_req == 0)) |
| return 0; |
| @@ -294,7 +293,7 @@ static void menu_update(struct cpuidle_d |
| new_factor = data->correction_factor[data->bucket] |
| * (DECAY - 1) / DECAY; |
| |
| - if (data->expected_us > 0 && data->measured_us < MAX_INTERESTING) |
| + if (data->expected_us > 0 && measured_us < MAX_INTERESTING) |
| new_factor += RESOLUTION * measured_us / data->expected_us; |
| else |
| /* |