cvs commit: src/usr.bin/vmstat vmstat.c src/usr.bin/w w.c

Bruce Evans bde at zeta.org.au
Thu Oct 20 04:50:36 PDT 2005


On Thu, 20 Oct 2005, Poul-Henning Kamp wrote:

> In message <20051020131450.T99502 at delplex.bde.org>, Bruce Evans writes:
>> On Tue, 18 Oct 2005, Poul-Henning Kamp wrote:
>
>> Using CLOCK_MONOTONIC doesn't work because it it gives the system's idea
>> of the time and doesn't try hard to keep in sync with the real time.
>> In particular, it doesn't jump when the real time is stepped by
>> settimeofday(2) or clock_settime(2).
>
> Uhm, Bruce,
>
> That is the exact reason why we have CLOCK_MONOTONIC: it doesn't jump.

I know why we have it and what it does.

> With respect to leapseconds:  Whoever was responsible for POSIX's
> decision should be forced to work as quality assurance inspector
> in a factory which makes cuu-cuu clocks for the rest of their lives.

POSIX's specification of CLOCK_MONOTONIC seems to be missing leap seconds
problems.  It seems to be required to actually work; thus it should give
the difference in real time, in seconds with nanoseconds resolution,
relative to its starting point, so it must include leap seconds.

Of course it can't reasonably be expected to have nanoseconds accuracy.
Since it cannot jump, it also cannot reasonably be expected to have
even seconds accuracy all the time.  There will be times just after the
time is synced with an external accurate clock when the real time is
kown very accurately but the monotonic time is known (at the kernel level)
to be very innaccurate (since the monotonic time cannot jump to match
the real time, especially backwards).  However, it is reasonable to expect
that the monotonic time is slewed to correct this difference.  This is
not done in FreeBSD.

difftime() also seems to be required to actually work.  According to
draft C99 (n869.txt):

%        [#2] The difftime function computes the  difference  between
%        two calendar times: time1 - time0.

time_t's cannot be naively subtracted in general in C, so the difference
here must be formal.  The difference is required to contain leap seconds
by POLA.

According to draft POSIX.1-2001 (d7.txt):

% 8275 CX        The functionality described on this reference page is aligned with the ISO C standard. Any
% 8276           conflict between the requirements described here and the ISO C standard is unintentional. This
% 8277           volume of IEEE Std 1003.1-200x defers to the ISO C standard.
% 8278           The difftime( ) function shall compute the difference between two calendar times (as returned by
% 8279           time( )): time1- time0.

Here naive subtraction gives a result, but it cannot always give the correct
result since time_t's don't contain leap seconds in POSIX.  Since C99 has
precedence, difftime() cannot be implemented using naive subtraction; it must
somehow adjust for leap seconds being missing from the time_t's.

Back to the utilities: according to the standards, it seems to be equally
correct to implement "double uptime()" as:

 	/* Done in kernel; happens to give 0 in FreeBSD implementation: */
 	clock_gettime(CLOCK_MONOTONIC, &boottime);

 	clock_gettime(CLOCK_MONOTONIC, &now);

 	return (now.tv_sec - boottime.tv_sec +
 	    1e-9 * (now.tv_nsec - boottime.tv_nsec);

and as:

 	/* Done in kernel; nonzero except if you booted in 1970: */
 	clock_gettime(CLOCK_REALTIME, &boottime);

 	clock_gettime(CLOCK_REALTIME, &now);

 	/* Restore leap seconds if necessary; lose nanoseconds resolution: */
 	return difftime(now.tv_sec, boottime.tv_sec);

Different bugs prevent both of these working as well as they should.
For w, no one should even notice the inaccuracies of a few seconds caused
by the bugs.  For vmstat, the first method works better because the bugs
in the monotonic clock cause only small relative errors in the difference,
while for the second method only the bugs can be fixed -- large relative
errors in the difference caused by stepping the clock are unfixable.

Bruce


More information about the cvs-src mailing list