Skip site navigation (1)Skip section navigation (2)
Date:      Sun, 28 Jun 1998 20:14:48 +0200 (SAT)
From:      John Hay <jhay@mikom.csir.co.za>
To:        phk@critter.freebsd.dk (Poul-Henning Kamp)
Cc:        freebsd-smp@FreeBSD.ORG
Subject:   Re: time problem?
Message-ID:  <199806281814.UAA09849@zibbi.mikom.csir.co.za>
In-Reply-To: <2720.899034051@critter.freebsd.dk> from Poul-Henning Kamp at "Jun 28, 98 01:40:51 pm"

next in thread | previous in thread | raw e-mail | index | archive | help
> >I have found that my dual P5 100MHz machine will gain +- 0.85 seconds
> >every now and again. [...]
> >so it looks like it has something
> >to do with the SMP code. It also does not seem to have anything to do
> >with how busy the machine is, it has happened on a totally idle machine
> >and also during a make world.
> >
> >Anybody have any ideas how I can look for this? I don't understand all
> >the low level time stuff yet (especially the SMP side of it), but if
> >given a little direction I'm willing to try a few things.
> 
> It is really very simple, and there is nothing SMP specific about the
> code.
> 
> .85 seconds sounds suspiciosly like 2^20 cycles at 1193182 Hz.

Ok, it is possible that I just haven't waited long enough with the
UP kernel, but I can try again.

> 
> Unfortunately that doesn't really make any kind of sense to me...
> 
> How do you detect this jump ?  what is the exact sequnce of events ?

Well, it is actually the one that you gave me to test the new pps api
with, which I modified a little. I'll attach it at the end.

I have an 1 pps signal connected to DCD of my serial port. With sysctl
kern.timecounter.frequency I tune the frequency until it runs as
accurately as possible. Then I use "ntpdate -b <timeserver>" a few times
to get the offset small. Then I run my little program and wait until
it shows a jump. Then I use "ntpdate -d <timeserver>" to make sure that
it was really a jump.

Basically what the program does is to fetch the timestamp from the
kernel and if it is within bounds, printf("...\r") it. If it is out
of bounds, it add a printf("\n") before and after it. The values
that it print is the timestamp (sec.nanosec), the sequence number
and the time difference between this and the previous timestamp/.

Here is the output of a piece of it:

----------------
A: 899000790.981073054 #29011  D: 1.000004191
A: 899000792.826104370 #29012  D: 1.845031316
A: 899016109.813482765 #44329  D: 0.999940488
A: 899016111.668519664 #44330  D: 1.855036899
----------

So on sequence numbers 29012 and 44330, I have gained .85 seconds
in the space of a second. For the 15000 seconds between 29012 and
44329 there were no glitches or jumps.

> 
> The only possibly weak spot I know is this test in i386/isa/clock.c,
> you can try out this patch, but I doubt it will fix it.

Ok, I'll try it.

I do also get glitches where the time will jump forward or backward
by 1 tick (10ms), but it will correct itself on the next sample, so
it does not have a long term effect. I thought its source was also
this piece of code. I get about 30-50 of these per day, using my test
program.

Is this function, i8254_get_timecount(), used by something that can
have a permanent effect on time? I thought it was only used by
nanotime() and microtime() to get the offset from the previous tick,
but that it wasn't used to calculate the next tick?

> 
> Index: clock.c
> ===================================================================
> RCS file: /home/ncvs/src/sys/i386/isa/clock.c,v
> retrieving revision 1.124
> diff -u -r1.124 clock.c
> --- clock.c	1998/06/09 13:10:46	1.124
> +++ clock.c	1998/06/28 11:39:03
> @@ -1148,7 +1148,7 @@
>  	high = inb(TIMER_CNTR0);
>  
>  	count = hardclock_max_count - ((high << 8) | low);
> -	if (count < i8254_lastcount) {
> +	if (count <= i8254_lastcount) {
>  		i8254_ticked = 1;
>  		i8254_offset += hardclock_max_count;
>  	}

John
-- 
John Hay -- John.Hay@mikom.csir.co.za

----------------------------- ppstst2.c -----------------------------
#include <stdio.h>
#include <errno.h>
#include <fcntl.h>
#include <err.h>
#include <sys/types.h>
#include <time.h>
#include <timepps.h>

#if 1
#define DEVNAME "/dev/gps0"
#else
#define DEVNAME "/dev/lppps0"
#endif

int
main(int argc, char **argv)
{
	int fd;
	struct timespec dts;
	pps_info_t pi, opi;
	pps_params_t pp;
	pps_handle_t ph;
	int i, mode;
	float df;

	fd = open(DEVNAME, O_RDONLY);
	if (fd < 0) 
		err(1, DEVNAME);

	i = time_pps_create(fd, &ph);
	if (i < 0)
		err(1, "time_pps_create");

	i = time_pps_getcap(ph, &mode);
	if (i < 0)
		err(1, "time_pps_getcap");
	printf("getcap says %x\n", mode);

	pp.mode = PPS_CAPTUREASSERT;

	i = time_pps_setparams(ph, &pp);
	if (i < 0)
		err(1, "time_pps_setparams");

	i = time_pps_fetch(ph, &pi);
	if (i < 0)
		err(1, "time_pps_fetch");
	opi = pi;

	while (1) {
		i = time_pps_fetch(ph, &pi);
		if (i < 0)
			err(1, "time_pps_fetch");
		if (opi.assert_sequence != pi.assert_sequence) {
			dts.tv_sec = pi.assert_timestamp.tv_sec -
				     opi.assert_timestamp.tv_sec;
			dts.tv_nsec = pi.assert_timestamp.tv_nsec -
				      opi.assert_timestamp.tv_nsec;

			if (dts.tv_nsec < 0) {
				dts.tv_sec--;
				dts.tv_nsec += 1000000000;
			}

			df = (float)dts.tv_sec;
			df += (float)dts.tv_nsec / 1000000000.0;
			if (df > 1.001 || df < 0.999)
				printf("\n");
			printf("A: %d.%09d #%d  D: %d.%09d\r",
				pi.assert_timestamp.tv_sec,
				pi.assert_timestamp.tv_nsec,
				pi.assert_sequence,
				dts.tv_sec,
				dts.tv_nsec);
			if (df > 1.001 || df < 0.999)
				printf("\n");
			else
				fflush(NULL);
			opi = pi;
		}
#if 0
		printf("A: %d.%09d #%d  C: %d.%09d #%d\n",
			pi.assert_timestamp.tv_sec,
			pi.assert_timestamp.tv_nsec,
			pi.assert_sequence,
			pi.clear_timestamp.tv_sec,
			pi.clear_timestamp.tv_nsec,
			pi.clear_sequence);
#endif
		usleep(250000);
	}

	return(0);
}

To Unsubscribe: send mail to majordomo@FreeBSD.org
with "unsubscribe freebsd-smp" in the body of the message



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?199806281814.UAA09849>