Re: time interpolation hooks

From: David Mosberger (davidm@napali.hpl.hp.com)
Date: Mon May 19 2003 - 18:03:44 EST


>>>>> On Mon, 19 May 2003 15:37:58 -0700 (PDT), "David S. Miller" <davem@redhat.com> said:

  DaveM> That's not the issue, if I have only ONE way to do this on my
  DaveM> platform, I can INLINE this thing and I DO NOT need function
  DaveM> pointers.

With the present code, an architecture does not have to use any
indirect function calls if there is only one known interpolator
(presumably based on a CPU cycle counter). The only extra overhead is
the (inlined) read of variable time_interpolator and a check against
NULL. Is this acceptable?

For convenience, I attached the current proposal. In the SPARC case,
you'd simply never call register_time_interpolator() and use
arch-specific code to calculate (and update) last_nsec_offset. The
time_interpolator_update() and time_interpolator_reset() code then
take care of the rest.

        --david

#ifdef CONFIG_TIME_INTERPOLATION

struct time_interpolator {
        /* cache-hot stuff first: */
        unsigned long (*get_offset) (void);
        void (*update) (long);
        void (*reset) (void);

        /* cache-cold stuff follows here: */
        struct time_interpolator *next;
        unsigned long frequency; /* frequency in counts/second */
        long drift; /* drift in parts-per-million (or -1) */
};

extern volatile unsigned long last_nsec_offset;
#ifndef __HAVE_ARCH_CMPXCHG
extern spin_lock_t last_nsec_offset_lock;
#endif
extern struct time_interpolator *time_interpolator;

extern void register_time_interpolator (struct time_interpolator *);
extern void unregister_time_interpolator (struct time_interpolator *);

/* Called with xtime read- OR write-lock acquired. */
static inline void
time_interpolator_update (long delta_nsec)
{
        struct time_interpolator *ti = time_interpolator;

        if (last_nsec_offset > 0) {
#ifdef __HAVE_ARCH_CMPXCHG
                unsigned long new, old;

                do {
                        old = last_nsec_offset;
                        if (old > delta_nsec)
                                new = old - delta_nsec;
                        else
                                new = 0;
                } while (cmpxchg(&last_nsec_offset, old, new) != old);
#else
                /*
                 * This really hurts, because it serializes gettimeofday(), but without an
                 * atomic single-word compare-and-exchange, there isn't all that much else
                 * we can do.
                 */
                spin_lock(&last_nsec_offset_lock);
                {
                        last_nsec_offset -= min(last_nsec_offset, delta_nsec);
                }
                spin_unlock(&last_nsec_offset_lock);
#endif
        }

        if (ti)
                (*ti->update)(delta_nsec);
}

/* Called with xtime read- or write-lock acquired. */
static inline void
time_interpolator_reset (void)
{
        struct time_interpolator *ti = time_interpolator;

        last_nsec_offset = 0;
        if (ti)
                (*ti->reset)();
}

static inline unsigned long
time_interpolator_get_offset (void)
{
        struct time_interpolator *ti = time_interpolator;
        if (ti)
                return (*ti->get_offset)();
        return last_nsec_offset;
}

#else /* !CONFIG_TIME_INTERPOLATION */

static inline void
time_interpolator_update (long delta_nsec)
{
}

static inline void
time_interpolator_reset (void)
{
}

static inline unsigned long
time_interpolator_get_offset (void)
{
        return 0;
}

#endif /* !CONFIG_TIME_INTERPOLATION */
-
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/



This archive was generated by hypermail 2b29 : Fri May 23 2003 - 22:00:37 EST