Re: vdso: is the reduced precision of the CLOCK_AUX base intentional?

From: Thomas Weißschuh

Date: Mon Aug 31 2026 - 05:04:44 EST


Hi Zhan,

On Mon, Aug 31, 2026 at 03:20:26PM +0800, Zhan Xusheng wrote:
> vdso_time_update_aux() shifts the base down to nanoseconds and back up,
> while the other clocks keep it scaled:

(...)

> So the difference is floor(a+b) - floor(a) - floor(b), and the vdso reads
> 0 or 1 ns below the syscall for the same clock. With shift 24 and a
> 2.5 GHz counter I get the 1 ns case on 60% of the (xtime_nsec, delta)
> combinations I tried.

Good catch.

> The scaled form the other clocks use looks like it would work here too,
> and would restore the exact parity that tk_update_ktime_data() documents:
>
> nsec = tk->tkr_mono.xtime_nsec;
> nsec += (u64)tk->monotonic_to_aux.tv_nsec << tk->tkr_mono.shift;

If this sum is >= NSEC_PER_SEC then the userspace fast-path will need to loop
an additional time in __iter_div_u64_rem().
We can and should avoid this similar to the highres monotonic/boottime path,
and precompute as much as possible in the tick slow-path:

from update_vdso_time_data():

nsec = tk->tkr_mono.xtime_nsec;
nsec += ((u64)tk->wall_to_monotonic.tv_nsec << tk->tkr_mono.shift);
while (nsec >= (((u64)NSEC_PER_SEC) << tk->tkr_mono.shift)) {
nsec -= (((u64)NSEC_PER_SEC) << tk->tkr_mono.shift);
vdso_ts->sec++;
}

But instead of open-coding this logic (yet again), we should introduce
__iter_div64_u64_rem() in include/vdso/math64.h.
(And also use that in update_vdso_time_data()).

> update_vdso_time_data() already shifts wall_to_monotonic.tv_nsec that way,
> and monotonic_to_aux.tv_nsec has the same range, so the width is settled.

(...)

> Was the reduced precision deliberate, on the grounds that the sub-ns bits
> of the base carry no meaning for an auxiliary clock?

It was not intentional from my side.

(...)

> Unrelated, from the dispatch next to it: __cvdso_clock_gettime_common()
> does msk = 1U << clock after admitting everything up to CLOCK_AUX_LAST.
> That is 23 today, but raising MAX_AUX_CLOCKS past 16 would make the shift
> undefined with nothing to catch it. A BUILD_BUG_ON(CLOCK_AUX_LAST >= 32)
> would pin it down.

I would prefer this, assuming all supported compilers can properly track the
actual value range:

BUILD_BUG_ON(clock >= BITS_PER_TYPE(msk)).


Thomas