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 <[email protected]>
---
 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 [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Reply via email to