On Fri, Dec 09, 2016 at 06:11:17AM +0100, Peter Zijlstra wrote:
> On Thu, Dec 08, 2016 at 08:49:39PM -0000, Thomas Gleixner wrote:
> 
> > +/*
> > + * Enabled when timekeeping is supposed to deal with virtualization keeping
> > + * VMs long enough scheduled out that the 64 * 32 bit multiplication in
> > + * timekeeping_delta_to_ns() overflows 64bit.
> > + */
> > +#ifdef CONFIG_TIMEKEEPING_USE_128BIT_MATH
> > +
> > +#if defined(CONFIG_ARCH_SUPPORTS_INT128) && defined(__SIZEOF_INT128__)
> > +static inline u64 timekeeping_delta_to_ns(struct tk_read_base *tkr, u64 
> > delta)
> > +{
> > +   unsigned __int128 nsec;
> > +
> > +   nsec = ((unsigned __int128)delta * tkr->mult) + tkr->xtime_nsec;
> > +   return (u64) (nsec >> tkr->shift);
> > +}
> > +#else
> > +static inline u64 timekeeping_delta_to_ns(struct tk_read_base *tkr, u64 
> > delta)
> > +{
> > +   u32 dh, dl;
> > +   u64 nsec;
> > +
> > +   dl = delta;
> > +   dh = delta >> 32;
> > +
> > +   nsec = ((u64)dl * tkr->mult) + tkr->xtime_nsec;
> > +   nsec >>= tkr->shift;
> > +   if (unlikely(dh))
> > +           nsec += ((u64)dh * tkr->mult) << (32 - tkr->shift);
> > +   return nsec;
> > +}
> > +#endif
> > +
> > +#else /* CONFIG_TIMEKEEPING_USE_128BIT_MATH */
> 
> xtime_nsec confuses me, contrary to its name, its not actually in nsec,
> its in shifted nsec units for some reason (and that might well be a good
> reason, but I don't know).
> 
> In any case, it needing to be inside the shift is somewhat unfortunate
> in that it doesn't allow you to use the existing mul_u64_u32_shr()

Wouldn't something like:

        nsec = mul_u64_u32_shr(delta, tkr->mult, tkr->shift);
        nsec += tkr->xtime_nsec >> tkr->shift;

Be good enough? Sure you have a slight rounding error, which results in
a few jaggies in the actual timeline, but it would still be monotonic.

That is, we'll observe the ns rollover 'late', but given its ns, does
anybody really care?

Reply via email to