xref: /freebsd/sys/kern/kern_clock.c (revision b05dcf3c2f7fe226e18edc4c6a820c50b562d762)
1b05dcf3cSPoul-Henning Kamp static volatile int print_tci = 1;
2b05dcf3cSPoul-Henning Kamp 
3df8bae1dSRodney W. Grimes /*-
47ec73f64SPoul-Henning Kamp  * Copyright (c) 1997, 1998 Poul-Henning Kamp <phk@FreeBSD.org>
5df8bae1dSRodney W. Grimes  * Copyright (c) 1982, 1986, 1991, 1993
6df8bae1dSRodney W. Grimes  *	The Regents of the University of California.  All rights reserved.
7df8bae1dSRodney W. Grimes  * (c) UNIX System Laboratories, Inc.
8df8bae1dSRodney W. Grimes  * All or some portions of this file are derived from material licensed
9df8bae1dSRodney W. Grimes  * to the University of California by American Telephone and Telegraph
10df8bae1dSRodney W. Grimes  * Co. or Unix System Laboratories, Inc. and are reproduced herein with
11df8bae1dSRodney W. Grimes  * the permission of UNIX System Laboratories, Inc.
12df8bae1dSRodney W. Grimes  *
13df8bae1dSRodney W. Grimes  * Redistribution and use in source and binary forms, with or without
14df8bae1dSRodney W. Grimes  * modification, are permitted provided that the following conditions
15df8bae1dSRodney W. Grimes  * are met:
16df8bae1dSRodney W. Grimes  * 1. Redistributions of source code must retain the above copyright
17df8bae1dSRodney W. Grimes  *    notice, this list of conditions and the following disclaimer.
18df8bae1dSRodney W. Grimes  * 2. Redistributions in binary form must reproduce the above copyright
19df8bae1dSRodney W. Grimes  *    notice, this list of conditions and the following disclaimer in the
20df8bae1dSRodney W. Grimes  *    documentation and/or other materials provided with the distribution.
21df8bae1dSRodney W. Grimes  * 3. All advertising materials mentioning features or use of this software
22df8bae1dSRodney W. Grimes  *    must display the following acknowledgement:
23df8bae1dSRodney W. Grimes  *	This product includes software developed by the University of
24df8bae1dSRodney W. Grimes  *	California, Berkeley and its contributors.
25df8bae1dSRodney W. Grimes  * 4. Neither the name of the University nor the names of its contributors
26df8bae1dSRodney W. Grimes  *    may be used to endorse or promote products derived from this software
27df8bae1dSRodney W. Grimes  *    without specific prior written permission.
28df8bae1dSRodney W. Grimes  *
29df8bae1dSRodney W. Grimes  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
30df8bae1dSRodney W. Grimes  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
31df8bae1dSRodney W. Grimes  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
32df8bae1dSRodney W. Grimes  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
33df8bae1dSRodney W. Grimes  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
34df8bae1dSRodney W. Grimes  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
35df8bae1dSRodney W. Grimes  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
36df8bae1dSRodney W. Grimes  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
37df8bae1dSRodney W. Grimes  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
38df8bae1dSRodney W. Grimes  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
39df8bae1dSRodney W. Grimes  * SUCH DAMAGE.
40df8bae1dSRodney W. Grimes  *
41df8bae1dSRodney W. Grimes  *	@(#)kern_clock.c	8.5 (Berkeley) 1/21/94
42b05dcf3cSPoul-Henning Kamp  * $Id: kern_clock.c,v 1.57 1998/02/20 16:35:49 phk Exp $
43df8bae1dSRodney W. Grimes  */
44df8bae1dSRodney W. Grimes 
45df8bae1dSRodney W. Grimes #include <sys/param.h>
46df8bae1dSRodney W. Grimes #include <sys/systm.h>
47df8bae1dSRodney W. Grimes #include <sys/dkstat.h>
48df8bae1dSRodney W. Grimes #include <sys/callout.h>
49df8bae1dSRodney W. Grimes #include <sys/kernel.h>
50df8bae1dSRodney W. Grimes #include <sys/proc.h>
51df8bae1dSRodney W. Grimes #include <sys/resourcevar.h>
52797f2d22SPoul-Henning Kamp #include <sys/signalvar.h>
533f31c649SGarrett Wollman #include <sys/timex.h>
548a129caeSDavid Greenman #include <vm/vm.h>
55996c772fSJohn Dyson #include <sys/lock.h>
56efeaf95aSDavid Greenman #include <vm/pmap.h>
57efeaf95aSDavid Greenman #include <vm/vm_map.h>
58797f2d22SPoul-Henning Kamp #include <sys/sysctl.h>
59df8bae1dSRodney W. Grimes 
60df8bae1dSRodney W. Grimes #include <machine/cpu.h>
61b1037dcdSBruce Evans #include <machine/limits.h>
62df8bae1dSRodney W. Grimes 
63df8bae1dSRodney W. Grimes #ifdef GPROF
64df8bae1dSRodney W. Grimes #include <sys/gmon.h>
65df8bae1dSRodney W. Grimes #endif
66df8bae1dSRodney W. Grimes 
67eae8fc2cSSteve Passe #if defined(SMP) && defined(BETTER_CLOCK)
68eae8fc2cSSteve Passe #include <machine/smp.h>
69eae8fc2cSSteve Passe #endif
70eae8fc2cSSteve Passe 
71d841aaa7SBruce Evans static void initclocks __P((void *dummy));
722b14f991SJulian Elischer SYSINIT(clocks, SI_SUB_CLOCKS, SI_ORDER_FIRST, initclocks, NULL)
732b14f991SJulian Elischer 
747ec73f64SPoul-Henning Kamp static void tco_forward __P((void));
757ec73f64SPoul-Henning Kamp static void tco_setscales __P((struct timecounter *tc));
767ec73f64SPoul-Henning Kamp 
77f23b4c91SGarrett Wollman /* Some of these don't belong here, but it's easiest to concentrate them. */
78eae8fc2cSSteve Passe #if defined(SMP) && defined(BETTER_CLOCK)
79eae8fc2cSSteve Passe long cp_time[CPUSTATES];
80eae8fc2cSSteve Passe #else
8127a0b398SPoul-Henning Kamp static long cp_time[CPUSTATES];
82eae8fc2cSSteve Passe #endif
83f23b4c91SGarrett Wollman long dk_seek[DK_NDRIVE];
84bea0f0beSBruce Evans static long dk_time[DK_NDRIVE];	/* time busy (in statclock ticks) */
85f23b4c91SGarrett Wollman long dk_wds[DK_NDRIVE];
86f23b4c91SGarrett Wollman long dk_wpms[DK_NDRIVE];
87f23b4c91SGarrett Wollman long dk_xfer[DK_NDRIVE];
88f23b4c91SGarrett Wollman 
89f23b4c91SGarrett Wollman int dk_busy;
908478cabaSGarrett Wollman int dk_ndrive = 0;
918478cabaSGarrett Wollman char dk_names[DK_NDRIVE][DK_NAMELEN];
92f23b4c91SGarrett Wollman 
93f23b4c91SGarrett Wollman long tk_cancc;
94f23b4c91SGarrett Wollman long tk_nin;
95f23b4c91SGarrett Wollman long tk_nout;
96f23b4c91SGarrett Wollman long tk_rawcc;
97f23b4c91SGarrett Wollman 
987ec73f64SPoul-Henning Kamp struct timecounter *timecounter;
997ec73f64SPoul-Henning Kamp 
100df8bae1dSRodney W. Grimes /*
101df8bae1dSRodney W. Grimes  * Clock handling routines.
102df8bae1dSRodney W. Grimes  *
103b05dcf3cSPoul-Henning Kamp  * This code is written to operate with two timers that run independently of
104b05dcf3cSPoul-Henning Kamp  * each other.
1057ec73f64SPoul-Henning Kamp  *
106b05dcf3cSPoul-Henning Kamp  * The main timer, running hz times per second, is used to trigger interval
107b05dcf3cSPoul-Henning Kamp  * timers, timeouts and rescheduling as needed.
1087ec73f64SPoul-Henning Kamp  *
109b05dcf3cSPoul-Henning Kamp  * The second timer handles kernel and user profiling,
110b05dcf3cSPoul-Henning Kamp  * and does resource use estimation.  If the second timer is programmable,
111b05dcf3cSPoul-Henning Kamp  * it is randomized to avoid aliasing between the two clocks.  For example,
112b05dcf3cSPoul-Henning Kamp  * the randomization prevents an adversary from always giving up the cpu
113df8bae1dSRodney W. Grimes  * just before its quantum expires.  Otherwise, it would never accumulate
114df8bae1dSRodney W. Grimes  * cpu ticks.  The mean frequency of the second timer is stathz.
115b05dcf3cSPoul-Henning Kamp  *
116b05dcf3cSPoul-Henning Kamp  * If no second timer exists, stathz will be zero; in this case we drive
117b05dcf3cSPoul-Henning Kamp  * profiling and statistics off the main clock.  This WILL NOT be accurate;
118b05dcf3cSPoul-Henning Kamp  * do not do it unless absolutely necessary.
119b05dcf3cSPoul-Henning Kamp  *
120df8bae1dSRodney W. Grimes  * The statistics clock may (or may not) be run at a higher rate while
121b05dcf3cSPoul-Henning Kamp  * profiling.  This profile clock runs at profhz.  We require that profhz
122b05dcf3cSPoul-Henning Kamp  * be an integral multiple of stathz.
123b05dcf3cSPoul-Henning Kamp  *
124b05dcf3cSPoul-Henning Kamp  * If the statistics clock is running fast, it must be divided by the ratio
125b05dcf3cSPoul-Henning Kamp  * profhz/stathz for statistics.  (For profiling, every tick counts.)
126df8bae1dSRodney W. Grimes  *
1277ec73f64SPoul-Henning Kamp  * Time-of-day is maintained using a "timecounter", which may or may
1287ec73f64SPoul-Henning Kamp  * not be related to the hardware generating the above mentioned
1297ec73f64SPoul-Henning Kamp  * interrupts.
130df8bae1dSRodney W. Grimes  */
131df8bae1dSRodney W. Grimes 
132df8bae1dSRodney W. Grimes int	stathz;
133df8bae1dSRodney W. Grimes int	profhz;
134cc3d5226SBruce Evans static int profprocs;
135df8bae1dSRodney W. Grimes int	ticks;
136df8bae1dSRodney W. Grimes static int psdiv, pscnt;		/* prof => stat divider */
137cc3d5226SBruce Evans int	psratio;			/* ratio: prof / stat */
138df8bae1dSRodney W. Grimes 
139b05dcf3cSPoul-Henning Kamp struct	timeval time;
140df8bae1dSRodney W. Grimes volatile struct	timeval mono_time;
141df8bae1dSRodney W. Grimes 
142df8bae1dSRodney W. Grimes /*
143df8bae1dSRodney W. Grimes  * Initialize clock frequencies and start both clocks running.
144df8bae1dSRodney W. Grimes  */
1452b14f991SJulian Elischer /* ARGSUSED*/
1462b14f991SJulian Elischer static void
147d841aaa7SBruce Evans initclocks(dummy)
148d841aaa7SBruce Evans 	void *dummy;
149df8bae1dSRodney W. Grimes {
150df8bae1dSRodney W. Grimes 	register int i;
151df8bae1dSRodney W. Grimes 
152df8bae1dSRodney W. Grimes 	/*
153df8bae1dSRodney W. Grimes 	 * Set divisors to 1 (normal case) and let the machine-specific
154df8bae1dSRodney W. Grimes 	 * code do its bit.
155df8bae1dSRodney W. Grimes 	 */
156df8bae1dSRodney W. Grimes 	psdiv = pscnt = 1;
157df8bae1dSRodney W. Grimes 	cpu_initclocks();
158df8bae1dSRodney W. Grimes 
159df8bae1dSRodney W. Grimes 	/*
160df8bae1dSRodney W. Grimes 	 * Compute profhz/stathz, and fix profhz if needed.
161df8bae1dSRodney W. Grimes 	 */
162df8bae1dSRodney W. Grimes 	i = stathz ? stathz : hz;
163df8bae1dSRodney W. Grimes 	if (profhz == 0)
164df8bae1dSRodney W. Grimes 		profhz = i;
165df8bae1dSRodney W. Grimes 	psratio = profhz / i;
166df8bae1dSRodney W. Grimes }
167df8bae1dSRodney W. Grimes 
168df8bae1dSRodney W. Grimes /*
169df8bae1dSRodney W. Grimes  * The real-time timer, interrupting hz times per second.
170df8bae1dSRodney W. Grimes  */
171df8bae1dSRodney W. Grimes void
172df8bae1dSRodney W. Grimes hardclock(frame)
173df8bae1dSRodney W. Grimes 	register struct clockframe *frame;
174df8bae1dSRodney W. Grimes {
175df8bae1dSRodney W. Grimes 	register struct proc *p;
176df8bae1dSRodney W. Grimes 
177df8bae1dSRodney W. Grimes 	p = curproc;
178df8bae1dSRodney W. Grimes 	if (p) {
179df8bae1dSRodney W. Grimes 		register struct pstats *pstats;
180df8bae1dSRodney W. Grimes 
181df8bae1dSRodney W. Grimes 		/*
182df8bae1dSRodney W. Grimes 		 * Run current process's virtual and profile time, as needed.
183df8bae1dSRodney W. Grimes 		 */
184df8bae1dSRodney W. Grimes 		pstats = p->p_stats;
185df8bae1dSRodney W. Grimes 		if (CLKF_USERMODE(frame) &&
186df8bae1dSRodney W. Grimes 		    timerisset(&pstats->p_timer[ITIMER_VIRTUAL].it_value) &&
187df8bae1dSRodney W. Grimes 		    itimerdecr(&pstats->p_timer[ITIMER_VIRTUAL], tick) == 0)
188df8bae1dSRodney W. Grimes 			psignal(p, SIGVTALRM);
189df8bae1dSRodney W. Grimes 		if (timerisset(&pstats->p_timer[ITIMER_PROF].it_value) &&
190df8bae1dSRodney W. Grimes 		    itimerdecr(&pstats->p_timer[ITIMER_PROF], tick) == 0)
191df8bae1dSRodney W. Grimes 			psignal(p, SIGPROF);
192df8bae1dSRodney W. Grimes 	}
193df8bae1dSRodney W. Grimes 
194eae8fc2cSSteve Passe #if defined(SMP) && defined(BETTER_CLOCK)
195eae8fc2cSSteve Passe 	forward_hardclock(pscnt);
196eae8fc2cSSteve Passe #endif
197b05dcf3cSPoul-Henning Kamp 
198df8bae1dSRodney W. Grimes 	/*
199df8bae1dSRodney W. Grimes 	 * If no separate statistics clock is available, run it from here.
200df8bae1dSRodney W. Grimes 	 */
201df8bae1dSRodney W. Grimes 	if (stathz == 0)
202df8bae1dSRodney W. Grimes 		statclock(frame);
203df8bae1dSRodney W. Grimes 
2047ec73f64SPoul-Henning Kamp 	tco_forward();
205df8bae1dSRodney W. Grimes 	ticks++;
2063f31c649SGarrett Wollman 
207b05dcf3cSPoul-Henning Kamp 	/*
208b05dcf3cSPoul-Henning Kamp 	 * Process callouts at a very low cpu priority, so we don't keep the
209b05dcf3cSPoul-Henning Kamp 	 * relatively high clock interrupt priority any longer than necessary.
210b05dcf3cSPoul-Henning Kamp 	 */
211b05dcf3cSPoul-Henning Kamp 	if (TAILQ_FIRST(&callwheel[ticks & callwheelmask]) != NULL) {
212b05dcf3cSPoul-Henning Kamp 		if (CLKF_BASEPRI(frame)) {
213b05dcf3cSPoul-Henning Kamp 			/*
214b05dcf3cSPoul-Henning Kamp 			 * Save the overhead of a software interrupt;
215b05dcf3cSPoul-Henning Kamp 			 * it will happen as soon as we return, so do it now.
216b05dcf3cSPoul-Henning Kamp 			 */
217b05dcf3cSPoul-Henning Kamp 			(void)splsoftclock();
218b05dcf3cSPoul-Henning Kamp 			softclock();
219b05dcf3cSPoul-Henning Kamp 		} else
220eeb355f7SPoul-Henning Kamp 			setsoftclock();
221b05dcf3cSPoul-Henning Kamp 	} else if (softticks + 1 == ticks)
222b05dcf3cSPoul-Henning Kamp 		++softticks;
223ab36c067SJustin T. Gibbs }
224ab36c067SJustin T. Gibbs 
225ab36c067SJustin T. Gibbs void
2263c816944SBruce Evans gettime(struct timeval *tvp)
2273c816944SBruce Evans {
2283c816944SBruce Evans 	int s;
2293c816944SBruce Evans 
2303c816944SBruce Evans 	s = splclock();
2319a8f4a4cSMike Pritchard 	/* XXX should use microtime() iff tv_usec is used. */
2323c816944SBruce Evans 	*tvp = time;
2333c816944SBruce Evans 	splx(s);
2343c816944SBruce Evans }
2353c816944SBruce Evans 
236df8bae1dSRodney W. Grimes /*
237df8bae1dSRodney W. Grimes  * Compute number of hz until specified time.  Used to
238df8bae1dSRodney W. Grimes  * compute third argument to timeout() from an absolute time.
239b05dcf3cSPoul-Henning Kamp  * XXX this interface is often inconvenient.  We often just need the
240b05dcf3cSPoul-Henning Kamp  * number of ticks in a timeval, but to use hzto() for that we have
241b05dcf3cSPoul-Henning Kamp  * to add `time' to the timeval and do everything at splclock().
242df8bae1dSRodney W. Grimes  */
243df8bae1dSRodney W. Grimes int
244df8bae1dSRodney W. Grimes hzto(tv)
245df8bae1dSRodney W. Grimes 	struct timeval *tv;
246df8bae1dSRodney W. Grimes {
2476976af69SBruce Evans 	register unsigned long ticks;
2486976af69SBruce Evans 	register long sec, usec;
249df8bae1dSRodney W. Grimes 	int s;
250df8bae1dSRodney W. Grimes 
251df8bae1dSRodney W. Grimes 	/*
2526976af69SBruce Evans 	 * If the number of usecs in the whole seconds part of the time
2536976af69SBruce Evans 	 * difference fits in a long, then the total number of usecs will
2546976af69SBruce Evans 	 * fit in an unsigned long.  Compute the total and convert it to
2556976af69SBruce Evans 	 * ticks, rounding up and adding 1 to allow for the current tick
2566976af69SBruce Evans 	 * to expire.  Rounding also depends on unsigned long arithmetic
2576976af69SBruce Evans 	 * to avoid overflow.
258df8bae1dSRodney W. Grimes 	 *
2596976af69SBruce Evans 	 * Otherwise, if the number of ticks in the whole seconds part of
2606976af69SBruce Evans 	 * the time difference fits in a long, then convert the parts to
2616976af69SBruce Evans 	 * ticks separately and add, using similar rounding methods and
2626976af69SBruce Evans 	 * overflow avoidance.  This method would work in the previous
2636976af69SBruce Evans 	 * case but it is slightly slower and assumes that hz is integral.
2646976af69SBruce Evans 	 *
2656976af69SBruce Evans 	 * Otherwise, round the time difference down to the maximum
2666976af69SBruce Evans 	 * representable value.
2676976af69SBruce Evans 	 *
2686976af69SBruce Evans 	 * If ints have 32 bits, then the maximum value for any timeout in
2696976af69SBruce Evans 	 * 10ms ticks is 248 days.
270df8bae1dSRodney W. Grimes 	 */
2716976af69SBruce Evans 	s = splclock();
272df8bae1dSRodney W. Grimes 	sec = tv->tv_sec - time.tv_sec;
2736976af69SBruce Evans 	usec = tv->tv_usec - time.tv_usec;
274df8bae1dSRodney W. Grimes 	splx(s);
2756976af69SBruce Evans 	if (usec < 0) {
2766976af69SBruce Evans 		sec--;
2776976af69SBruce Evans 		usec += 1000000;
2786976af69SBruce Evans 	}
2796976af69SBruce Evans 	if (sec < 0) {
2806976af69SBruce Evans #ifdef DIAGNOSTIC
281b05dcf3cSPoul-Henning Kamp 		if (usec > 0) {
2827ec73f64SPoul-Henning Kamp 			sec++;
2837ec73f64SPoul-Henning Kamp 			usec -= 1000000;
2847ec73f64SPoul-Henning Kamp 		}
2856976af69SBruce Evans 		printf("hzto: negative time difference %ld sec %ld usec\n",
2866976af69SBruce Evans 		       sec, usec);
2876976af69SBruce Evans #endif
2886976af69SBruce Evans 		ticks = 1;
2896976af69SBruce Evans 	} else if (sec <= LONG_MAX / 1000000)
2906976af69SBruce Evans 		ticks = (sec * 1000000 + (unsigned long)usec + (tick - 1))
2916976af69SBruce Evans 			/ tick + 1;
2926976af69SBruce Evans 	else if (sec <= LONG_MAX / hz)
2936976af69SBruce Evans 		ticks = sec * hz
2946976af69SBruce Evans 			+ ((unsigned long)usec + (tick - 1)) / tick + 1;
2956976af69SBruce Evans 	else
2966976af69SBruce Evans 		ticks = LONG_MAX;
2976976af69SBruce Evans 	if (ticks > INT_MAX)
2986976af69SBruce Evans 		ticks = INT_MAX;
299df8bae1dSRodney W. Grimes 	return (ticks);
300df8bae1dSRodney W. Grimes }
301df8bae1dSRodney W. Grimes 
302df8bae1dSRodney W. Grimes /*
303df8bae1dSRodney W. Grimes  * Start profiling on a process.
304df8bae1dSRodney W. Grimes  *
305df8bae1dSRodney W. Grimes  * Kernel profiling passes proc0 which never exits and hence
306df8bae1dSRodney W. Grimes  * keeps the profile clock running constantly.
307df8bae1dSRodney W. Grimes  */
308df8bae1dSRodney W. Grimes void
309df8bae1dSRodney W. Grimes startprofclock(p)
310df8bae1dSRodney W. Grimes 	register struct proc *p;
311df8bae1dSRodney W. Grimes {
312df8bae1dSRodney W. Grimes 	int s;
313df8bae1dSRodney W. Grimes 
314df8bae1dSRodney W. Grimes 	if ((p->p_flag & P_PROFIL) == 0) {
315df8bae1dSRodney W. Grimes 		p->p_flag |= P_PROFIL;
316df8bae1dSRodney W. Grimes 		if (++profprocs == 1 && stathz != 0) {
317df8bae1dSRodney W. Grimes 			s = splstatclock();
318df8bae1dSRodney W. Grimes 			psdiv = pscnt = psratio;
319df8bae1dSRodney W. Grimes 			setstatclockrate(profhz);
320df8bae1dSRodney W. Grimes 			splx(s);
321df8bae1dSRodney W. Grimes 		}
322df8bae1dSRodney W. Grimes 	}
323df8bae1dSRodney W. Grimes }
324df8bae1dSRodney W. Grimes 
325df8bae1dSRodney W. Grimes /*
326df8bae1dSRodney W. Grimes  * Stop profiling on a process.
327df8bae1dSRodney W. Grimes  */
328df8bae1dSRodney W. Grimes void
329df8bae1dSRodney W. Grimes stopprofclock(p)
330df8bae1dSRodney W. Grimes 	register struct proc *p;
331df8bae1dSRodney W. Grimes {
332df8bae1dSRodney W. Grimes 	int s;
333df8bae1dSRodney W. Grimes 
334df8bae1dSRodney W. Grimes 	if (p->p_flag & P_PROFIL) {
335df8bae1dSRodney W. Grimes 		p->p_flag &= ~P_PROFIL;
336df8bae1dSRodney W. Grimes 		if (--profprocs == 0 && stathz != 0) {
337df8bae1dSRodney W. Grimes 			s = splstatclock();
338df8bae1dSRodney W. Grimes 			psdiv = pscnt = 1;
339df8bae1dSRodney W. Grimes 			setstatclockrate(stathz);
340df8bae1dSRodney W. Grimes 			splx(s);
341df8bae1dSRodney W. Grimes 		}
342df8bae1dSRodney W. Grimes 	}
343df8bae1dSRodney W. Grimes }
344df8bae1dSRodney W. Grimes 
345df8bae1dSRodney W. Grimes /*
346df8bae1dSRodney W. Grimes  * Statistics clock.  Grab profile sample, and if divider reaches 0,
347df8bae1dSRodney W. Grimes  * do process and kernel statistics.
348df8bae1dSRodney W. Grimes  */
349df8bae1dSRodney W. Grimes void
350df8bae1dSRodney W. Grimes statclock(frame)
351df8bae1dSRodney W. Grimes 	register struct clockframe *frame;
352df8bae1dSRodney W. Grimes {
353df8bae1dSRodney W. Grimes #ifdef GPROF
354df8bae1dSRodney W. Grimes 	register struct gmonparam *g;
355df8bae1dSRodney W. Grimes #endif
356f5e9e8ecSBruce Evans 	register struct proc *p;
357df8bae1dSRodney W. Grimes 	register int i;
3588a129caeSDavid Greenman 	struct pstats *pstats;
359f5e9e8ecSBruce Evans 	long rss;
3608a129caeSDavid Greenman 	struct rusage *ru;
3618a129caeSDavid Greenman 	struct vmspace *vm;
3628a129caeSDavid Greenman 
363df8bae1dSRodney W. Grimes 	if (CLKF_USERMODE(frame)) {
364f5e9e8ecSBruce Evans 		p = curproc;
365df8bae1dSRodney W. Grimes 		if (p->p_flag & P_PROFIL)
366df8bae1dSRodney W. Grimes 			addupc_intr(p, CLKF_PC(frame), 1);
367eae8fc2cSSteve Passe #if defined(SMP) && defined(BETTER_CLOCK)
368eae8fc2cSSteve Passe 		if (stathz != 0)
369eae8fc2cSSteve Passe 			forward_statclock(pscnt);
370eae8fc2cSSteve Passe #endif
371df8bae1dSRodney W. Grimes 		if (--pscnt > 0)
372df8bae1dSRodney W. Grimes 			return;
373df8bae1dSRodney W. Grimes 		/*
374df8bae1dSRodney W. Grimes 		 * Came from user mode; CPU was in user state.
375df8bae1dSRodney W. Grimes 		 * If this process is being profiled record the tick.
376df8bae1dSRodney W. Grimes 		 */
377df8bae1dSRodney W. Grimes 		p->p_uticks++;
378df8bae1dSRodney W. Grimes 		if (p->p_nice > NZERO)
379df8bae1dSRodney W. Grimes 			cp_time[CP_NICE]++;
380df8bae1dSRodney W. Grimes 		else
381df8bae1dSRodney W. Grimes 			cp_time[CP_USER]++;
382df8bae1dSRodney W. Grimes 	} else {
383df8bae1dSRodney W. Grimes #ifdef GPROF
384df8bae1dSRodney W. Grimes 		/*
385df8bae1dSRodney W. Grimes 		 * Kernel statistics are just like addupc_intr, only easier.
386df8bae1dSRodney W. Grimes 		 */
387df8bae1dSRodney W. Grimes 		g = &_gmonparam;
388df8bae1dSRodney W. Grimes 		if (g->state == GMON_PROF_ON) {
389df8bae1dSRodney W. Grimes 			i = CLKF_PC(frame) - g->lowpc;
390df8bae1dSRodney W. Grimes 			if (i < g->textsize) {
391df8bae1dSRodney W. Grimes 				i /= HISTFRACTION * sizeof(*g->kcount);
392df8bae1dSRodney W. Grimes 				g->kcount[i]++;
393df8bae1dSRodney W. Grimes 			}
394df8bae1dSRodney W. Grimes 		}
395df8bae1dSRodney W. Grimes #endif
396eae8fc2cSSteve Passe #if defined(SMP) && defined(BETTER_CLOCK)
397eae8fc2cSSteve Passe 		if (stathz != 0)
398eae8fc2cSSteve Passe 			forward_statclock(pscnt);
399eae8fc2cSSteve Passe #endif
400df8bae1dSRodney W. Grimes 		if (--pscnt > 0)
401df8bae1dSRodney W. Grimes 			return;
402df8bae1dSRodney W. Grimes 		/*
403df8bae1dSRodney W. Grimes 		 * Came from kernel mode, so we were:
404df8bae1dSRodney W. Grimes 		 * - handling an interrupt,
405df8bae1dSRodney W. Grimes 		 * - doing syscall or trap work on behalf of the current
406df8bae1dSRodney W. Grimes 		 *   user process, or
407df8bae1dSRodney W. Grimes 		 * - spinning in the idle loop.
408df8bae1dSRodney W. Grimes 		 * Whichever it is, charge the time as appropriate.
409df8bae1dSRodney W. Grimes 		 * Note that we charge interrupts to the current process,
410df8bae1dSRodney W. Grimes 		 * regardless of whether they are ``for'' that process,
411df8bae1dSRodney W. Grimes 		 * so that we know how much of its real time was spent
412df8bae1dSRodney W. Grimes 		 * in ``non-process'' (i.e., interrupt) work.
413df8bae1dSRodney W. Grimes 		 */
414f5e9e8ecSBruce Evans 		p = curproc;
415df8bae1dSRodney W. Grimes 		if (CLKF_INTR(frame)) {
416df8bae1dSRodney W. Grimes 			if (p != NULL)
417df8bae1dSRodney W. Grimes 				p->p_iticks++;
418df8bae1dSRodney W. Grimes 			cp_time[CP_INTR]++;
419b672aa4bSBruce Evans 		} else if (p != NULL) {
420df8bae1dSRodney W. Grimes 			p->p_sticks++;
421df8bae1dSRodney W. Grimes 			cp_time[CP_SYS]++;
422df8bae1dSRodney W. Grimes 		} else
423df8bae1dSRodney W. Grimes 			cp_time[CP_IDLE]++;
424df8bae1dSRodney W. Grimes 	}
425df8bae1dSRodney W. Grimes 	pscnt = psdiv;
426df8bae1dSRodney W. Grimes 
427df8bae1dSRodney W. Grimes 	/*
428df8bae1dSRodney W. Grimes 	 * We maintain statistics shown by user-level statistics
429df8bae1dSRodney W. Grimes 	 * programs:  the amount of time in each cpu state, and
430df8bae1dSRodney W. Grimes 	 * the amount of time each of DK_NDRIVE ``drives'' is busy.
431df8bae1dSRodney W. Grimes 	 *
432df8bae1dSRodney W. Grimes 	 * XXX	should either run linked list of drives, or (better)
433df8bae1dSRodney W. Grimes 	 *	grab timestamps in the start & done code.
434df8bae1dSRodney W. Grimes 	 */
435df8bae1dSRodney W. Grimes 	for (i = 0; i < DK_NDRIVE; i++)
436df8bae1dSRodney W. Grimes 		if (dk_busy & (1 << i))
437df8bae1dSRodney W. Grimes 			dk_time[i]++;
438df8bae1dSRodney W. Grimes 
439df8bae1dSRodney W. Grimes 	/*
440df8bae1dSRodney W. Grimes 	 * We adjust the priority of the current process.  The priority of
441df8bae1dSRodney W. Grimes 	 * a process gets worse as it accumulates CPU time.  The cpu usage
442df8bae1dSRodney W. Grimes 	 * estimator (p_estcpu) is increased here.  The formula for computing
443df8bae1dSRodney W. Grimes 	 * priorities (in kern_synch.c) will compute a different value each
444df8bae1dSRodney W. Grimes 	 * time p_estcpu increases by 4.  The cpu usage estimator ramps up
445df8bae1dSRodney W. Grimes 	 * quite quickly when the process is running (linearly), and decays
446df8bae1dSRodney W. Grimes 	 * away exponentially, at a rate which is proportionally slower when
447df8bae1dSRodney W. Grimes 	 * the system is busy.  The basic principal is that the system will
448df8bae1dSRodney W. Grimes 	 * 90% forget that the process used a lot of CPU time in 5 * loadav
449df8bae1dSRodney W. Grimes 	 * seconds.  This causes the system to favor processes which haven't
450df8bae1dSRodney W. Grimes 	 * run much recently, and to round-robin among other processes.
451df8bae1dSRodney W. Grimes 	 */
452df8bae1dSRodney W. Grimes 	if (p != NULL) {
453df8bae1dSRodney W. Grimes 		p->p_cpticks++;
454df8bae1dSRodney W. Grimes 		if (++p->p_estcpu == 0)
455df8bae1dSRodney W. Grimes 			p->p_estcpu--;
456df8bae1dSRodney W. Grimes 		if ((p->p_estcpu & 3) == 0) {
457df8bae1dSRodney W. Grimes 			resetpriority(p);
458df8bae1dSRodney W. Grimes 			if (p->p_priority >= PUSER)
459df8bae1dSRodney W. Grimes 				p->p_priority = p->p_usrpri;
460df8bae1dSRodney W. Grimes 		}
461f5e9e8ecSBruce Evans 
462f5e9e8ecSBruce Evans 		/* Update resource usage integrals and maximums. */
463f5e9e8ecSBruce Evans 		if ((pstats = p->p_stats) != NULL &&
464f5e9e8ecSBruce Evans 		    (ru = &pstats->p_ru) != NULL &&
465f5e9e8ecSBruce Evans 		    (vm = p->p_vmspace) != NULL) {
466f5e9e8ecSBruce Evans 			ru->ru_ixrss += vm->vm_tsize * PAGE_SIZE / 1024;
467f5e9e8ecSBruce Evans 			ru->ru_idrss += vm->vm_dsize * PAGE_SIZE / 1024;
468f5e9e8ecSBruce Evans 			ru->ru_isrss += vm->vm_ssize * PAGE_SIZE / 1024;
469f5e9e8ecSBruce Evans 			rss = vm->vm_pmap.pm_stats.resident_count *
470f5e9e8ecSBruce Evans 			      PAGE_SIZE / 1024;
471f5e9e8ecSBruce Evans 			if (ru->ru_maxrss < rss)
472f5e9e8ecSBruce Evans 				ru->ru_maxrss = rss;
473f5e9e8ecSBruce Evans         	}
474df8bae1dSRodney W. Grimes 	}
475df8bae1dSRodney W. Grimes }
476df8bae1dSRodney W. Grimes 
477df8bae1dSRodney W. Grimes /*
478df8bae1dSRodney W. Grimes  * Return information about system clocks.
479df8bae1dSRodney W. Grimes  */
480787d58f2SPoul-Henning Kamp static int
481787d58f2SPoul-Henning Kamp sysctl_kern_clockrate SYSCTL_HANDLER_ARGS
482df8bae1dSRodney W. Grimes {
483df8bae1dSRodney W. Grimes 	struct clockinfo clkinfo;
484df8bae1dSRodney W. Grimes 	/*
485df8bae1dSRodney W. Grimes 	 * Construct clockinfo structure.
486df8bae1dSRodney W. Grimes 	 */
487df8bae1dSRodney W. Grimes 	clkinfo.hz = hz;
488df8bae1dSRodney W. Grimes 	clkinfo.tick = tick;
4895faa3121SJohn Hay 	clkinfo.tickadj = tickadj;
490df8bae1dSRodney W. Grimes 	clkinfo.profhz = profhz;
491df8bae1dSRodney W. Grimes 	clkinfo.stathz = stathz ? stathz : hz;
492ae0eb976SPoul-Henning Kamp 	return (sysctl_handle_opaque(oidp, &clkinfo, sizeof clkinfo, req));
493df8bae1dSRodney W. Grimes }
4943f31c649SGarrett Wollman 
495946bb7a2SPoul-Henning Kamp SYSCTL_PROC(_kern, KERN_CLOCKRATE, clockrate, CTLTYPE_STRUCT|CTLFLAG_RD,
49665d0bc13SPoul-Henning Kamp 	0, 0, sysctl_kern_clockrate, "S,clockinfo","");
497787d58f2SPoul-Henning Kamp 
498c7c9a816SPoul-Henning Kamp void
4997ec73f64SPoul-Henning Kamp microtime(struct timeval *tv)
500c7c9a816SPoul-Henning Kamp {
5017ec73f64SPoul-Henning Kamp 	struct timecounter *tc;
5027ec73f64SPoul-Henning Kamp 
5037ec73f64SPoul-Henning Kamp 	tc = (struct timecounter *)timecounter;
5047ec73f64SPoul-Henning Kamp 	tv->tv_sec = tc->offset_sec;
5057ec73f64SPoul-Henning Kamp 	tv->tv_usec = tc->offset_micro;
5067ec73f64SPoul-Henning Kamp 	tv->tv_usec +=
5077ec73f64SPoul-Henning Kamp 	    ((u_int64_t)tc->get_timedelta(tc) * tc->scale_micro) >> 32;
5087ec73f64SPoul-Henning Kamp 	if (tv->tv_usec >= 1000000) {
5097ec73f64SPoul-Henning Kamp 		tv->tv_usec -= 1000000;
5107ec73f64SPoul-Henning Kamp 		tv->tv_sec++;
511c7c9a816SPoul-Henning Kamp 	}
5127ec73f64SPoul-Henning Kamp }
5137ec73f64SPoul-Henning Kamp 
5147ec73f64SPoul-Henning Kamp void
5157ec73f64SPoul-Henning Kamp nanotime(struct timespec *tv)
5167ec73f64SPoul-Henning Kamp {
517b05dcf3cSPoul-Henning Kamp 	u_int count;
5187ec73f64SPoul-Henning Kamp 	u_int64_t delta;
5197ec73f64SPoul-Henning Kamp 	struct timecounter *tc;
5207ec73f64SPoul-Henning Kamp 
5217ec73f64SPoul-Henning Kamp 	tc = (struct timecounter *)timecounter;
5227ec73f64SPoul-Henning Kamp 	tv->tv_sec = tc->offset_sec;
5237ec73f64SPoul-Henning Kamp 	count = tc->get_timedelta(tc);
5247ec73f64SPoul-Henning Kamp 	delta = tc->offset_nano;
5257ec73f64SPoul-Henning Kamp 	delta += ((u_int64_t)count * tc->scale_nano_f);
5267ec73f64SPoul-Henning Kamp 	delta >>= 32;
527b05dcf3cSPoul-Henning Kamp 	delta += ((u_int64_t)count * tc->scale_nano_i);
5287ec73f64SPoul-Henning Kamp 	if (delta >= 1000000000) {
5297ec73f64SPoul-Henning Kamp 		delta -= 1000000000;
5307ec73f64SPoul-Henning Kamp 		tv->tv_sec++;
5317ec73f64SPoul-Henning Kamp 	}
5327ec73f64SPoul-Henning Kamp 	tv->tv_nsec = delta;
5337ec73f64SPoul-Henning Kamp }
5347ec73f64SPoul-Henning Kamp 
5357ec73f64SPoul-Henning Kamp static void
5367ec73f64SPoul-Henning Kamp tco_setscales(struct timecounter *tc)
5377ec73f64SPoul-Henning Kamp {
5387ec73f64SPoul-Henning Kamp 	u_int64_t scale;
5397ec73f64SPoul-Henning Kamp 
5407ec73f64SPoul-Henning Kamp 	scale = 1000000000LL << 32;
5417ec73f64SPoul-Henning Kamp 	if (tc->adjustment > 0)
5427ec73f64SPoul-Henning Kamp 		scale += (tc->adjustment * 1000LL) << 10;
5437ec73f64SPoul-Henning Kamp 	else
5447ec73f64SPoul-Henning Kamp 		scale -= (-tc->adjustment * 1000LL) << 10;
5457ec73f64SPoul-Henning Kamp 	scale /= tc->frequency;
5467ec73f64SPoul-Henning Kamp 	tc->scale_micro = scale / 1000;
5477ec73f64SPoul-Henning Kamp 	tc->scale_nano_f = scale & 0xffffffff;
5487ec73f64SPoul-Henning Kamp 	tc->scale_nano_i = scale >> 32;
5497ec73f64SPoul-Henning Kamp }
5507ec73f64SPoul-Henning Kamp 
5517ec73f64SPoul-Henning Kamp static u_int
5527ec73f64SPoul-Henning Kamp delta_timecounter(struct timecounter *tc)
5537ec73f64SPoul-Henning Kamp {
554b05dcf3cSPoul-Henning Kamp 
5557ec73f64SPoul-Henning Kamp 	return((tc->get_timecount() - tc->offset_count) & tc->counter_mask);
5567ec73f64SPoul-Henning Kamp }
5577ec73f64SPoul-Henning Kamp 
5587ec73f64SPoul-Henning Kamp void
5597ec73f64SPoul-Henning Kamp init_timecounter(struct timecounter *tc)
5607ec73f64SPoul-Henning Kamp {
5617ec73f64SPoul-Henning Kamp 	struct timespec ts0, ts1;
5627ec73f64SPoul-Henning Kamp 	int i;
5637ec73f64SPoul-Henning Kamp 
5647ec73f64SPoul-Henning Kamp 	if (!tc->get_timedelta)
5657ec73f64SPoul-Henning Kamp 		tc->get_timedelta = delta_timecounter;
5667ec73f64SPoul-Henning Kamp 	tc->adjustment = 0;
5677ec73f64SPoul-Henning Kamp 	tco_setscales(tc);
5687ec73f64SPoul-Henning Kamp 	tc->offset_count = tc->get_timecount();
5697ec73f64SPoul-Henning Kamp 	tc[0].tweak = &tc[0];
5707ec73f64SPoul-Henning Kamp 	tc[2] = tc[1] = tc[0];
5717ec73f64SPoul-Henning Kamp 	tc[1].other = &tc[2];
5727ec73f64SPoul-Henning Kamp 	tc[2].other = &tc[1];
5737ec73f64SPoul-Henning Kamp 	if (!timecounter)
5747ec73f64SPoul-Henning Kamp 		timecounter = &tc[2];
5757ec73f64SPoul-Henning Kamp 	tc = &tc[1];
5767ec73f64SPoul-Henning Kamp 
5777ec73f64SPoul-Henning Kamp 	/*
5787ec73f64SPoul-Henning Kamp 	 * Figure out the cost of calling this timecounter.
5797ec73f64SPoul-Henning Kamp 	 * XXX: The 1:15 ratio is a guess at reality.
5807ec73f64SPoul-Henning Kamp 	 */
5817ec73f64SPoul-Henning Kamp 	nanotime(&ts0);
5827ec73f64SPoul-Henning Kamp 	for (i = 0; i < 16; i ++)
5837ec73f64SPoul-Henning Kamp 		tc->get_timecount();
5847ec73f64SPoul-Henning Kamp 	for (i = 0; i < 240; i ++)
5857ec73f64SPoul-Henning Kamp 		tc->get_timedelta(tc);
5867ec73f64SPoul-Henning Kamp 	nanotime(&ts1);
5877ec73f64SPoul-Henning Kamp 	ts1.tv_sec -= ts0.tv_sec;
5887ec73f64SPoul-Henning Kamp 	tc->cost = ts1.tv_sec * 1000000000 + ts1.tv_nsec - ts0.tv_nsec;
5897ec73f64SPoul-Henning Kamp 	tc->cost >>= 8;
590b05dcf3cSPoul-Henning Kamp 	if (print_tci)
5917ec73f64SPoul-Henning Kamp 	printf("Timecounter \"%s\"  frequency %lu Hz  cost %u ns\n",
5927ec73f64SPoul-Henning Kamp 	    tc->name, tc->frequency, tc->cost);
5937ec73f64SPoul-Henning Kamp 
5947ec73f64SPoul-Henning Kamp 	/* XXX: For now always start using the counter. */
5957ec73f64SPoul-Henning Kamp 	tc->offset_count = tc->get_timecount();
5967ec73f64SPoul-Henning Kamp 	nanotime(&ts1);
5977ec73f64SPoul-Henning Kamp 	tc->offset_nano = (u_int64_t)ts1.tv_nsec << 32;
5987ec73f64SPoul-Henning Kamp 	tc->offset_micro = ts1.tv_nsec / 1000;
5997ec73f64SPoul-Henning Kamp 	tc->offset_sec = ts1.tv_sec;
6007ec73f64SPoul-Henning Kamp 	timecounter = tc;
6017ec73f64SPoul-Henning Kamp }
6027ec73f64SPoul-Henning Kamp 
6037ec73f64SPoul-Henning Kamp void
6047ec73f64SPoul-Henning Kamp set_timecounter(struct timespec *ts)
6057ec73f64SPoul-Henning Kamp {
6067ec73f64SPoul-Henning Kamp 	struct timecounter *tc, *tco;
6077ec73f64SPoul-Henning Kamp 	int s;
6087ec73f64SPoul-Henning Kamp 
609b05dcf3cSPoul-Henning Kamp 	/*
610b05dcf3cSPoul-Henning Kamp 	 * XXX we must be called at splclock() to preven *ts becoming
611b05dcf3cSPoul-Henning Kamp 	 * invalid, so there is no point in spls here.
612b05dcf3cSPoul-Henning Kamp 	 */
6137ec73f64SPoul-Henning Kamp 	s = splclock();
6147ec73f64SPoul-Henning Kamp 	tc = timecounter->other;
6157ec73f64SPoul-Henning Kamp 	tco = tc->other;
6167ec73f64SPoul-Henning Kamp 	*tc = *timecounter;
6177ec73f64SPoul-Henning Kamp 	tc->other = tco;
6187ec73f64SPoul-Henning Kamp 	tc->offset_sec = ts->tv_sec;
6197ec73f64SPoul-Henning Kamp 	tc->offset_nano = (u_int64_t)ts->tv_nsec << 32;
6207ec73f64SPoul-Henning Kamp 	tc->offset_micro = ts->tv_nsec / 1000;
6217ec73f64SPoul-Henning Kamp 	tc->offset_count = tc->get_timecount();
6227ec73f64SPoul-Henning Kamp 	time.tv_sec = tc->offset_sec;
6237ec73f64SPoul-Henning Kamp 	time.tv_usec = tc->offset_micro;
6247ec73f64SPoul-Henning Kamp 	timecounter = tc;
6257ec73f64SPoul-Henning Kamp 	splx(s);
6267ec73f64SPoul-Henning Kamp }
6277ec73f64SPoul-Henning Kamp 
628b05dcf3cSPoul-Henning Kamp void
629b05dcf3cSPoul-Henning Kamp switch_timecounter(struct timecounter *newtc)
630b05dcf3cSPoul-Henning Kamp {
631b05dcf3cSPoul-Henning Kamp 	int s;
632b05dcf3cSPoul-Henning Kamp 	struct timecounter *tc;
633b05dcf3cSPoul-Henning Kamp 	struct timespec ts;
634b05dcf3cSPoul-Henning Kamp 
635b05dcf3cSPoul-Henning Kamp 	s = splclock();
636b05dcf3cSPoul-Henning Kamp 	tc = timecounter;
637b05dcf3cSPoul-Henning Kamp 	if (newtc == tc || newtc == tc->other) {
638b05dcf3cSPoul-Henning Kamp 		splx(s);
639b05dcf3cSPoul-Henning Kamp 		return;
640b05dcf3cSPoul-Henning Kamp 	}
641b05dcf3cSPoul-Henning Kamp 	nanotime(&ts);
642b05dcf3cSPoul-Henning Kamp 	newtc->offset_sec = ts.tv_sec;
643b05dcf3cSPoul-Henning Kamp 	newtc->offset_nano = (u_int64_t)ts.tv_nsec << 32;
644b05dcf3cSPoul-Henning Kamp 	newtc->offset_micro = ts.tv_nsec / 1000;
645b05dcf3cSPoul-Henning Kamp 	newtc->offset_count = newtc->get_timecount();
646b05dcf3cSPoul-Henning Kamp 	timecounter = newtc;
647b05dcf3cSPoul-Henning Kamp 	splx(s);
648b05dcf3cSPoul-Henning Kamp }
649b05dcf3cSPoul-Henning Kamp 
6507ec73f64SPoul-Henning Kamp static struct timecounter *
651b05dcf3cSPoul-Henning Kamp sync_other_counter(void)
6527ec73f64SPoul-Henning Kamp {
6537ec73f64SPoul-Henning Kamp 	struct timecounter *tc, *tco;
654b05dcf3cSPoul-Henning Kamp 	u_int delta;
6557ec73f64SPoul-Henning Kamp 
6567ec73f64SPoul-Henning Kamp 	tc = timecounter->other;
6577ec73f64SPoul-Henning Kamp 	tco = tc->other;
6587ec73f64SPoul-Henning Kamp 	*tc = *timecounter;
6597ec73f64SPoul-Henning Kamp 	tc->other = tco;
6607ec73f64SPoul-Henning Kamp 	delta = tc->get_timedelta(tc);
6617ec73f64SPoul-Henning Kamp 	tc->offset_count += delta;
6627ec73f64SPoul-Henning Kamp 	tc->offset_count &= tc->counter_mask;
6637ec73f64SPoul-Henning Kamp 	tc->offset_nano += (u_int64_t)delta * tc->scale_nano_f;
6647ec73f64SPoul-Henning Kamp 	tc->offset_nano += (u_int64_t)delta * tc->scale_nano_i << 32;
6657ec73f64SPoul-Henning Kamp 	return (tc);
6667ec73f64SPoul-Henning Kamp }
6677ec73f64SPoul-Henning Kamp 
6687ec73f64SPoul-Henning Kamp static void
6697ec73f64SPoul-Henning Kamp tco_forward(void)
6707ec73f64SPoul-Henning Kamp {
6717ec73f64SPoul-Henning Kamp 	struct timecounter *tc;
6727ec73f64SPoul-Henning Kamp 
673b05dcf3cSPoul-Henning Kamp 	tc = sync_other_counter();
674b05dcf3cSPoul-Henning Kamp 	if (timedelta != 0) {
675b05dcf3cSPoul-Henning Kamp 		tc->offset_nano += (u_int64_t)(tickdelta * 1000) << 32;
676b05dcf3cSPoul-Henning Kamp 		mono_time.tv_usec += tickdelta;
6777ec73f64SPoul-Henning Kamp 		timedelta -= tickdelta;
6787ec73f64SPoul-Henning Kamp 	}
679b05dcf3cSPoul-Henning Kamp 	mono_time.tv_usec += tick;
6807ec73f64SPoul-Henning Kamp 	if (mono_time.tv_usec >= 1000000) {
6817ec73f64SPoul-Henning Kamp 		mono_time.tv_usec -= 1000000;
6827ec73f64SPoul-Henning Kamp 		mono_time.tv_sec++;
6837ec73f64SPoul-Henning Kamp 	}
684b05dcf3cSPoul-Henning Kamp 
6857ec73f64SPoul-Henning Kamp 	if (tc->offset_nano >= 1000000000ULL << 32) {
6867ec73f64SPoul-Henning Kamp 		tc->offset_nano -= 1000000000ULL << 32;
6877ec73f64SPoul-Henning Kamp 		tc->offset_sec++;
6887ec73f64SPoul-Henning Kamp 		tc->frequency = tc->tweak->frequency;
689b05dcf3cSPoul-Henning Kamp 		tc->adjustment = tc->tweak->adjustment;
6907ec73f64SPoul-Henning Kamp 		ntp_update_second(tc);	/* XXX only needed if xntpd runs */
6917ec73f64SPoul-Henning Kamp 		tco_setscales(tc);
6927ec73f64SPoul-Henning Kamp 	}
693b05dcf3cSPoul-Henning Kamp 
6947ec73f64SPoul-Henning Kamp 	tc->offset_micro = (tc->offset_nano / 1000) >> 32;
695b05dcf3cSPoul-Henning Kamp 
6967ec73f64SPoul-Henning Kamp 	time.tv_usec = tc->offset_micro;
6977ec73f64SPoul-Henning Kamp 	time.tv_sec = tc->offset_sec;
6987ec73f64SPoul-Henning Kamp 	timecounter = tc;
6997ec73f64SPoul-Henning Kamp }
7007ec73f64SPoul-Henning Kamp 
7017ec73f64SPoul-Henning Kamp static int
7027ec73f64SPoul-Henning Kamp sysctl_kern_timecounter_frequency SYSCTL_HANDLER_ARGS
7037ec73f64SPoul-Henning Kamp {
704b05dcf3cSPoul-Henning Kamp 
7057ec73f64SPoul-Henning Kamp 	return (sysctl_handle_opaque(oidp, &timecounter->tweak->frequency,
7067ec73f64SPoul-Henning Kamp 	    sizeof(timecounter->tweak->frequency), req));
7077ec73f64SPoul-Henning Kamp }
7087ec73f64SPoul-Henning Kamp 
7097ec73f64SPoul-Henning Kamp static int
7107ec73f64SPoul-Henning Kamp sysctl_kern_timecounter_adjustment SYSCTL_HANDLER_ARGS
7117ec73f64SPoul-Henning Kamp {
712b05dcf3cSPoul-Henning Kamp 
7137ec73f64SPoul-Henning Kamp 	return (sysctl_handle_opaque(oidp, &timecounter->tweak->adjustment,
7147ec73f64SPoul-Henning Kamp 	    sizeof(timecounter->tweak->adjustment), req));
7157ec73f64SPoul-Henning Kamp }
7167ec73f64SPoul-Henning Kamp 
7177ec73f64SPoul-Henning Kamp SYSCTL_NODE(_kern, OID_AUTO, timecounter, CTLFLAG_RW, 0, "");
7187ec73f64SPoul-Henning Kamp 
7197ec73f64SPoul-Henning Kamp SYSCTL_PROC(_kern_timecounter, OID_AUTO, frequency, CTLTYPE_INT | CTLFLAG_RW,
7207ec73f64SPoul-Henning Kamp     0, sizeof(u_int), sysctl_kern_timecounter_frequency, "I", "");
7217ec73f64SPoul-Henning Kamp 
7227ec73f64SPoul-Henning Kamp SYSCTL_PROC(_kern_timecounter, OID_AUTO, adjustment, CTLTYPE_INT | CTLFLAG_RW,
7237ec73f64SPoul-Henning Kamp     0, sizeof(int), sysctl_kern_timecounter_adjustment, "I", "");
724