aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/time/timekeeping.c
diff options
context:
space:
mode:
authorJohn Stultz <john.stultz@linaro.org>2015-03-12 00:16:32 -0400
committerIngo Molnar <mingo@kernel.org>2015-03-13 03:06:58 -0400
commit3c17ad19f0697ffe5ef7438cdafc2d2b7757d8a5 (patch)
tree9d47ff591a06ab8ed93df330b01964da3fbff8d7 /kernel/time/timekeeping.c
parentfb82fe2fe8588745edd73aa3a6229facac5c1e15 (diff)
timekeeping: Add debugging checks to warn if we see delays
Recently there's been requests for better sanity checking in the time code, so that it's more clear when something is going wrong, since timekeeping issues could manifest in a large number of strange ways in various subsystems. Thus, this patch adds some extra infrastructure to add a check to update_wall_time() to print two new warnings: 1) if we see the call delayed beyond the 'max_cycles' overflow point, 2) or if we see the call delayed beyond the clocksource's 'max_idle_ns' value, which is currently 50% of the overflow point. This extra infrastructure is conditional on a new CONFIG_DEBUG_TIMEKEEPING option, also added in this patch - default off. Tested this a bit by halting qemu for specified lengths of time to trigger the warnings. Signed-off-by: John Stultz <john.stultz@linaro.org> Cc: Dave Jones <davej@codemonkey.org.uk> Cc: Linus Torvalds <torvalds@linux-foundation.org> Cc: Peter Zijlstra <peterz@infradead.org> Cc: Prarit Bhargava <prarit@redhat.com> Cc: Richard Cochran <richardcochran@gmail.com> Cc: Stephen Boyd <sboyd@codeaurora.org> Cc: Thomas Gleixner <tglx@linutronix.de> Link: http://lkml.kernel.org/r/1426133800-29329-5-git-send-email-john.stultz@linaro.org [ Improved the changelog and the messages a bit. ] Signed-off-by: Ingo Molnar <mingo@kernel.org>
Diffstat (limited to 'kernel/time/timekeeping.c')
-rw-r--r--kernel/time/timekeeping.c28
1 files changed, 28 insertions, 0 deletions
diff --git a/kernel/time/timekeeping.c b/kernel/time/timekeeping.c
index 91db94136c10..acf049144cf6 100644
--- a/kernel/time/timekeeping.c
+++ b/kernel/time/timekeeping.c
@@ -118,6 +118,31 @@ static inline void tk_update_sleep_time(struct timekeeper *tk, ktime_t delta)
118 tk->offs_boot = ktime_add(tk->offs_boot, delta); 118 tk->offs_boot = ktime_add(tk->offs_boot, delta);
119} 119}
120 120
121#ifdef CONFIG_DEBUG_TIMEKEEPING
122static void timekeeping_check_update(struct timekeeper *tk, cycle_t offset)
123{
124
125 cycle_t max_cycles = tk->tkr.clock->max_cycles;
126 const char *name = tk->tkr.clock->name;
127
128 if (offset > max_cycles) {
129 printk_deferred("WARNING: timekeeping: Cycle offset (%lld) is larger than allowed by the '%s' clock's max_cycles value (%lld): time overflow\n",
130 offset, name, max_cycles);
131 printk_deferred(" timekeeping: Your kernel is sick, but tries to cope\n");
132 } else {
133 if (offset > (max_cycles >> 1)) {
134 printk_deferred("INFO: timekeeping: Cycle offset (%lld) is larger than the the '%s' clock's 50%% safety margin (%lld)\n",
135 offset, name, max_cycles >> 1);
136 printk_deferred(" timekeeping: Your kernel is still fine, but is feeling a bit nervous\n");
137 }
138 }
139}
140#else
141static inline void timekeeping_check_update(struct timekeeper *tk, cycle_t offset)
142{
143}
144#endif
145
121/** 146/**
122 * tk_setup_internals - Set up internals to use clocksource clock. 147 * tk_setup_internals - Set up internals to use clocksource clock.
123 * 148 *
@@ -1630,6 +1655,9 @@ void update_wall_time(void)
1630 if (offset < real_tk->cycle_interval) 1655 if (offset < real_tk->cycle_interval)
1631 goto out; 1656 goto out;
1632 1657
1658 /* Do some additional sanity checking */
1659 timekeeping_check_update(real_tk, offset);
1660
1633 /* 1661 /*
1634 * With NO_HZ we may have to accumulate many cycle_intervals 1662 * With NO_HZ we may have to accumulate many cycle_intervals
1635 * (think "ticks") worth of time at once. To do this efficiently, 1663 * (think "ticks") worth of time at once. To do this efficiently,