[PATCH] watchdog: optimizing the hrtimer interval for power saving

From: Chuansheng Liu
Date: Thu Nov 22 2012 - 14:11:41 EST



By default, the watchdog threshold is 10, it means every 4s
every CPU will receive one hrtimer interrupt, for low power
device, it will cause 4-5mV power impact when device is deep
sleep.

So here want to optimize it as below:
4s + 4s + 4s + 4s + 4s
== >
12s + 2s + 2s + 2s + 2s
3/5 1/10 1/10 1/10 1/10

In 5 chances, once one chance is hit, then we can start the
hrtimer with a longer period sample(12s). Until the current
chance is not hit, will start the hrtimer with a shorted
period sample(2s).

With this patch, in most case the hrtimer will be 12s instead
of 4s averagely. It can save the device power indeed.

Signed-off-by: liu chuansheng <chuansheng.liu@xxxxxxxxx>
---
kernel/watchdog.c | 30 ++++++++++++++++++++++++++++--
1 files changed, 28 insertions(+), 2 deletions(-)

diff --git a/kernel/watchdog.c b/kernel/watchdog.c
index dd4b80a..6457e62 100644
--- a/kernel/watchdog.c
+++ b/kernel/watchdog.c
@@ -125,7 +125,24 @@ static u64 get_sample_period(void)
* and hard thresholds) to increment before the
* hardlockup detector generates a warning
*/
- return get_softlockup_thresh() * ((u64)NSEC_PER_SEC / 5);
+ return get_softlockup_thresh() * ((u64)NSEC_PER_SEC / 10);
+}
+
+static u64 get_long_sample_period(void)
+{
+ /*
+ * convert watchdog_thresh from seconds to ns
+ * We want to give 5 chances to detect softlockup,
+ * for power saving, once one chance is succeeding,
+ * we can set long period to avoid power consumption.
+ * Currently, set the long sample period is:
+ * 20s * 3/5 = 12s, once this 12s chance is not hit,
+ * we will divide the left 8s into 4 pieces, give every
+ * chance every 2s, so it will be likely:
+ * 12s + 2s + 2s + 2s + 2s,
+ * Anyway, we just use 12s is enough in normal case.
+ */
+ return get_softlockup_thresh() * ((u64)NSEC_PER_SEC * 3 / 5);
}

/* Commands for resetting the watchdog */
@@ -267,6 +284,10 @@ static enum hrtimer_restart watchdog_timer_fn(struct hrtimer *hrtimer)
unsigned long touch_ts = __this_cpu_read(watchdog_touch_ts);
struct pt_regs *regs = get_irq_regs();
int duration;
+ bool is_touched;
+
+ is_touched = (__this_cpu_read(hrtimer_interrupts) ==
+ __this_cpu_read(soft_lockup_hrtimer_cnt));

/* kick the hardlockup detector */
watchdog_interrupt_count();
@@ -275,7 +296,12 @@ static enum hrtimer_restart watchdog_timer_fn(struct hrtimer *hrtimer)
wake_up_process(__this_cpu_read(softlockup_watchdog));

/* .. and repeat */
- hrtimer_forward_now(hrtimer, ns_to_ktime(get_sample_period()));
+ if (is_touched) {
+ hrtimer_forward_now(hrtimer,
+ ns_to_ktime(get_long_sample_period()));
+ } else {
+ hrtimer_forward_now(hrtimer, ns_to_ktime(get_sample_period()));
+ }

if (touch_ts == 0) {
if (unlikely(__this_cpu_read(softlockup_touch_sync))) {
--
1.7.0.4



--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/