Skip site navigation (1)Skip section navigation (2)
Date:      Sun, 17 Feb 2002 18:54:13 +1100 (EST)
From:      Bruce Evans <bde@zeta.org.au>
To:        Matthew Dillon <dillon@apollo.backplane.com>
Cc:        <freebsd-current@FreeBSD.ORG>
Subject:   Re: 'microuptime() went backwards ...' using ACPI timer.  Shouldn't that be impossible?
Message-ID:  <20020217184436.M934-100000@gamplex.bde.org>
In-Reply-To: <200202170028.g1H0SQZ41827@apollo.backplane.com>

next in thread | previous in thread | raw e-mail | index | archive | help
On Sat, 16 Feb 2002, Matthew Dillon wrote:

> Testing with a 'make -j 10 buildworld' on a -current box I am getting
> regular:
>
>     microuptime() went backwards (146.826785 -> 146.156715)
>     microuptime() went backwards (146.826782 -> 146.228636)
>     ...
>     microuptime() went backwards (8945.938288 -> 8945.251603)
>     microuptime() went backwards (8945.938306 -> 8945.347173)
>     microuptime() went backwards (9142.847550 -> 9142.847546)
>
> This occurs both with and without the gettimeofday Giant-removal patch, so
> I am fairly sure it has nothing to do with any of my current work.  This is
> running -current on a DELL2550 (2xCPUs), compiled with the SMP option.

The fact that the timecounter usually goes backwards by about 0.68 seconds
is probably significant, but I can't quite explain it.

>     Timecounter "i8254"  frequency 1193182 Hz
>     ...
>     Timecounter "ACPI"  frequency 3579545 Hz
>     acpi_timer0: <32-bit timer at 3.579545MHz> port 0x808-0x80b on acpi0
>     acpi_cpu0: <CPU> on acpi0
>     acpi_cpu1: <CPU> on acpi0
>     acpi_pcib0: <Host-PCI bridge> on acpi0
>     ...
>
> Question:  How can this be occuring at all?  Isn't the ACPI counter a
> 32 bit counter that does not have the rollover problems that the 8254 timer
> has?

Timecounters go backwards when the timecounter update or reference code is
called insufficiently often to prevent overflow.  The rollover problems of
the i8254 timecounter actually reduce this problem.  If an i8254 rollover
is missed, then it causes the the i8254 timecounter to go forward less
than it should.

I just wrote the following fix for some of the overflow problems.

%%%
Index: kern_tc.c
===================================================================
RCS file: /home/ncvs/src/sys/kern/kern_tc.c,v
retrieving revision 1.113
diff -c -2 -r1.113 kern_tc.c
*** kern_tc.c	7 Feb 2002 21:21:55 -0000	1.113
--- kern_tc.c	17 Feb 2002 06:25:14 -0000
***************
*** 108,114 ****
  	struct timecounter *tc;

! 	tc = timecounter;
! 	*bt = tc->tc_offset;
! 	bintime_addx(bt, tc->tc_scale * tco_delta(tc));
  }

--- 95,129 ----
  	struct timecounter *tc;

! 	/*
! 	 * The loop is to handle changes of timecounter underneath us.
! 	 * Such changes may even become normal for preemptive kernels.
! 	 * It is quite reasonable for idle priority processes to not
! 	 * run for many seconds, and if they are not running after
! 	 * being preempted here, the timecounter may cycle many times
! 	 * underneath them.  An NTIMECOUNTER of > 2 is neither necessary
! 	 * or sufficient for fixing this problem, unless NTIMECOUNTER is
! 	 * preposterously large.  NTIMECOUNTER == 2 suffices for most
! 	 * cases, and something more is required to fix the general case.
! 	 *
! 	 * I hope this also fixes problems with overflow of the
! 	 * multiplication.  We depend on tc not becoming stale by more
! 	 * than 1 second.  We will now normally see such staleness
! 	 * because it will cause the timecounter to change many times
! 	 * underneath us.  There will only be problems if hardclock()
! 	 * doesn't run for many seconds, but hardclock() is a very
! 	 * high priority interrupt, so such problems "can't happen".
! 	 *
! 	 * XXX should use a generation count.
! 	 *
! 	 * XXX problems with hardclock() can happen, e.g., at boot time
! 	 * if you have fixed hardclock() to not be a broken fast interrupt
! 	 * handler, or if you sit at the ddb prompt for several seconds.
! 	 * Should do something to make them harmless.
! 	 */
! 	do {
! 		tc = timecounter;
! 		*bt = tc->tc_offset;
! 		bintime_addx(bt, tc->tc_scale * tco_delta(tc));
! 	} while (tc != timecounter);
  }

%%%

Bruce


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




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