Patchwork [1/1] cpuidle: menu: fixed wrapping timers at 4.294 seconds

login
register
mail settings
Submitter Colin King
Date June 22, 2011, 9:40 a.m.
Message ID <1308735645-5298-2-git-send-email-colin.king@canonical.com>
Download mbox | patch
Permalink /patch/101424/
State New
Headers show

Comments

Colin King - June 22, 2011, 9:40 a.m.
From: Tero Kristo <tero.kristo@nokia.com>

Cpuidle menu governor is using u32 as a temporary datatype for storing
nanosecond values which wrap around at 4.294 seconds. This causes errors
in predicted sleep times resulting in higher than should be C state
selection and increased power consumption. This also breaks cpuidle
state residency statistics.

cc: stable@kernel.org # .32.x through .39.x
Signed-off-by: Tero Kristo <tero.kristo@nokia.com>
Signed-off-by: Len Brown <len.brown@intel.com>
---
 drivers/cpuidle/governors/menu.c |    4 +++-
 1 files changed, 3 insertions(+), 1 deletions(-)
Stefan Bader - June 22, 2011, 12:41 p.m.
On 22.06.2011 11:40, Colin King wrote:
> From: Tero Kristo <tero.kristo@nokia.com>
> 
> Cpuidle menu governor is using u32 as a temporary datatype for storing
> nanosecond values which wrap around at 4.294 seconds. This causes errors
> in predicted sleep times resulting in higher than should be C state
> selection and increased power consumption. This also breaks cpuidle
> state residency statistics.
> 
> cc: stable@kernel.org # .32.x through .39.x
> Signed-off-by: Tero Kristo <tero.kristo@nokia.com>
> Signed-off-by: Len Brown <len.brown@intel.com>
> ---
>  drivers/cpuidle/governors/menu.c |    4 +++-
>  1 files changed, 3 insertions(+), 1 deletions(-)
> 
> diff --git a/drivers/cpuidle/governors/menu.c b/drivers/cpuidle/governors/menu.c
> index f508690..c47f3d0 100644
> --- a/drivers/cpuidle/governors/menu.c
> +++ b/drivers/cpuidle/governors/menu.c
> @@ -237,6 +237,7 @@ static int menu_select(struct cpuidle_device *dev)
>  	unsigned int power_usage = -1;
>  	int i;
>  	int multiplier;
> +	struct timespec t;
>  
>  	if (data->needs_update) {
>  		menu_update(dev);
> @@ -251,8 +252,9 @@ static int menu_select(struct cpuidle_device *dev)
>  		return 0;
>  
>  	/* determine the expected residency time, round up */
> +	t = ktime_to_timespec(tick_nohz_get_sleep_length());
>  	data->expected_us =
> -	    DIV_ROUND_UP((u32)ktime_to_ns(tick_nohz_get_sleep_length()), 1000);
> +		t.tv_sec * USEC_PER_SEC + t.tv_nsec / NSEC_PER_USEC;
>  
>  
>  	data->bucket = which_bucket(data->expected_us);

Clean pick and also queued for upstream stable.

Acked-by: Stefan Bader <stefan.bader@canonical.com>

Patch

diff --git a/drivers/cpuidle/governors/menu.c b/drivers/cpuidle/governors/menu.c
index f508690..c47f3d0 100644
--- a/drivers/cpuidle/governors/menu.c
+++ b/drivers/cpuidle/governors/menu.c
@@ -237,6 +237,7 @@  static int menu_select(struct cpuidle_device *dev)
 	unsigned int power_usage = -1;
 	int i;
 	int multiplier;
+	struct timespec t;
 
 	if (data->needs_update) {
 		menu_update(dev);
@@ -251,8 +252,9 @@  static int menu_select(struct cpuidle_device *dev)
 		return 0;
 
 	/* determine the expected residency time, round up */
+	t = ktime_to_timespec(tick_nohz_get_sleep_length());
 	data->expected_us =
-	    DIV_ROUND_UP((u32)ktime_to_ns(tick_nohz_get_sleep_length()), 1000);
+		t.tv_sec * USEC_PER_SEC + t.tv_nsec / NSEC_PER_USEC;
 
 
 	data->bucket = which_bucket(data->expected_us);