time: Rework debugging variables so they aren't global

Ingo suggested that the timekeeping debugging variables
recently added should not be global, and should be tied
to the timekeeper's read_base.

Thus this patch implements that suggestion.

This version is different from the earlier versions
as it keeps the variables in the timekeeper structure
rather then in the tkr.

Cc: Ingo Molnar <mingo@kernel.org>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Prarit Bhargava <prarit@redhat.com>
Cc: Richard Cochran <richardcochran@gmail.com>
Signed-off-by: John Stultz <john.stultz@linaro.org>
This commit is contained in:
John Stultz 2015-05-13 16:04:47 -07:00
parent 6374f9124e
commit 57d05a93ad
2 changed files with 26 additions and 22 deletions

View File

@ -61,6 +61,9 @@ struct tk_read_base {
* shifted nano seconds. * shifted nano seconds.
* @ntp_error_shift: Shift conversion between clock shifted nano seconds and * @ntp_error_shift: Shift conversion between clock shifted nano seconds and
* ntp shifted nano seconds. * ntp shifted nano seconds.
* @last_warning: Warning ratelimiter (DEBUG_TIMEKEEPING)
* @underflow_seen: Underflow warning flag (DEBUG_TIMEKEEPING)
* @overflow_seen: Overflow warning flag (DEBUG_TIMEKEEPING)
* *
* Note: For timespec(64) based interfaces wall_to_monotonic is what * Note: For timespec(64) based interfaces wall_to_monotonic is what
* we need to add to xtime (or xtime corrected for sub jiffie times) * we need to add to xtime (or xtime corrected for sub jiffie times)
@ -106,6 +109,18 @@ struct timekeeper {
s64 ntp_error; s64 ntp_error;
u32 ntp_error_shift; u32 ntp_error_shift;
u32 ntp_err_mult; u32 ntp_err_mult;
#ifdef CONFIG_DEBUG_TIMEKEEPING
long last_warning;
/*
* These simple flag variables are managed
* without locks, which is racy, but they are
* ok since we don't really care about being
* super precise about how many events were
* seen, just that a problem was observed.
*/
int underflow_seen;
int overflow_seen;
#endif
}; };
#ifdef CONFIG_GENERIC_TIME_VSYSCALL #ifdef CONFIG_GENERIC_TIME_VSYSCALL

View File

@ -118,18 +118,6 @@ static inline void tk_update_sleep_time(struct timekeeper *tk, ktime_t delta)
#ifdef CONFIG_DEBUG_TIMEKEEPING #ifdef CONFIG_DEBUG_TIMEKEEPING
#define WARNING_FREQ (HZ*300) /* 5 minute rate-limiting */ #define WARNING_FREQ (HZ*300) /* 5 minute rate-limiting */
/*
* These simple flag variables are managed
* without locks, which is racy, but ok since
* we don't really care about being super
* precise about how many events were seen,
* just that a problem was observed.
*/
static int timekeeping_underflow_seen;
static int timekeeping_overflow_seen;
/* last_warning is only modified under the timekeeping lock */
static long timekeeping_last_warning;
static void timekeeping_check_update(struct timekeeper *tk, cycle_t offset) static void timekeeping_check_update(struct timekeeper *tk, cycle_t offset)
{ {
@ -149,29 +137,30 @@ static void timekeeping_check_update(struct timekeeper *tk, cycle_t offset)
} }
} }
if (timekeeping_underflow_seen) { if (tk->underflow_seen) {
if (jiffies - timekeeping_last_warning > WARNING_FREQ) { if (jiffies - tk->last_warning > WARNING_FREQ) {
printk_deferred("WARNING: Underflow in clocksource '%s' observed, time update ignored.\n", name); printk_deferred("WARNING: Underflow in clocksource '%s' observed, time update ignored.\n", name);
printk_deferred(" Please report this, consider using a different clocksource, if possible.\n"); printk_deferred(" Please report this, consider using a different clocksource, if possible.\n");
printk_deferred(" Your kernel is probably still fine.\n"); printk_deferred(" Your kernel is probably still fine.\n");
timekeeping_last_warning = jiffies; tk->last_warning = jiffies;
} }
timekeeping_underflow_seen = 0; tk->underflow_seen = 0;
} }
if (timekeeping_overflow_seen) { if (tk->overflow_seen) {
if (jiffies - timekeeping_last_warning > WARNING_FREQ) { if (jiffies - tk->last_warning > WARNING_FREQ) {
printk_deferred("WARNING: Overflow in clocksource '%s' observed, time update capped.\n", name); printk_deferred("WARNING: Overflow in clocksource '%s' observed, time update capped.\n", name);
printk_deferred(" Please report this, consider using a different clocksource, if possible.\n"); printk_deferred(" Please report this, consider using a different clocksource, if possible.\n");
printk_deferred(" Your kernel is probably still fine.\n"); printk_deferred(" Your kernel is probably still fine.\n");
timekeeping_last_warning = jiffies; tk->last_warning = jiffies;
} }
timekeeping_overflow_seen = 0; tk->overflow_seen = 0;
} }
} }
static inline cycle_t timekeeping_get_delta(struct tk_read_base *tkr) static inline cycle_t timekeeping_get_delta(struct tk_read_base *tkr)
{ {
struct timekeeper *tk = &tk_core.timekeeper;
cycle_t now, last, mask, max, delta; cycle_t now, last, mask, max, delta;
unsigned int seq; unsigned int seq;
@ -197,13 +186,13 @@ static inline cycle_t timekeeping_get_delta(struct tk_read_base *tkr)
* mask-relative negative values. * mask-relative negative values.
*/ */
if (unlikely((~delta & mask) < (mask >> 3))) { if (unlikely((~delta & mask) < (mask >> 3))) {
timekeeping_underflow_seen = 1; tk->underflow_seen = 1;
delta = 0; delta = 0;
} }
/* Cap delta value to the max_cycles values to avoid mult overflows */ /* Cap delta value to the max_cycles values to avoid mult overflows */
if (unlikely(delta > max)) { if (unlikely(delta > max)) {
timekeeping_overflow_seen = 1; tk->overflow_seen = 1;
delta = tkr->clock->max_cycles; delta = tkr->clock->max_cycles;
} }