Re: [PATCH] correct inconsistent ntp interval/tick_length usage

john stultz
2008-01-30T02:14:36Z

On Tue, 2008-01-29 at 05:02 +0100, Roman Zippel wrote:
> Hi,
>
> On Mon, 28 Jan 2008, john stultz wrote:
>
> > Regardless, current_tick_length() really is the base interval we're
> > using in the error accumulation loop, so it seems the cleanest interface
> > to use (just to avoid redundancy at least) when establishing the
> > clocksource's interval length. Or do you not agree?
>
> I see, what you need to use in timex.h for !CONFIG_NO_HZ is:
>
> #define NTP_INTERVAL_LENGTH ((s64)LATCH * NSEC_PER_SEC) / (s64)CLOCK_TICK_RATE)
>
> this calculates the base length of a clock tick in nsec.
>
> current_tick_length() would only work during boot. If you switch clocks
> later, it would include random adjustments specific to the old clock.

Ah. Good point. How about the following, tested on x86_64 both with and
without CONFIG_NO_HZ?

Thanks for the review and feedback!
-john

Correct NTP drift caused by using inconsistent NTP_INTERVAL_LENGTHs in
clocksource initialization and error accumulation. This corrects a
280ppm drift seen on some systems using acpi_pm, and affects other
clocksources as well (likely to a lesser degree).

Signed-off-by: John Stultz <johnstul@us.ibm.com>

Index: linux/include/linux/timex.h
===================================================================
--- linux.orig/include/linux/timex.h
+++ linux/include/linux/timex.h
@@ -231,7 +231,13 @@ static inline int ntp_synced(void)
#else
#define NTP_INTERVAL_FREQ (HZ)
#endif
-#define NTP_INTERVAL_LENGTH (NSEC_PER_SEC/NTP_INTERVAL_FREQ)
+
+#define CLOCK_TICK_OVERFLOW (LATCH * HZ - CLOCK_TICK_RATE)
+#define CLOCK_TICK_ADJUST (((s64)CLOCK_TICK_OVERFLOW * NSEC_PER_SEC) / \
+ (s64)CLOCK_TICK_RATE)
+
+/* Because using NSEC_PER_SEC would be too easy */
+#define NTP_INTERVAL_LENGTH ((((s64)TICK_USEC*NSEC_PER_USEC*USER_HZ)+CLOCK_TICK_ADJUST)/NTP_INTERVAL_FREQ)

/* Returns how long ticks are at present, in ns / 2^(SHIFT_SCALE-10). */
extern u64 current_tick_length(void);
Index: linux/kernel/time/ntp.c
===================================================================
--- linux.orig/kernel/time/ntp.c
+++ linux/kernel/time/ntp.c
@@ -43,10 +43,6 @@ long time_freq; /* frequency offset (
static long time_reftime; /* time at last adjustment (s) */
long time_adjust;

-#define CLOCK_TICK_OVERFLOW (LATCH * HZ - CLOCK_TICK_RATE)
-#define CLOCK_TICK_ADJUST (((s64)CLOCK_TICK_OVERFLOW * NSEC_PER_SEC) / \
- (s64)CLOCK_TICK_RATE)
-
static void ntp_update_frequency(void)
{
u64 second_length = (u64)(tick_usec * NSEC_PER_USEC * USER_HZ)