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