aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/cpuidle
diff options
context:
space:
mode:
authorTuukka Tikkanen <tuukka.tikkanen@linaro.org>2013-08-14 12:02:41 -0400
committerRafael J. Wysocki <rafael.j.wysocki@intel.com>2013-08-22 18:24:16 -0400
commit51f245b895e3fe4cbac0b2633e54a1830864a83f (patch)
tree15391fbf91a242be303522edb0642fb6ff130e19 /drivers/cpuidle
parentdecd51bbcd7fd949840da4cc634f6b70baa1b512 (diff)
cpuidle: Change struct menu_device field types
Field predicted_us value can never exceed expected_us value, but it has a potentially larger type. As there is no need for additional 32 bits of zeroes on 32 bit plaforms, change the type of predicted_us to match the type of expected_us. Field correction_factor is used to store a value that cannot exceed the product of RESOLUTION and DECAY (default 1024*8 = 8192). The constants cannot in practice be incremented to such values, that they'd overflow unsigned int even on 32 bit systems, so the type is changed to avoid unnecessary 64 bit arithmetic on 32 bit systems. One multiplication of (now) 32 bit values needs an added cast to avoid truncation of the result and has been added. In order to avoid another multiplication from 32 bit domain to 64 bit domain, the new correction_factor calculation has been changed from new = old * (DECAY-1) / DECAY to new = old - old / DECAY, which with infinite precision would yeild exactly the same result, but now changes the direction of rounding. The impact is not significant as the maximum accumulated difference cannot exceed the value of DECAY, which is relatively small compared to product of RESOLUTION and DECAY (8 / 8192). Signed-off-by: Tuukka Tikkanen <tuukka.tikkanen@linaro.org> Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Diffstat (limited to 'drivers/cpuidle')
-rw-r--r--drivers/cpuidle/governors/menu.c28
1 files changed, 17 insertions, 11 deletions
diff --git a/drivers/cpuidle/governors/menu.c b/drivers/cpuidle/governors/menu.c
index a8b31b0ca57f..cf7f2f0e4ef5 100644
--- a/drivers/cpuidle/governors/menu.c
+++ b/drivers/cpuidle/governors/menu.c
@@ -123,10 +123,10 @@ struct menu_device {
123 int needs_update; 123 int needs_update;
124 124
125 unsigned int expected_us; 125 unsigned int expected_us;
126 u64 predicted_us; 126 unsigned int predicted_us;
127 unsigned int exit_us; 127 unsigned int exit_us;
128 unsigned int bucket; 128 unsigned int bucket;
129 u64 correction_factor[BUCKETS]; 129 unsigned int correction_factor[BUCKETS];
130 unsigned int intervals[INTERVALS]; 130 unsigned int intervals[INTERVALS];
131 int interval_ptr; 131 int interval_ptr;
132}; 132};
@@ -321,8 +321,13 @@ static int menu_select(struct cpuidle_driver *drv, struct cpuidle_device *dev)
321 if (data->correction_factor[data->bucket] == 0) 321 if (data->correction_factor[data->bucket] == 0)
322 data->correction_factor[data->bucket] = RESOLUTION * DECAY; 322 data->correction_factor[data->bucket] = RESOLUTION * DECAY;
323 323
324 /* Make sure to round up for half microseconds */ 324 /*
325 data->predicted_us = div_round64(data->expected_us * data->correction_factor[data->bucket], 325 * Force the result of multiplication to be 64 bits even if both
326 * operands are 32 bits.
327 * Make sure to round up for half microseconds.
328 */
329 data->predicted_us = div_round64((uint64_t)data->expected_us *
330 data->correction_factor[data->bucket],
326 RESOLUTION * DECAY); 331 RESOLUTION * DECAY);
327 332
328 get_typical_interval(data); 333 get_typical_interval(data);
@@ -388,7 +393,7 @@ static void menu_update(struct cpuidle_driver *drv, struct cpuidle_device *dev)
388 unsigned int last_idle_us = cpuidle_get_last_residency(dev); 393 unsigned int last_idle_us = cpuidle_get_last_residency(dev);
389 struct cpuidle_state *target = &drv->states[last_idx]; 394 struct cpuidle_state *target = &drv->states[last_idx];
390 unsigned int measured_us; 395 unsigned int measured_us;
391 u64 new_factor; 396 unsigned int new_factor;
392 397
393 /* 398 /*
394 * Ugh, this idle state doesn't support residency measurements, so we 399 * Ugh, this idle state doesn't support residency measurements, so we
@@ -409,10 +414,9 @@ static void menu_update(struct cpuidle_driver *drv, struct cpuidle_device *dev)
409 measured_us -= data->exit_us; 414 measured_us -= data->exit_us;
410 415
411 416
412 /* update our correction ratio */ 417 /* Update our correction ratio */
413 418 new_factor = data->correction_factor[data->bucket];
414 new_factor = data->correction_factor[data->bucket] 419 new_factor -= new_factor / DECAY;
415 * (DECAY - 1) / DECAY;
416 420
417 if (data->expected_us > 0 && measured_us < MAX_INTERESTING) 421 if (data->expected_us > 0 && measured_us < MAX_INTERESTING)
418 new_factor += RESOLUTION * measured_us / data->expected_us; 422 new_factor += RESOLUTION * measured_us / data->expected_us;
@@ -425,9 +429,11 @@ static void menu_update(struct cpuidle_driver *drv, struct cpuidle_device *dev)
425 429
426 /* 430 /*
427 * We don't want 0 as factor; we always want at least 431 * We don't want 0 as factor; we always want at least
428 * a tiny bit of estimated time. 432 * a tiny bit of estimated time. Fortunately, due to rounding,
433 * new_factor will stay nonzero regardless of measured_us values
434 * and the compiler can eliminate this test as long as DECAY > 1.
429 */ 435 */
430 if (new_factor == 0) 436 if (DECAY == 1 && unlikely(new_factor == 0))
431 new_factor = 1; 437 new_factor = 1;
432 438
433 data->correction_factor[data->bucket] = new_factor; 439 data->correction_factor[data->bucket] = new_factor;