lkml.org 
[lkml]   [2006]   [Dec]   [12]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    Subject[RFC] HZ free ntp
    From
    Date
    On Wed, 2006-12-06 at 15:33 +0100, Roman Zippel wrote:
    > On Wed, 6 Dec 2006, Ingo Molnar wrote:
    > > i disagree with you and it's pretty low-impact anyway. There's still
    > > quite many HZ/tick assumptions all around the time code (NTP being one
    > > example), we'll deal with those via other patches.
    >
    > Why do you pick on the NTP code? That's actually one of the places where
    > assumptions about HZ are largely gone. NTP state is updated incrementally
    > and this won't change, but the update frequency can now be easily
    > disconnected from HZ.

    Hey Roman,
    Here's my rough first attempt at doing so. I'd not call it easy, but
    maybe you have some suggestions for a simpler way?

    Basically INTERVAL_LENGTH_NSEC defines the NTP interval length that the
    time code will use to accumulate with. In this patch I've pushed it out
    to a full second, but it could be set via config (NSEC_PER_SEC/HZ for
    regular systems, something larger for systems using dynticks).

    Thoughts?

    -john


    diff --git a/include/linux/timex.h b/include/linux/timex.h
    index db501dc..be13daf 100644
    --- a/include/linux/timex.h
    +++ b/include/linux/timex.h
    @@ -286,9 +286,10 @@ #endif /* !CONFIG_TIME_INTERPOLATION */

    #define TICK_LENGTH_SHIFT 32

    -/* Returns how long ticks are at present, in ns / 2^(SHIFT_SCALE-10). */
    -extern u64 current_tick_length(void);
    +#define INTERVAL_LENGTH_NSEC (NSEC_PER_SEC)

    +/* Returns how long NTP intervals are at present, in ns / 2^(SHIFT_SCALE-10).*/
    +extern u64 ntp_interval_length(void);
    extern void second_overflow(void);
    extern void update_ntp_one_tick(void);
    extern int do_adjtimex(struct timex *);
    diff --git a/kernel/hrtimer.c b/kernel/hrtimer.c
    index d0ba190..53979a9 100644
    --- a/kernel/hrtimer.c
    +++ b/kernel/hrtimer.c
    @@ -127,12 +127,14 @@ EXPORT_SYMBOL_GPL(ktime_get_ts);
    */
    static void hrtimer_get_softirq_time(struct hrtimer_base *base)
    {
    + struct timespec ts;
    ktime_t xtim, tomono;
    unsigned long seq;

    do {
    seq = read_seqbegin(&xtime_lock);
    - xtim = timespec_to_ktime(xtime);
    + getnstimeofday(&ts);
    + xtim = timespec_to_ktime(ts);
    tomono = timespec_to_ktime(wall_to_monotonic);

    } while (read_seqretry(&xtime_lock, seq));
    diff --git a/kernel/time/ntp.c b/kernel/time/ntp.c
    index 3afeaa3..812c56f 100644
    --- a/kernel/time/ntp.c
    +++ b/kernel/time/ntp.c
    @@ -20,11 +20,12 @@ #include <asm/timex.h>
    */
    unsigned long tick_usec = TICK_USEC; /* USER_HZ period (usec) */
    unsigned long tick_nsec; /* ACTHZ period (nsec) */
    -static u64 tick_length, tick_length_base;
    +static u64 interval_length, interval_length_base;

    #define MAX_TICKADJ 500 /* microsecs */
    -#define MAX_TICKADJ_SCALED (((u64)(MAX_TICKADJ * NSEC_PER_USEC) << \
    - TICK_LENGTH_SHIFT) / HZ)
    +#define MAX_TICKADJ_SCALED \
    + ((((u64)MAX_TICKADJ * NSEC_PER_USEC * INTERVAL_LENGTH_NSEC) \
    + / NSEC_PER_SEC)<< TICK_LENGTH_SHIFT)

    /*
    * phase-lock loop variables
    @@ -44,15 +45,45 @@ #define CLOCK_TICK_OVERFLOW (LATCH * HZ
    #define CLOCK_TICK_ADJUST (((s64)CLOCK_TICK_OVERFLOW * NSEC_PER_SEC) / \
    (s64)CLOCK_TICK_RATE)

    +/**
    + * ntp_update_frequency - Calculates base values used for NTP adjustments
    + *
    + */
    static void ntp_update_frequency(void)
    {
    - tick_length_base = (u64)(tick_usec * NSEC_PER_USEC * USER_HZ) << TICK_LENGTH_SHIFT;
    - tick_length_base += (s64)CLOCK_TICK_ADJUST << TICK_LENGTH_SHIFT;
    - tick_length_base += (s64)time_freq << (TICK_LENGTH_SHIFT - SHIFT_NSEC);
    -
    - do_div(tick_length_base, HZ);
    -
    - tick_nsec = tick_length_base >> TICK_LENGTH_SHIFT;
    + u64 second_length;
    + s64 adj_length;
    + u64 tick_length;
    + int neg = 0;
    + /* calculate the length of one NTP adjusted second */
    + second_length = (u64)(tick_usec * NSEC_PER_USEC * USER_HZ);
    + second_length += (s64)CLOCK_TICK_ADJUST;
    + adj_length = (s64)time_freq;
    +
    + /* calculate tick length @ HZ*/
    + tick_length = (second_length << TICK_LENGTH_SHIFT)
    + + (adj_length << (TICK_LENGTH_SHIFT - SHIFT_NSEC));
    + do_div(tick_length, HZ);
    + tick_nsec = tick_length >> TICK_LENGTH_SHIFT;
    +
    +
    + /* calculate interval_length_base */
    + /* XXX - this is broken up to avoid 64bit overlfows */
    + interval_length_base = second_length * INTERVAL_LENGTH_NSEC;
    + interval_length_base <<= 2;
    + do_div(interval_length_base, NSEC_PER_SEC);
    + interval_length_base <<= TICK_LENGTH_SHIFT-2;
    +
    + if (adj_length < 0) {
    + neg = 1;
    + adj_length = -adj_length;
    + }
    + adj_length *= INTERVAL_LENGTH_NSEC;
    + do_div(adj_length, NSEC_PER_SEC);
    + adj_length <<= (TICK_LENGTH_SHIFT - SHIFT_NSEC);
    + if(neg)
    + adj_length = -adj_length;
    + interval_length_base += adj_length;
    }

    /**
    @@ -69,7 +100,7 @@ void ntp_clear(void)

    ntp_update_frequency();

    - tick_length = tick_length_base;
    + interval_length = interval_length_base;
    time_offset = 0;
    }

    @@ -148,37 +179,39 @@ void second_overflow(void)
    * Compute the phase adjustment for the next second. The offset is
    * reduced by a fixed factor times the time constant.
    */
    - tick_length = tick_length_base;
    + interval_length = interval_length_base;
    time_adj = shift_right(time_offset, SHIFT_PLL + time_constant);
    time_offset -= time_adj;
    - tick_length += (s64)time_adj << (TICK_LENGTH_SHIFT - SHIFT_UPDATE);
    + interval_length += (s64)time_adj << (TICK_LENGTH_SHIFT - SHIFT_UPDATE);

    if (unlikely(time_adjust)) {
    if (time_adjust > MAX_TICKADJ) {
    time_adjust -= MAX_TICKADJ;
    - tick_length += MAX_TICKADJ_SCALED;
    + interval_length += MAX_TICKADJ_SCALED;
    } else if (time_adjust < -MAX_TICKADJ) {
    time_adjust += MAX_TICKADJ;
    - tick_length -= MAX_TICKADJ_SCALED;
    + interval_length -= MAX_TICKADJ_SCALED;
    } else {
    - tick_length += (s64)(time_adjust * NSEC_PER_USEC /
    - HZ) << TICK_LENGTH_SHIFT;
    + u64 adjlen = ((s64)time_adjust * NSEC_PER_USEC
    + * INTERVAL_LENGTH_NSEC) << TICK_LENGTH_SHIFT;
    + do_div(adjlen, NSEC_PER_SEC);
    + interval_length += adjlen;
    time_adjust = 0;
    }
    }
    }

    /*
    - * Return how long ticks are at the moment, that is, how much time
    - * update_wall_time_one_tick will add to xtime next time we call it
    + * Return how long NTP intervals are at the moment, that is, how
    + * much time update_wall_time will add to xtime next time we call it
    * (assuming no calls to do_adjtimex in the meantime).
    * The return value is in fixed-point nanoseconds shifted by the
    * specified number of bits to the right of the binary point.
    * This function has no side-effects.
    */
    -u64 current_tick_length(void)
    +u64 ntp_interval_length(void)
    {
    - return tick_length;
    + return interval_length;
    }


    diff --git a/kernel/timer.c b/kernel/timer.c
    index 0256ab4..3a9f2b4 100644
    --- a/kernel/timer.c
    +++ b/kernel/timer.c
    @@ -890,7 +890,7 @@ void __init timekeeping_init(void)
    ntp_clear();

    clock = clocksource_get_next();
    - clocksource_calculate_interval(clock, tick_nsec);
    + clocksource_calculate_interval(clock, INTERVAL_LENGTH_NSEC);
    clock->cycle_last = clocksource_read(clock);

    write_sequnlock_irqrestore(&xtime_lock, flags);
    @@ -980,7 +980,7 @@ static __always_inline int clocksource_b
    * Now calculate the error in (1 << look_ahead) ticks, but first
    * remove the single look ahead already included in the error.
    */
    - tick_error = current_tick_length() >>
    + tick_error = ntp_interval_length() >>
    (TICK_LENGTH_SHIFT - clock->shift + 1);
    tick_error -= clock->xtime_interval >> 1;
    error = ((error - tick_error) >> look_ahead) + tick_error;
    @@ -1077,7 +1077,7 @@ #endif
    >> clock->shift);

    /* accumulate error between NTP and clock interval */
    - clock->error += current_tick_length();
    + clock->error += ntp_interval_length();
    clock->error -= clock->xtime_interval << (TICK_LENGTH_SHIFT - clock->shift);
    }

    @@ -1092,7 +1092,7 @@ #endif
    if (change_clocksource()) {
    clock->error = 0;
    clock->xtime_nsec = 0;
    - clocksource_calculate_interval(clock, tick_nsec);
    + clocksource_calculate_interval(clock, INTERVAL_LENGTH_NSEC);
    }
    }



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

    \
     
     \ /
      Last update: 2006-12-12 21:49    [W:4.517 / U:0.084 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site