1df8bae1dSRodney W. Grimes /*- 27ec73f64SPoul-Henning Kamp * Copyright (c) 1997, 1998 Poul-Henning Kamp <phk@FreeBSD.org> 3df8bae1dSRodney W. Grimes * Copyright (c) 1982, 1986, 1991, 1993 4df8bae1dSRodney W. Grimes * The Regents of the University of California. All rights reserved. 5df8bae1dSRodney W. Grimes * (c) UNIX System Laboratories, Inc. 6df8bae1dSRodney W. Grimes * All or some portions of this file are derived from material licensed 7df8bae1dSRodney W. Grimes * to the University of California by American Telephone and Telegraph 8df8bae1dSRodney W. Grimes * Co. or Unix System Laboratories, Inc. and are reproduced herein with 9df8bae1dSRodney W. Grimes * the permission of UNIX System Laboratories, Inc. 10df8bae1dSRodney W. Grimes * 11df8bae1dSRodney W. Grimes * Redistribution and use in source and binary forms, with or without 12df8bae1dSRodney W. Grimes * modification, are permitted provided that the following conditions 13df8bae1dSRodney W. Grimes * are met: 14df8bae1dSRodney W. Grimes * 1. Redistributions of source code must retain the above copyright 15df8bae1dSRodney W. Grimes * notice, this list of conditions and the following disclaimer. 16df8bae1dSRodney W. Grimes * 2. Redistributions in binary form must reproduce the above copyright 17df8bae1dSRodney W. Grimes * notice, this list of conditions and the following disclaimer in the 18df8bae1dSRodney W. Grimes * documentation and/or other materials provided with the distribution. 19df8bae1dSRodney W. Grimes * 3. All advertising materials mentioning features or use of this software 20df8bae1dSRodney W. Grimes * must display the following acknowledgement: 21df8bae1dSRodney W. Grimes * This product includes software developed by the University of 22df8bae1dSRodney W. Grimes * California, Berkeley and its contributors. 23df8bae1dSRodney W. Grimes * 4. Neither the name of the University nor the names of its contributors 24df8bae1dSRodney W. Grimes * may be used to endorse or promote products derived from this software 25df8bae1dSRodney W. Grimes * without specific prior written permission. 26df8bae1dSRodney W. Grimes * 27df8bae1dSRodney W. Grimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 28df8bae1dSRodney W. Grimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 29df8bae1dSRodney W. Grimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 30df8bae1dSRodney W. Grimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 31df8bae1dSRodney W. Grimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 32df8bae1dSRodney W. Grimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 33df8bae1dSRodney W. Grimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 34df8bae1dSRodney W. Grimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 35df8bae1dSRodney W. Grimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 36df8bae1dSRodney W. Grimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 37df8bae1dSRodney W. Grimes * SUCH DAMAGE. 38df8bae1dSRodney W. Grimes * 39df8bae1dSRodney W. Grimes * @(#)kern_clock.c 8.5 (Berkeley) 1/21/94 40c3aac50fSPeter Wemm * $FreeBSD$ 41df8bae1dSRodney W. Grimes */ 42df8bae1dSRodney W. Grimes 4332c20357SPoul-Henning Kamp #include "opt_ntp.h" 4432c20357SPoul-Henning Kamp 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> 513bac064fSPoul-Henning Kamp #include <sys/malloc.h> 52df8bae1dSRodney W. Grimes #include <sys/resourcevar.h> 53797f2d22SPoul-Henning Kamp #include <sys/signalvar.h> 543f31c649SGarrett Wollman #include <sys/timex.h> 5532c20357SPoul-Henning Kamp #include <sys/timepps.h> 568a129caeSDavid Greenman #include <vm/vm.h> 57996c772fSJohn Dyson #include <sys/lock.h> 58efeaf95aSDavid Greenman #include <vm/pmap.h> 59efeaf95aSDavid Greenman #include <vm/vm_map.h> 60797f2d22SPoul-Henning Kamp #include <sys/sysctl.h> 61df8bae1dSRodney W. Grimes 62df8bae1dSRodney W. Grimes #include <machine/cpu.h> 63b1037dcdSBruce Evans #include <machine/limits.h> 64df8bae1dSRodney W. Grimes 65df8bae1dSRodney W. Grimes #ifdef GPROF 66df8bae1dSRodney W. Grimes #include <sys/gmon.h> 67df8bae1dSRodney W. Grimes #endif 68df8bae1dSRodney W. Grimes 69eae8fc2cSSteve Passe #if defined(SMP) && defined(BETTER_CLOCK) 70eae8fc2cSSteve Passe #include <machine/smp.h> 71eae8fc2cSSteve Passe #endif 72eae8fc2cSSteve Passe 733bac064fSPoul-Henning Kamp /* 743bac064fSPoul-Henning Kamp * Number of timecounters used to implement stable storage 753bac064fSPoul-Henning Kamp */ 763bac064fSPoul-Henning Kamp #ifndef NTIMECOUNTER 77c2906d55SPoul-Henning Kamp #define NTIMECOUNTER 5 783bac064fSPoul-Henning Kamp #endif 793bac064fSPoul-Henning Kamp 803bac064fSPoul-Henning Kamp static MALLOC_DEFINE(M_TIMECOUNTER, "timecounter", 813bac064fSPoul-Henning Kamp "Timecounter stable storage"); 823bac064fSPoul-Henning Kamp 83d841aaa7SBruce Evans static void initclocks __P((void *dummy)); 842b14f991SJulian Elischer SYSINIT(clocks, SI_SUB_CLOCKS, SI_ORDER_FIRST, initclocks, NULL) 852b14f991SJulian Elischer 86c2906d55SPoul-Henning Kamp static void tco_forward __P((int force)); 877ec73f64SPoul-Henning Kamp static void tco_setscales __P((struct timecounter *tc)); 88a58f0f8eSPoul-Henning Kamp static __inline unsigned tco_delta __P((struct timecounter *tc)); 897ec73f64SPoul-Henning Kamp 90f23b4c91SGarrett Wollman /* Some of these don't belong here, but it's easiest to concentrate them. */ 91eae8fc2cSSteve Passe #if defined(SMP) && defined(BETTER_CLOCK) 92eae8fc2cSSteve Passe long cp_time[CPUSTATES]; 93eae8fc2cSSteve Passe #else 9427a0b398SPoul-Henning Kamp static long cp_time[CPUSTATES]; 95eae8fc2cSSteve Passe #endif 96f23b4c91SGarrett Wollman 97f23b4c91SGarrett Wollman long tk_cancc; 98f23b4c91SGarrett Wollman long tk_nin; 99f23b4c91SGarrett Wollman long tk_nout; 100f23b4c91SGarrett Wollman long tk_rawcc; 101f23b4c91SGarrett Wollman 102227ee8a1SPoul-Henning Kamp time_t time_second; 103227ee8a1SPoul-Henning Kamp 104df8bae1dSRodney W. Grimes /* 105510eb5b9SPoul-Henning Kamp * Which update policy to use. 106510eb5b9SPoul-Henning Kamp * 0 - every tick, bad hardware may fail with "calcru negative..." 107510eb5b9SPoul-Henning Kamp * 1 - more resistent to the above hardware, but less efficient. 108510eb5b9SPoul-Henning Kamp */ 109510eb5b9SPoul-Henning Kamp static int tco_method; 110510eb5b9SPoul-Henning Kamp 111510eb5b9SPoul-Henning Kamp /* 1123bac064fSPoul-Henning Kamp * Implement a dummy timecounter which we can use until we get a real one 1133bac064fSPoul-Henning Kamp * in the air. This allows the console and other early stuff to use 1143bac064fSPoul-Henning Kamp * timeservices. 1153bac064fSPoul-Henning Kamp */ 1163bac064fSPoul-Henning Kamp 1173bac064fSPoul-Henning Kamp static unsigned 1183bac064fSPoul-Henning Kamp dummy_get_timecount(struct timecounter *tc) 1193bac064fSPoul-Henning Kamp { 1203bac064fSPoul-Henning Kamp static unsigned now; 1213bac064fSPoul-Henning Kamp return (++now); 1223bac064fSPoul-Henning Kamp } 1233bac064fSPoul-Henning Kamp 1243bac064fSPoul-Henning Kamp static struct timecounter dummy_timecounter = { 1253bac064fSPoul-Henning Kamp dummy_get_timecount, 1263bac064fSPoul-Henning Kamp 0, 1273bac064fSPoul-Henning Kamp ~0u, 1283bac064fSPoul-Henning Kamp 1000000, 1293bac064fSPoul-Henning Kamp "dummy" 1303bac064fSPoul-Henning Kamp }; 1313bac064fSPoul-Henning Kamp 1323bac064fSPoul-Henning Kamp struct timecounter *timecounter = &dummy_timecounter; 1333bac064fSPoul-Henning Kamp 1343bac064fSPoul-Henning Kamp /* 135df8bae1dSRodney W. Grimes * Clock handling routines. 136df8bae1dSRodney W. Grimes * 137b05dcf3cSPoul-Henning Kamp * This code is written to operate with two timers that run independently of 138b05dcf3cSPoul-Henning Kamp * each other. 1397ec73f64SPoul-Henning Kamp * 140b05dcf3cSPoul-Henning Kamp * The main timer, running hz times per second, is used to trigger interval 141b05dcf3cSPoul-Henning Kamp * timers, timeouts and rescheduling as needed. 1427ec73f64SPoul-Henning Kamp * 143b05dcf3cSPoul-Henning Kamp * The second timer handles kernel and user profiling, 144b05dcf3cSPoul-Henning Kamp * and does resource use estimation. If the second timer is programmable, 145b05dcf3cSPoul-Henning Kamp * it is randomized to avoid aliasing between the two clocks. For example, 146b05dcf3cSPoul-Henning Kamp * the randomization prevents an adversary from always giving up the cpu 147df8bae1dSRodney W. Grimes * just before its quantum expires. Otherwise, it would never accumulate 148df8bae1dSRodney W. Grimes * cpu ticks. The mean frequency of the second timer is stathz. 149b05dcf3cSPoul-Henning Kamp * 150b05dcf3cSPoul-Henning Kamp * If no second timer exists, stathz will be zero; in this case we drive 151b05dcf3cSPoul-Henning Kamp * profiling and statistics off the main clock. This WILL NOT be accurate; 152b05dcf3cSPoul-Henning Kamp * do not do it unless absolutely necessary. 153b05dcf3cSPoul-Henning Kamp * 154df8bae1dSRodney W. Grimes * The statistics clock may (or may not) be run at a higher rate while 155b05dcf3cSPoul-Henning Kamp * profiling. This profile clock runs at profhz. We require that profhz 156b05dcf3cSPoul-Henning Kamp * be an integral multiple of stathz. 157b05dcf3cSPoul-Henning Kamp * 158b05dcf3cSPoul-Henning Kamp * If the statistics clock is running fast, it must be divided by the ratio 159b05dcf3cSPoul-Henning Kamp * profhz/stathz for statistics. (For profiling, every tick counts.) 160df8bae1dSRodney W. Grimes * 1617ec73f64SPoul-Henning Kamp * Time-of-day is maintained using a "timecounter", which may or may 1627ec73f64SPoul-Henning Kamp * not be related to the hardware generating the above mentioned 1637ec73f64SPoul-Henning Kamp * interrupts. 164df8bae1dSRodney W. Grimes */ 165df8bae1dSRodney W. Grimes 166df8bae1dSRodney W. Grimes int stathz; 167df8bae1dSRodney W. Grimes int profhz; 168cc3d5226SBruce Evans static int profprocs; 169df8bae1dSRodney W. Grimes int ticks; 170df8bae1dSRodney W. Grimes static int psdiv, pscnt; /* prof => stat divider */ 171cc3d5226SBruce Evans int psratio; /* ratio: prof / stat */ 172df8bae1dSRodney W. Grimes 173df8bae1dSRodney W. Grimes /* 174df8bae1dSRodney W. Grimes * Initialize clock frequencies and start both clocks running. 175df8bae1dSRodney W. Grimes */ 1762b14f991SJulian Elischer /* ARGSUSED*/ 1772b14f991SJulian Elischer static void 178d841aaa7SBruce Evans initclocks(dummy) 179d841aaa7SBruce Evans void *dummy; 180df8bae1dSRodney W. Grimes { 181df8bae1dSRodney W. Grimes register int i; 182df8bae1dSRodney W. Grimes 183df8bae1dSRodney W. Grimes /* 184df8bae1dSRodney W. Grimes * Set divisors to 1 (normal case) and let the machine-specific 185df8bae1dSRodney W. Grimes * code do its bit. 186df8bae1dSRodney W. Grimes */ 187df8bae1dSRodney W. Grimes psdiv = pscnt = 1; 188df8bae1dSRodney W. Grimes cpu_initclocks(); 189df8bae1dSRodney W. Grimes 190df8bae1dSRodney W. Grimes /* 191df8bae1dSRodney W. Grimes * Compute profhz/stathz, and fix profhz if needed. 192df8bae1dSRodney W. Grimes */ 193df8bae1dSRodney W. Grimes i = stathz ? stathz : hz; 194df8bae1dSRodney W. Grimes if (profhz == 0) 195df8bae1dSRodney W. Grimes profhz = i; 196df8bae1dSRodney W. Grimes psratio = profhz / i; 197df8bae1dSRodney W. Grimes } 198df8bae1dSRodney W. Grimes 199df8bae1dSRodney W. Grimes /* 200df8bae1dSRodney W. Grimes * The real-time timer, interrupting hz times per second. 201df8bae1dSRodney W. Grimes */ 202df8bae1dSRodney W. Grimes void 203df8bae1dSRodney W. Grimes hardclock(frame) 204df8bae1dSRodney W. Grimes register struct clockframe *frame; 205df8bae1dSRodney W. Grimes { 206df8bae1dSRodney W. Grimes register struct proc *p; 207df8bae1dSRodney W. Grimes 208df8bae1dSRodney W. Grimes p = curproc; 209df8bae1dSRodney W. Grimes if (p) { 210df8bae1dSRodney W. Grimes register struct pstats *pstats; 211df8bae1dSRodney W. Grimes 212df8bae1dSRodney W. Grimes /* 213df8bae1dSRodney W. Grimes * Run current process's virtual and profile time, as needed. 214df8bae1dSRodney W. Grimes */ 215df8bae1dSRodney W. Grimes pstats = p->p_stats; 216df8bae1dSRodney W. Grimes if (CLKF_USERMODE(frame) && 2174cf41af3SPoul-Henning Kamp timevalisset(&pstats->p_timer[ITIMER_VIRTUAL].it_value) && 218df8bae1dSRodney W. Grimes itimerdecr(&pstats->p_timer[ITIMER_VIRTUAL], tick) == 0) 219df8bae1dSRodney W. Grimes psignal(p, SIGVTALRM); 2204cf41af3SPoul-Henning Kamp if (timevalisset(&pstats->p_timer[ITIMER_PROF].it_value) && 221df8bae1dSRodney W. Grimes itimerdecr(&pstats->p_timer[ITIMER_PROF], tick) == 0) 222df8bae1dSRodney W. Grimes psignal(p, SIGPROF); 223df8bae1dSRodney W. Grimes } 224df8bae1dSRodney W. Grimes 225eae8fc2cSSteve Passe #if defined(SMP) && defined(BETTER_CLOCK) 226eae8fc2cSSteve Passe forward_hardclock(pscnt); 227eae8fc2cSSteve Passe #endif 228b05dcf3cSPoul-Henning Kamp 229df8bae1dSRodney W. Grimes /* 230df8bae1dSRodney W. Grimes * If no separate statistics clock is available, run it from here. 231df8bae1dSRodney W. Grimes */ 232df8bae1dSRodney W. Grimes if (stathz == 0) 233df8bae1dSRodney W. Grimes statclock(frame); 234df8bae1dSRodney W. Grimes 235c2906d55SPoul-Henning Kamp tco_forward(0); 236df8bae1dSRodney W. Grimes ticks++; 2373f31c649SGarrett Wollman 238b05dcf3cSPoul-Henning Kamp /* 239b05dcf3cSPoul-Henning Kamp * Process callouts at a very low cpu priority, so we don't keep the 240b05dcf3cSPoul-Henning Kamp * relatively high clock interrupt priority any longer than necessary. 241b05dcf3cSPoul-Henning Kamp */ 242b05dcf3cSPoul-Henning Kamp if (TAILQ_FIRST(&callwheel[ticks & callwheelmask]) != NULL) { 243b05dcf3cSPoul-Henning Kamp if (CLKF_BASEPRI(frame)) { 244b05dcf3cSPoul-Henning Kamp /* 245b05dcf3cSPoul-Henning Kamp * Save the overhead of a software interrupt; 246b05dcf3cSPoul-Henning Kamp * it will happen as soon as we return, so do it now. 247b05dcf3cSPoul-Henning Kamp */ 248b05dcf3cSPoul-Henning Kamp (void)splsoftclock(); 249b05dcf3cSPoul-Henning Kamp softclock(); 250b05dcf3cSPoul-Henning Kamp } else 251eeb355f7SPoul-Henning Kamp setsoftclock(); 252b05dcf3cSPoul-Henning Kamp } else if (softticks + 1 == ticks) 253b05dcf3cSPoul-Henning Kamp ++softticks; 254ab36c067SJustin T. Gibbs } 255ab36c067SJustin T. Gibbs 256df8bae1dSRodney W. Grimes /* 257227ee8a1SPoul-Henning Kamp * Compute number of ticks in the specified amount of time. 258df8bae1dSRodney W. Grimes */ 259df8bae1dSRodney W. Grimes int 260227ee8a1SPoul-Henning Kamp tvtohz(tv) 261df8bae1dSRodney W. Grimes struct timeval *tv; 262df8bae1dSRodney W. Grimes { 2636976af69SBruce Evans register unsigned long ticks; 2646976af69SBruce Evans register long sec, usec; 265df8bae1dSRodney W. Grimes 266df8bae1dSRodney W. Grimes /* 2676976af69SBruce Evans * If the number of usecs in the whole seconds part of the time 2686976af69SBruce Evans * difference fits in a long, then the total number of usecs will 2696976af69SBruce Evans * fit in an unsigned long. Compute the total and convert it to 2706976af69SBruce Evans * ticks, rounding up and adding 1 to allow for the current tick 2716976af69SBruce Evans * to expire. Rounding also depends on unsigned long arithmetic 2726976af69SBruce Evans * to avoid overflow. 273df8bae1dSRodney W. Grimes * 2746976af69SBruce Evans * Otherwise, if the number of ticks in the whole seconds part of 2756976af69SBruce Evans * the time difference fits in a long, then convert the parts to 2766976af69SBruce Evans * ticks separately and add, using similar rounding methods and 2776976af69SBruce Evans * overflow avoidance. This method would work in the previous 2786976af69SBruce Evans * case but it is slightly slower and assumes that hz is integral. 2796976af69SBruce Evans * 2806976af69SBruce Evans * Otherwise, round the time difference down to the maximum 2816976af69SBruce Evans * representable value. 2826976af69SBruce Evans * 2836976af69SBruce Evans * If ints have 32 bits, then the maximum value for any timeout in 2846976af69SBruce Evans * 10ms ticks is 248 days. 285df8bae1dSRodney W. Grimes */ 286227ee8a1SPoul-Henning Kamp sec = tv->tv_sec; 287227ee8a1SPoul-Henning Kamp usec = tv->tv_usec; 2886976af69SBruce Evans if (usec < 0) { 2896976af69SBruce Evans sec--; 2906976af69SBruce Evans usec += 1000000; 2916976af69SBruce Evans } 2926976af69SBruce Evans if (sec < 0) { 2936976af69SBruce Evans #ifdef DIAGNOSTIC 294b05dcf3cSPoul-Henning Kamp if (usec > 0) { 2957ec73f64SPoul-Henning Kamp sec++; 2967ec73f64SPoul-Henning Kamp usec -= 1000000; 2977ec73f64SPoul-Henning Kamp } 298227ee8a1SPoul-Henning Kamp printf("tvotohz: negative time difference %ld sec %ld usec\n", 2996976af69SBruce Evans sec, usec); 3006976af69SBruce Evans #endif 3016976af69SBruce Evans ticks = 1; 3026976af69SBruce Evans } else if (sec <= LONG_MAX / 1000000) 3036976af69SBruce Evans ticks = (sec * 1000000 + (unsigned long)usec + (tick - 1)) 3046976af69SBruce Evans / tick + 1; 3056976af69SBruce Evans else if (sec <= LONG_MAX / hz) 3066976af69SBruce Evans ticks = sec * hz 3076976af69SBruce Evans + ((unsigned long)usec + (tick - 1)) / tick + 1; 3086976af69SBruce Evans else 3096976af69SBruce Evans ticks = LONG_MAX; 3106976af69SBruce Evans if (ticks > INT_MAX) 3116976af69SBruce Evans ticks = INT_MAX; 312d6116663SAlexander Langer return ((int)ticks); 313df8bae1dSRodney W. Grimes } 314df8bae1dSRodney W. Grimes 315df8bae1dSRodney W. Grimes /* 316df8bae1dSRodney W. Grimes * Start profiling on a process. 317df8bae1dSRodney W. Grimes * 318df8bae1dSRodney W. Grimes * Kernel profiling passes proc0 which never exits and hence 319df8bae1dSRodney W. Grimes * keeps the profile clock running constantly. 320df8bae1dSRodney W. Grimes */ 321df8bae1dSRodney W. Grimes void 322df8bae1dSRodney W. Grimes startprofclock(p) 323df8bae1dSRodney W. Grimes register struct proc *p; 324df8bae1dSRodney W. Grimes { 325df8bae1dSRodney W. Grimes int s; 326df8bae1dSRodney W. Grimes 327df8bae1dSRodney W. Grimes if ((p->p_flag & P_PROFIL) == 0) { 328df8bae1dSRodney W. Grimes p->p_flag |= P_PROFIL; 329df8bae1dSRodney W. Grimes if (++profprocs == 1 && stathz != 0) { 330df8bae1dSRodney W. Grimes s = splstatclock(); 331df8bae1dSRodney W. Grimes psdiv = pscnt = psratio; 332df8bae1dSRodney W. Grimes setstatclockrate(profhz); 333df8bae1dSRodney W. Grimes splx(s); 334df8bae1dSRodney W. Grimes } 335df8bae1dSRodney W. Grimes } 336df8bae1dSRodney W. Grimes } 337df8bae1dSRodney W. Grimes 338df8bae1dSRodney W. Grimes /* 339df8bae1dSRodney W. Grimes * Stop profiling on a process. 340df8bae1dSRodney W. Grimes */ 341df8bae1dSRodney W. Grimes void 342df8bae1dSRodney W. Grimes stopprofclock(p) 343df8bae1dSRodney W. Grimes register struct proc *p; 344df8bae1dSRodney W. Grimes { 345df8bae1dSRodney W. Grimes int s; 346df8bae1dSRodney W. Grimes 347df8bae1dSRodney W. Grimes if (p->p_flag & P_PROFIL) { 348df8bae1dSRodney W. Grimes p->p_flag &= ~P_PROFIL; 349df8bae1dSRodney W. Grimes if (--profprocs == 0 && stathz != 0) { 350df8bae1dSRodney W. Grimes s = splstatclock(); 351df8bae1dSRodney W. Grimes psdiv = pscnt = 1; 352df8bae1dSRodney W. Grimes setstatclockrate(stathz); 353df8bae1dSRodney W. Grimes splx(s); 354df8bae1dSRodney W. Grimes } 355df8bae1dSRodney W. Grimes } 356df8bae1dSRodney W. Grimes } 357df8bae1dSRodney W. Grimes 358df8bae1dSRodney W. Grimes /* 359df8bae1dSRodney W. Grimes * Statistics clock. Grab profile sample, and if divider reaches 0, 360df8bae1dSRodney W. Grimes * do process and kernel statistics. 361df8bae1dSRodney W. Grimes */ 362df8bae1dSRodney W. Grimes void 363df8bae1dSRodney W. Grimes statclock(frame) 364df8bae1dSRodney W. Grimes register struct clockframe *frame; 365df8bae1dSRodney W. Grimes { 366df8bae1dSRodney W. Grimes #ifdef GPROF 367df8bae1dSRodney W. Grimes register struct gmonparam *g; 368fffd686aSBruce Evans int i; 369df8bae1dSRodney W. Grimes #endif 370f5e9e8ecSBruce Evans register struct proc *p; 3718a129caeSDavid Greenman struct pstats *pstats; 372f5e9e8ecSBruce Evans long rss; 3738a129caeSDavid Greenman struct rusage *ru; 3748a129caeSDavid Greenman struct vmspace *vm; 3758a129caeSDavid Greenman 3768843cc35SSøren Schmidt if (curproc != NULL && CLKF_USERMODE(frame)) { 377f5e9e8ecSBruce Evans p = curproc; 378df8bae1dSRodney W. Grimes if (p->p_flag & P_PROFIL) 379df8bae1dSRodney W. Grimes addupc_intr(p, CLKF_PC(frame), 1); 380eae8fc2cSSteve Passe #if defined(SMP) && defined(BETTER_CLOCK) 381eae8fc2cSSteve Passe if (stathz != 0) 382eae8fc2cSSteve Passe forward_statclock(pscnt); 383eae8fc2cSSteve Passe #endif 384df8bae1dSRodney W. Grimes if (--pscnt > 0) 385df8bae1dSRodney W. Grimes return; 386df8bae1dSRodney W. Grimes /* 387df8bae1dSRodney W. Grimes * Came from user mode; CPU was in user state. 388df8bae1dSRodney W. Grimes * If this process is being profiled record the tick. 389df8bae1dSRodney W. Grimes */ 390df8bae1dSRodney W. Grimes p->p_uticks++; 391df8bae1dSRodney W. Grimes if (p->p_nice > NZERO) 392df8bae1dSRodney W. Grimes cp_time[CP_NICE]++; 393df8bae1dSRodney W. Grimes else 394df8bae1dSRodney W. Grimes cp_time[CP_USER]++; 395df8bae1dSRodney W. Grimes } else { 396df8bae1dSRodney W. Grimes #ifdef GPROF 397df8bae1dSRodney W. Grimes /* 398df8bae1dSRodney W. Grimes * Kernel statistics are just like addupc_intr, only easier. 399df8bae1dSRodney W. Grimes */ 400df8bae1dSRodney W. Grimes g = &_gmonparam; 401df8bae1dSRodney W. Grimes if (g->state == GMON_PROF_ON) { 402df8bae1dSRodney W. Grimes i = CLKF_PC(frame) - g->lowpc; 403df8bae1dSRodney W. Grimes if (i < g->textsize) { 404df8bae1dSRodney W. Grimes i /= HISTFRACTION * sizeof(*g->kcount); 405df8bae1dSRodney W. Grimes g->kcount[i]++; 406df8bae1dSRodney W. Grimes } 407df8bae1dSRodney W. Grimes } 408df8bae1dSRodney W. Grimes #endif 409eae8fc2cSSteve Passe #if defined(SMP) && defined(BETTER_CLOCK) 410eae8fc2cSSteve Passe if (stathz != 0) 411eae8fc2cSSteve Passe forward_statclock(pscnt); 412eae8fc2cSSteve Passe #endif 413df8bae1dSRodney W. Grimes if (--pscnt > 0) 414df8bae1dSRodney W. Grimes return; 415df8bae1dSRodney W. Grimes /* 416df8bae1dSRodney W. Grimes * Came from kernel mode, so we were: 417df8bae1dSRodney W. Grimes * - handling an interrupt, 418df8bae1dSRodney W. Grimes * - doing syscall or trap work on behalf of the current 419df8bae1dSRodney W. Grimes * user process, or 420df8bae1dSRodney W. Grimes * - spinning in the idle loop. 421df8bae1dSRodney W. Grimes * Whichever it is, charge the time as appropriate. 422df8bae1dSRodney W. Grimes * Note that we charge interrupts to the current process, 423df8bae1dSRodney W. Grimes * regardless of whether they are ``for'' that process, 424df8bae1dSRodney W. Grimes * so that we know how much of its real time was spent 425df8bae1dSRodney W. Grimes * in ``non-process'' (i.e., interrupt) work. 426df8bae1dSRodney W. Grimes */ 427f5e9e8ecSBruce Evans p = curproc; 428df8bae1dSRodney W. Grimes if (CLKF_INTR(frame)) { 429df8bae1dSRodney W. Grimes if (p != NULL) 430df8bae1dSRodney W. Grimes p->p_iticks++; 431df8bae1dSRodney W. Grimes cp_time[CP_INTR]++; 432b672aa4bSBruce Evans } else if (p != NULL) { 433df8bae1dSRodney W. Grimes p->p_sticks++; 434df8bae1dSRodney W. Grimes cp_time[CP_SYS]++; 435df8bae1dSRodney W. Grimes } else 436df8bae1dSRodney W. Grimes cp_time[CP_IDLE]++; 437df8bae1dSRodney W. Grimes } 438df8bae1dSRodney W. Grimes pscnt = psdiv; 439df8bae1dSRodney W. Grimes 440df8bae1dSRodney W. Grimes /* 441df8bae1dSRodney W. Grimes * We maintain statistics shown by user-level statistics 4427ea97031SJustin T. Gibbs * programs: the amount of time in each cpu state. 443df8bae1dSRodney W. Grimes */ 444df8bae1dSRodney W. Grimes 445df8bae1dSRodney W. Grimes /* 446df8bae1dSRodney W. Grimes * We adjust the priority of the current process. The priority of 447df8bae1dSRodney W. Grimes * a process gets worse as it accumulates CPU time. The cpu usage 448df8bae1dSRodney W. Grimes * estimator (p_estcpu) is increased here. The formula for computing 449df8bae1dSRodney W. Grimes * priorities (in kern_synch.c) will compute a different value each 450df8bae1dSRodney W. Grimes * time p_estcpu increases by 4. The cpu usage estimator ramps up 451df8bae1dSRodney W. Grimes * quite quickly when the process is running (linearly), and decays 452df8bae1dSRodney W. Grimes * away exponentially, at a rate which is proportionally slower when 453df8bae1dSRodney W. Grimes * the system is busy. The basic principal is that the system will 454df8bae1dSRodney W. Grimes * 90% forget that the process used a lot of CPU time in 5 * loadav 455df8bae1dSRodney W. Grimes * seconds. This causes the system to favor processes which haven't 456df8bae1dSRodney W. Grimes * run much recently, and to round-robin among other processes. 457df8bae1dSRodney W. Grimes */ 458df8bae1dSRodney W. Grimes if (p != NULL) { 459df8bae1dSRodney W. Grimes p->p_cpticks++; 460df8bae1dSRodney W. Grimes if (++p->p_estcpu == 0) 461df8bae1dSRodney W. Grimes p->p_estcpu--; 462df8bae1dSRodney W. Grimes if ((p->p_estcpu & 3) == 0) { 463df8bae1dSRodney W. Grimes resetpriority(p); 464df8bae1dSRodney W. Grimes if (p->p_priority >= PUSER) 465df8bae1dSRodney W. Grimes p->p_priority = p->p_usrpri; 466df8bae1dSRodney W. Grimes } 467f5e9e8ecSBruce Evans 468f5e9e8ecSBruce Evans /* Update resource usage integrals and maximums. */ 469f5e9e8ecSBruce Evans if ((pstats = p->p_stats) != NULL && 470f5e9e8ecSBruce Evans (ru = &pstats->p_ru) != NULL && 471f5e9e8ecSBruce Evans (vm = p->p_vmspace) != NULL) { 4721c6d46f9SLuoqi Chen ru->ru_ixrss += pgtok(vm->vm_tsize); 4731c6d46f9SLuoqi Chen ru->ru_idrss += pgtok(vm->vm_dsize); 4741c6d46f9SLuoqi Chen ru->ru_isrss += pgtok(vm->vm_ssize); 4751c6d46f9SLuoqi Chen rss = pgtok(vmspace_resident_count(vm)); 476f5e9e8ecSBruce Evans if (ru->ru_maxrss < rss) 477f5e9e8ecSBruce Evans ru->ru_maxrss = rss; 478f5e9e8ecSBruce Evans } 479df8bae1dSRodney W. Grimes } 480df8bae1dSRodney W. Grimes } 481df8bae1dSRodney W. Grimes 482df8bae1dSRodney W. Grimes /* 483df8bae1dSRodney W. Grimes * Return information about system clocks. 484df8bae1dSRodney W. Grimes */ 485787d58f2SPoul-Henning Kamp static int 486787d58f2SPoul-Henning Kamp sysctl_kern_clockrate SYSCTL_HANDLER_ARGS 487df8bae1dSRodney W. Grimes { 488df8bae1dSRodney W. Grimes struct clockinfo clkinfo; 489df8bae1dSRodney W. Grimes /* 490df8bae1dSRodney W. Grimes * Construct clockinfo structure. 491df8bae1dSRodney W. Grimes */ 492df8bae1dSRodney W. Grimes clkinfo.hz = hz; 493df8bae1dSRodney W. Grimes clkinfo.tick = tick; 4945faa3121SJohn Hay clkinfo.tickadj = tickadj; 495df8bae1dSRodney W. Grimes clkinfo.profhz = profhz; 496df8bae1dSRodney W. Grimes clkinfo.stathz = stathz ? stathz : hz; 497ae0eb976SPoul-Henning Kamp return (sysctl_handle_opaque(oidp, &clkinfo, sizeof clkinfo, req)); 498df8bae1dSRodney W. Grimes } 4993f31c649SGarrett Wollman 500946bb7a2SPoul-Henning Kamp SYSCTL_PROC(_kern, KERN_CLOCKRATE, clockrate, CTLTYPE_STRUCT|CTLFLAG_RD, 50165d0bc13SPoul-Henning Kamp 0, 0, sysctl_kern_clockrate, "S,clockinfo",""); 502787d58f2SPoul-Henning Kamp 503e796e00dSPoul-Henning Kamp static __inline unsigned 504a58f0f8eSPoul-Henning Kamp tco_delta(struct timecounter *tc) 505e796e00dSPoul-Henning Kamp { 506e796e00dSPoul-Henning Kamp 507a58f0f8eSPoul-Henning Kamp return ((tc->tc_get_timecount(tc) - tc->tc_offset_count) & 508a58f0f8eSPoul-Henning Kamp tc->tc_counter_mask); 509e796e00dSPoul-Henning Kamp } 510a0502b19SPoul-Henning Kamp 511a0502b19SPoul-Henning Kamp /* 51232c20357SPoul-Henning Kamp * We have eight functions for looking at the clock, four for 51332c20357SPoul-Henning Kamp * microseconds and four for nanoseconds. For each there is fast 51432c20357SPoul-Henning Kamp * but less precise version "get{nano|micro}[up]time" which will 51532c20357SPoul-Henning Kamp * return a time which is up to 1/HZ previous to the call, whereas 51632c20357SPoul-Henning Kamp * the raw version "{nano|micro}[up]time" will return a timestamp 51732c20357SPoul-Henning Kamp * which is as precise as possible. The "up" variants return the 51832c20357SPoul-Henning Kamp * time relative to system boot, these are well suited for time 51932c20357SPoul-Henning Kamp * interval measurements. 520a0502b19SPoul-Henning Kamp */ 521a0502b19SPoul-Henning Kamp 522a0502b19SPoul-Henning Kamp void 523a0502b19SPoul-Henning Kamp getmicrotime(struct timeval *tvp) 524a0502b19SPoul-Henning Kamp { 525a0502b19SPoul-Henning Kamp struct timecounter *tc; 526a0502b19SPoul-Henning Kamp 527510eb5b9SPoul-Henning Kamp if (!tco_method) { 528a0502b19SPoul-Henning Kamp tc = timecounter; 529a58f0f8eSPoul-Henning Kamp *tvp = tc->tc_microtime; 530510eb5b9SPoul-Henning Kamp } else { 531510eb5b9SPoul-Henning Kamp microtime(tvp); 532510eb5b9SPoul-Henning Kamp } 53300af9731SPoul-Henning Kamp } 53400af9731SPoul-Henning Kamp 53500af9731SPoul-Henning Kamp void 53600af9731SPoul-Henning Kamp getnanotime(struct timespec *tsp) 53700af9731SPoul-Henning Kamp { 53800af9731SPoul-Henning Kamp struct timecounter *tc; 53900af9731SPoul-Henning Kamp 540510eb5b9SPoul-Henning Kamp if (!tco_method) { 54100af9731SPoul-Henning Kamp tc = timecounter; 542a58f0f8eSPoul-Henning Kamp *tsp = tc->tc_nanotime; 543510eb5b9SPoul-Henning Kamp } else { 544510eb5b9SPoul-Henning Kamp nanotime(tsp); 545510eb5b9SPoul-Henning Kamp } 54600af9731SPoul-Henning Kamp } 54700af9731SPoul-Henning Kamp 54800af9731SPoul-Henning Kamp void 54900af9731SPoul-Henning Kamp microtime(struct timeval *tv) 55000af9731SPoul-Henning Kamp { 55100af9731SPoul-Henning Kamp struct timecounter *tc; 55200af9731SPoul-Henning Kamp 5537ac9503bSJohn Polstra tc = timecounter; 554a58f0f8eSPoul-Henning Kamp tv->tv_sec = tc->tc_offset_sec; 555a58f0f8eSPoul-Henning Kamp tv->tv_usec = tc->tc_offset_micro; 556a58f0f8eSPoul-Henning Kamp tv->tv_usec += ((u_int64_t)tco_delta(tc) * tc->tc_scale_micro) >> 32; 55700af9731SPoul-Henning Kamp tv->tv_usec += boottime.tv_usec; 55800af9731SPoul-Henning Kamp tv->tv_sec += boottime.tv_sec; 55991ad39c6SPoul-Henning Kamp while (tv->tv_usec >= 1000000) { 56000af9731SPoul-Henning Kamp tv->tv_usec -= 1000000; 56100af9731SPoul-Henning Kamp tv->tv_sec++; 56200af9731SPoul-Henning Kamp } 56300af9731SPoul-Henning Kamp } 56400af9731SPoul-Henning Kamp 56500af9731SPoul-Henning Kamp void 56648115288SPoul-Henning Kamp nanotime(struct timespec *ts) 56700af9731SPoul-Henning Kamp { 568579f4456SPoul-Henning Kamp unsigned count; 56900af9731SPoul-Henning Kamp u_int64_t delta; 57000af9731SPoul-Henning Kamp struct timecounter *tc; 57100af9731SPoul-Henning Kamp 5727ac9503bSJohn Polstra tc = timecounter; 573a58f0f8eSPoul-Henning Kamp ts->tv_sec = tc->tc_offset_sec; 574a58f0f8eSPoul-Henning Kamp count = tco_delta(tc); 575a58f0f8eSPoul-Henning Kamp delta = tc->tc_offset_nano; 576a58f0f8eSPoul-Henning Kamp delta += ((u_int64_t)count * tc->tc_scale_nano_f); 57700af9731SPoul-Henning Kamp delta >>= 32; 578a58f0f8eSPoul-Henning Kamp delta += ((u_int64_t)count * tc->tc_scale_nano_i); 57900af9731SPoul-Henning Kamp delta += boottime.tv_usec * 1000; 58048115288SPoul-Henning Kamp ts->tv_sec += boottime.tv_sec; 58191ad39c6SPoul-Henning Kamp while (delta >= 1000000000) { 58200af9731SPoul-Henning Kamp delta -= 1000000000; 58348115288SPoul-Henning Kamp ts->tv_sec++; 58400af9731SPoul-Henning Kamp } 58548115288SPoul-Henning Kamp ts->tv_nsec = delta; 58648115288SPoul-Henning Kamp } 58748115288SPoul-Henning Kamp 58848115288SPoul-Henning Kamp void 589c21410e1SPoul-Henning Kamp getmicrouptime(struct timeval *tvp) 59000af9731SPoul-Henning Kamp { 59100af9731SPoul-Henning Kamp struct timecounter *tc; 59200af9731SPoul-Henning Kamp 593510eb5b9SPoul-Henning Kamp if (!tco_method) { 59400af9731SPoul-Henning Kamp tc = timecounter; 595a58f0f8eSPoul-Henning Kamp tvp->tv_sec = tc->tc_offset_sec; 596a58f0f8eSPoul-Henning Kamp tvp->tv_usec = tc->tc_offset_micro; 597510eb5b9SPoul-Henning Kamp } else { 598510eb5b9SPoul-Henning Kamp microuptime(tvp); 599510eb5b9SPoul-Henning Kamp } 600a0502b19SPoul-Henning Kamp } 601a0502b19SPoul-Henning Kamp 602a0502b19SPoul-Henning Kamp void 603c21410e1SPoul-Henning Kamp getnanouptime(struct timespec *tsp) 604a0502b19SPoul-Henning Kamp { 605a0502b19SPoul-Henning Kamp struct timecounter *tc; 606a0502b19SPoul-Henning Kamp 607510eb5b9SPoul-Henning Kamp if (!tco_method) { 608a0502b19SPoul-Henning Kamp tc = timecounter; 609a58f0f8eSPoul-Henning Kamp tsp->tv_sec = tc->tc_offset_sec; 610a58f0f8eSPoul-Henning Kamp tsp->tv_nsec = tc->tc_offset_nano >> 32; 611510eb5b9SPoul-Henning Kamp } else { 612510eb5b9SPoul-Henning Kamp nanouptime(tsp); 613510eb5b9SPoul-Henning Kamp } 614a0502b19SPoul-Henning Kamp } 615a0502b19SPoul-Henning Kamp 616c7c9a816SPoul-Henning Kamp void 617c21410e1SPoul-Henning Kamp microuptime(struct timeval *tv) 618c7c9a816SPoul-Henning Kamp { 6197ec73f64SPoul-Henning Kamp struct timecounter *tc; 6207ec73f64SPoul-Henning Kamp 6217ac9503bSJohn Polstra tc = timecounter; 622a58f0f8eSPoul-Henning Kamp tv->tv_sec = tc->tc_offset_sec; 623a58f0f8eSPoul-Henning Kamp tv->tv_usec = tc->tc_offset_micro; 624a58f0f8eSPoul-Henning Kamp tv->tv_usec += ((u_int64_t)tco_delta(tc) * tc->tc_scale_micro) >> 32; 6257ec73f64SPoul-Henning Kamp if (tv->tv_usec >= 1000000) { 6267ec73f64SPoul-Henning Kamp tv->tv_usec -= 1000000; 6277ec73f64SPoul-Henning Kamp tv->tv_sec++; 628c7c9a816SPoul-Henning Kamp } 6297ec73f64SPoul-Henning Kamp } 6307ec73f64SPoul-Henning Kamp 6317ec73f64SPoul-Henning Kamp void 632c2906d55SPoul-Henning Kamp nanouptime(struct timespec *ts) 6337ec73f64SPoul-Henning Kamp { 634e796e00dSPoul-Henning Kamp unsigned count; 6357ec73f64SPoul-Henning Kamp u_int64_t delta; 6367ec73f64SPoul-Henning Kamp struct timecounter *tc; 6377ec73f64SPoul-Henning Kamp 6387ac9503bSJohn Polstra tc = timecounter; 639c2906d55SPoul-Henning Kamp ts->tv_sec = tc->tc_offset_sec; 640a58f0f8eSPoul-Henning Kamp count = tco_delta(tc); 641a58f0f8eSPoul-Henning Kamp delta = tc->tc_offset_nano; 642a58f0f8eSPoul-Henning Kamp delta += ((u_int64_t)count * tc->tc_scale_nano_f); 6437ec73f64SPoul-Henning Kamp delta >>= 32; 644a58f0f8eSPoul-Henning Kamp delta += ((u_int64_t)count * tc->tc_scale_nano_i); 6457ec73f64SPoul-Henning Kamp if (delta >= 1000000000) { 6467ec73f64SPoul-Henning Kamp delta -= 1000000000; 647c2906d55SPoul-Henning Kamp ts->tv_sec++; 6487ec73f64SPoul-Henning Kamp } 649c2906d55SPoul-Henning Kamp ts->tv_nsec = delta; 6507ec73f64SPoul-Henning Kamp } 6517ec73f64SPoul-Henning Kamp 6527ec73f64SPoul-Henning Kamp static void 6537ec73f64SPoul-Henning Kamp tco_setscales(struct timecounter *tc) 6547ec73f64SPoul-Henning Kamp { 6557ec73f64SPoul-Henning Kamp u_int64_t scale; 6567ec73f64SPoul-Henning Kamp 6577ec73f64SPoul-Henning Kamp scale = 1000000000LL << 32; 658c68996e2SPoul-Henning Kamp scale += tc->tc_adjustment; 6590bb2226aSPoul-Henning Kamp scale /= tc->tc_tweak->tc_frequency; 660a58f0f8eSPoul-Henning Kamp tc->tc_scale_micro = scale / 1000; 661a58f0f8eSPoul-Henning Kamp tc->tc_scale_nano_f = scale & 0xffffffff; 662a58f0f8eSPoul-Henning Kamp tc->tc_scale_nano_i = scale >> 32; 6637ec73f64SPoul-Henning Kamp } 6647ec73f64SPoul-Henning Kamp 6657ec73f64SPoul-Henning Kamp void 6660bb2226aSPoul-Henning Kamp update_timecounter(struct timecounter *tc) 6670bb2226aSPoul-Henning Kamp { 6680bb2226aSPoul-Henning Kamp tco_setscales(tc); 6690bb2226aSPoul-Henning Kamp } 6700bb2226aSPoul-Henning Kamp 6710bb2226aSPoul-Henning Kamp void 6727ec73f64SPoul-Henning Kamp init_timecounter(struct timecounter *tc) 6737ec73f64SPoul-Henning Kamp { 674f5ef029eSPoul-Henning Kamp struct timespec ts1; 6753bac064fSPoul-Henning Kamp struct timecounter *t1, *t2, *t3; 6767ec73f64SPoul-Henning Kamp int i; 6777ec73f64SPoul-Henning Kamp 678a58f0f8eSPoul-Henning Kamp tc->tc_adjustment = 0; 6790bb2226aSPoul-Henning Kamp tc->tc_tweak = tc; 6807ec73f64SPoul-Henning Kamp tco_setscales(tc); 681a58f0f8eSPoul-Henning Kamp tc->tc_offset_count = tc->tc_get_timecount(tc); 6826b6ef746SBruce Evans if (timecounter == &dummy_timecounter) 6836b6ef746SBruce Evans tc->tc_avail = tc; 6846b6ef746SBruce Evans else { 6856b6ef746SBruce Evans tc->tc_avail = timecounter->tc_tweak->tc_avail; 6866b6ef746SBruce Evans timecounter->tc_tweak->tc_avail = tc; 6876b6ef746SBruce Evans } 6883bac064fSPoul-Henning Kamp MALLOC(t1, struct timecounter *, sizeof *t1, M_TIMECOUNTER, M_WAITOK); 6896b6ef746SBruce Evans tc->tc_other = t1; 6903bac064fSPoul-Henning Kamp *t1 = *tc; 6913bac064fSPoul-Henning Kamp t2 = t1; 6923bac064fSPoul-Henning Kamp for (i = 1; i < NTIMECOUNTER; i++) { 6933bac064fSPoul-Henning Kamp MALLOC(t3, struct timecounter *, sizeof *t3, 6943bac064fSPoul-Henning Kamp M_TIMECOUNTER, M_WAITOK); 6953bac064fSPoul-Henning Kamp *t3 = *tc; 6963bac064fSPoul-Henning Kamp t3->tc_other = t2; 6973bac064fSPoul-Henning Kamp t2 = t3; 6983bac064fSPoul-Henning Kamp } 6993bac064fSPoul-Henning Kamp t1->tc_other = t3; 7003bac064fSPoul-Henning Kamp tc = t1; 7017ec73f64SPoul-Henning Kamp 7023bac064fSPoul-Henning Kamp printf("Timecounter \"%s\" frequency %lu Hz\n", 7033bac064fSPoul-Henning Kamp tc->tc_name, (u_long)tc->tc_frequency); 7047ec73f64SPoul-Henning Kamp 7057ec73f64SPoul-Henning Kamp /* XXX: For now always start using the counter. */ 706a58f0f8eSPoul-Henning Kamp tc->tc_offset_count = tc->tc_get_timecount(tc); 7076ca4ca24SPoul-Henning Kamp nanouptime(&ts1); 708a58f0f8eSPoul-Henning Kamp tc->tc_offset_nano = (u_int64_t)ts1.tv_nsec << 32; 709a58f0f8eSPoul-Henning Kamp tc->tc_offset_micro = ts1.tv_nsec / 1000; 710a58f0f8eSPoul-Henning Kamp tc->tc_offset_sec = ts1.tv_sec; 7117ec73f64SPoul-Henning Kamp timecounter = tc; 7127ec73f64SPoul-Henning Kamp } 7137ec73f64SPoul-Henning Kamp 7147ec73f64SPoul-Henning Kamp void 7157ec73f64SPoul-Henning Kamp set_timecounter(struct timespec *ts) 7167ec73f64SPoul-Henning Kamp { 71700af9731SPoul-Henning Kamp struct timespec ts2; 7187ec73f64SPoul-Henning Kamp 719c21410e1SPoul-Henning Kamp nanouptime(&ts2); 72000af9731SPoul-Henning Kamp boottime.tv_sec = ts->tv_sec - ts2.tv_sec; 72100af9731SPoul-Henning Kamp boottime.tv_usec = (ts->tv_nsec - ts2.tv_nsec) / 1000; 72200af9731SPoul-Henning Kamp if (boottime.tv_usec < 0) { 72300af9731SPoul-Henning Kamp boottime.tv_usec += 1000000; 72400af9731SPoul-Henning Kamp boottime.tv_sec--; 72500af9731SPoul-Henning Kamp } 72600af9731SPoul-Henning Kamp /* fiddle all the little crinkly bits around the fiords... */ 727c2906d55SPoul-Henning Kamp tco_forward(1); 7287ec73f64SPoul-Henning Kamp } 7297ec73f64SPoul-Henning Kamp 7306b6ef746SBruce Evans static void 731b05dcf3cSPoul-Henning Kamp switch_timecounter(struct timecounter *newtc) 732b05dcf3cSPoul-Henning Kamp { 733b05dcf3cSPoul-Henning Kamp int s; 734b05dcf3cSPoul-Henning Kamp struct timecounter *tc; 735b05dcf3cSPoul-Henning Kamp struct timespec ts; 736b05dcf3cSPoul-Henning Kamp 737b05dcf3cSPoul-Henning Kamp s = splclock(); 738b05dcf3cSPoul-Henning Kamp tc = timecounter; 7396b6ef746SBruce Evans if (newtc->tc_tweak == tc->tc_tweak) { 740b05dcf3cSPoul-Henning Kamp splx(s); 741b05dcf3cSPoul-Henning Kamp return; 742b05dcf3cSPoul-Henning Kamp } 7436b6ef746SBruce Evans newtc = newtc->tc_tweak->tc_other; 7446ca4ca24SPoul-Henning Kamp nanouptime(&ts); 745a58f0f8eSPoul-Henning Kamp newtc->tc_offset_sec = ts.tv_sec; 746a58f0f8eSPoul-Henning Kamp newtc->tc_offset_nano = (u_int64_t)ts.tv_nsec << 32; 747a58f0f8eSPoul-Henning Kamp newtc->tc_offset_micro = ts.tv_nsec / 1000; 748a58f0f8eSPoul-Henning Kamp newtc->tc_offset_count = newtc->tc_get_timecount(newtc); 7496b6ef746SBruce Evans tco_setscales(newtc); 750b05dcf3cSPoul-Henning Kamp timecounter = newtc; 751b05dcf3cSPoul-Henning Kamp splx(s); 752b05dcf3cSPoul-Henning Kamp } 753b05dcf3cSPoul-Henning Kamp 7547ec73f64SPoul-Henning Kamp static struct timecounter * 755b05dcf3cSPoul-Henning Kamp sync_other_counter(void) 7567ec73f64SPoul-Henning Kamp { 7570edd53d2SPoul-Henning Kamp struct timecounter *tc, *tcn, *tco; 758579f4456SPoul-Henning Kamp unsigned delta; 7597ec73f64SPoul-Henning Kamp 7600edd53d2SPoul-Henning Kamp tco = timecounter; 7610edd53d2SPoul-Henning Kamp tc = tco->tc_other; 7620edd53d2SPoul-Henning Kamp tcn = tc->tc_other; 7630edd53d2SPoul-Henning Kamp *tc = *tco; 7640edd53d2SPoul-Henning Kamp tc->tc_other = tcn; 765a58f0f8eSPoul-Henning Kamp delta = tco_delta(tc); 766a58f0f8eSPoul-Henning Kamp tc->tc_offset_count += delta; 767a58f0f8eSPoul-Henning Kamp tc->tc_offset_count &= tc->tc_counter_mask; 768a58f0f8eSPoul-Henning Kamp tc->tc_offset_nano += (u_int64_t)delta * tc->tc_scale_nano_f; 769a58f0f8eSPoul-Henning Kamp tc->tc_offset_nano += (u_int64_t)delta * tc->tc_scale_nano_i << 32; 7707ec73f64SPoul-Henning Kamp return (tc); 7717ec73f64SPoul-Henning Kamp } 7727ec73f64SPoul-Henning Kamp 7737ec73f64SPoul-Henning Kamp static void 774c2906d55SPoul-Henning Kamp tco_forward(int force) 7757ec73f64SPoul-Henning Kamp { 77652f8e5d6SPoul-Henning Kamp struct timecounter *tc, *tco; 7777ec73f64SPoul-Henning Kamp 77852f8e5d6SPoul-Henning Kamp tco = timecounter; 779b05dcf3cSPoul-Henning Kamp tc = sync_other_counter(); 7800edd53d2SPoul-Henning Kamp /* 7810edd53d2SPoul-Henning Kamp * We may be inducing a tiny error here, the tc_poll_pps() may 7820edd53d2SPoul-Henning Kamp * process a latched count which happens after the tco_delta() 7830edd53d2SPoul-Henning Kamp * in sync_other_counter(), which would extend the previous 7840edd53d2SPoul-Henning Kamp * counters parameters into the domain of this new one. 7850edd53d2SPoul-Henning Kamp * Since the timewindow is very small for this, the error is 7860edd53d2SPoul-Henning Kamp * going to be only a few weenieseconds (as Dave Mills would 7870edd53d2SPoul-Henning Kamp * say), so lets just not talk more about it, OK ? 7880edd53d2SPoul-Henning Kamp */ 78952f8e5d6SPoul-Henning Kamp if (tco->tc_poll_pps) 79052f8e5d6SPoul-Henning Kamp tco->tc_poll_pps(tco); 791b05dcf3cSPoul-Henning Kamp if (timedelta != 0) { 792a58f0f8eSPoul-Henning Kamp tc->tc_offset_nano += (u_int64_t)(tickdelta * 1000) << 32; 7937ec73f64SPoul-Henning Kamp timedelta -= tickdelta; 794c2906d55SPoul-Henning Kamp force++; 7957ec73f64SPoul-Henning Kamp } 796b05dcf3cSPoul-Henning Kamp 797a58f0f8eSPoul-Henning Kamp while (tc->tc_offset_nano >= 1000000000ULL << 32) { 798a58f0f8eSPoul-Henning Kamp tc->tc_offset_nano -= 1000000000ULL << 32; 799a58f0f8eSPoul-Henning Kamp tc->tc_offset_sec++; 8007ec73f64SPoul-Henning Kamp ntp_update_second(tc); /* XXX only needed if xntpd runs */ 8017ec73f64SPoul-Henning Kamp tco_setscales(tc); 802c2906d55SPoul-Henning Kamp force++; 8037ec73f64SPoul-Henning Kamp } 804b05dcf3cSPoul-Henning Kamp 805510eb5b9SPoul-Henning Kamp if (tco_method && !force) 806c2906d55SPoul-Henning Kamp return; 807c2906d55SPoul-Henning Kamp 808a58f0f8eSPoul-Henning Kamp tc->tc_offset_micro = (tc->tc_offset_nano / 1000) >> 32; 809b05dcf3cSPoul-Henning Kamp 81000af9731SPoul-Henning Kamp /* Figure out the wall-clock time */ 811a58f0f8eSPoul-Henning Kamp tc->tc_nanotime.tv_sec = tc->tc_offset_sec + boottime.tv_sec; 812a58f0f8eSPoul-Henning Kamp tc->tc_nanotime.tv_nsec = 813a58f0f8eSPoul-Henning Kamp (tc->tc_offset_nano >> 32) + boottime.tv_usec * 1000; 814a58f0f8eSPoul-Henning Kamp tc->tc_microtime.tv_usec = tc->tc_offset_micro + boottime.tv_usec; 815a58f0f8eSPoul-Henning Kamp if (tc->tc_nanotime.tv_nsec >= 1000000000) { 816a58f0f8eSPoul-Henning Kamp tc->tc_nanotime.tv_nsec -= 1000000000; 817a58f0f8eSPoul-Henning Kamp tc->tc_microtime.tv_usec -= 1000000; 818a58f0f8eSPoul-Henning Kamp tc->tc_nanotime.tv_sec++; 81900af9731SPoul-Henning Kamp } 820a58f0f8eSPoul-Henning Kamp time_second = tc->tc_microtime.tv_sec = tc->tc_nanotime.tv_sec; 82100af9731SPoul-Henning Kamp 8227ec73f64SPoul-Henning Kamp timecounter = tc; 8237ec73f64SPoul-Henning Kamp } 8247ec73f64SPoul-Henning Kamp 8257ec73f64SPoul-Henning Kamp SYSCTL_NODE(_kern, OID_AUTO, timecounter, CTLFLAG_RW, 0, ""); 8267ec73f64SPoul-Henning Kamp 82730f27235SPoul-Henning Kamp SYSCTL_INT(_kern_timecounter, OID_AUTO, method, CTLFLAG_RW, &tco_method, 0, 828510eb5b9SPoul-Henning Kamp "This variable determines the method used for updating timecounters. " 829510eb5b9SPoul-Henning Kamp "If the default algorithm (0) fails with \"calcru negative...\" messages " 830510eb5b9SPoul-Henning Kamp "try the alternate algorithm (1) which handles bad hardware better." 831510eb5b9SPoul-Henning Kamp 832510eb5b9SPoul-Henning Kamp ); 833510eb5b9SPoul-Henning Kamp 8346b6ef746SBruce Evans static int 8356b6ef746SBruce Evans sysctl_kern_timecounter_hardware SYSCTL_HANDLER_ARGS 8366b6ef746SBruce Evans { 8376b6ef746SBruce Evans char newname[32]; 8386b6ef746SBruce Evans struct timecounter *newtc, *tc; 8396b6ef746SBruce Evans int error; 8406b6ef746SBruce Evans 8416b6ef746SBruce Evans tc = timecounter->tc_tweak; 8426b6ef746SBruce Evans strncpy(newname, tc->tc_name, sizeof(newname)); 8436b6ef746SBruce Evans error = sysctl_handle_string(oidp, &newname[0], sizeof(newname), req); 8446b6ef746SBruce Evans if (error == 0 && req->newptr != NULL && 8456b6ef746SBruce Evans strcmp(newname, tc->tc_name) != 0) { 846a1a10fdfSBruce Evans for (newtc = tc->tc_avail; newtc != tc; 847a1a10fdfSBruce Evans newtc = newtc->tc_avail) { 8486b6ef746SBruce Evans if (strcmp(newname, newtc->tc_name) == 0) { 8496b6ef746SBruce Evans /* Warm up new timecounter. */ 8506b6ef746SBruce Evans (void)newtc->tc_get_timecount(newtc); 8516b6ef746SBruce Evans 8526b6ef746SBruce Evans switch_timecounter(newtc); 8536b6ef746SBruce Evans return (0); 8546b6ef746SBruce Evans } 8556b6ef746SBruce Evans } 8566b6ef746SBruce Evans return (EINVAL); 8576b6ef746SBruce Evans } 8586b6ef746SBruce Evans return (error); 8596b6ef746SBruce Evans } 8606b6ef746SBruce Evans 8616b6ef746SBruce Evans SYSCTL_PROC(_kern_timecounter, OID_AUTO, hardware, CTLTYPE_STRING | CTLFLAG_RW, 8626b6ef746SBruce Evans 0, 0, sysctl_kern_timecounter_hardware, "A", ""); 8636b6ef746SBruce Evans 8647ec73f64SPoul-Henning Kamp 86532c20357SPoul-Henning Kamp int 86632c20357SPoul-Henning Kamp pps_ioctl(u_long cmd, caddr_t data, struct pps_state *pps) 86732c20357SPoul-Henning Kamp { 86832c20357SPoul-Henning Kamp pps_params_t *app; 86932c20357SPoul-Henning Kamp pps_info_t *api; 87032c20357SPoul-Henning Kamp 87132c20357SPoul-Henning Kamp switch (cmd) { 87232c20357SPoul-Henning Kamp case PPS_IOC_CREATE: 87332c20357SPoul-Henning Kamp return (0); 87432c20357SPoul-Henning Kamp case PPS_IOC_DESTROY: 87532c20357SPoul-Henning Kamp return (0); 87632c20357SPoul-Henning Kamp case PPS_IOC_SETPARAMS: 87732c20357SPoul-Henning Kamp app = (pps_params_t *)data; 87832c20357SPoul-Henning Kamp if (app->mode & ~pps->ppscap) 87932c20357SPoul-Henning Kamp return (EINVAL); 88032c20357SPoul-Henning Kamp pps->ppsparam = *app; 88132c20357SPoul-Henning Kamp return (0); 88232c20357SPoul-Henning Kamp case PPS_IOC_GETPARAMS: 88332c20357SPoul-Henning Kamp app = (pps_params_t *)data; 88432c20357SPoul-Henning Kamp *app = pps->ppsparam; 88532c20357SPoul-Henning Kamp return (0); 88632c20357SPoul-Henning Kamp case PPS_IOC_GETCAP: 88732c20357SPoul-Henning Kamp *(int*)data = pps->ppscap; 88832c20357SPoul-Henning Kamp return (0); 88932c20357SPoul-Henning Kamp case PPS_IOC_FETCH: 89032c20357SPoul-Henning Kamp api = (pps_info_t *)data; 89132c20357SPoul-Henning Kamp pps->ppsinfo.current_mode = pps->ppsparam.mode; 89232c20357SPoul-Henning Kamp *api = pps->ppsinfo; 89332c20357SPoul-Henning Kamp return (0); 89432c20357SPoul-Henning Kamp case PPS_IOC_WAIT: 89532c20357SPoul-Henning Kamp return (EOPNOTSUPP); 89632c20357SPoul-Henning Kamp default: 89732c20357SPoul-Henning Kamp return (ENOTTY); 89832c20357SPoul-Henning Kamp } 89932c20357SPoul-Henning Kamp } 90032c20357SPoul-Henning Kamp 90132c20357SPoul-Henning Kamp void 90232c20357SPoul-Henning Kamp pps_init(struct pps_state *pps) 90332c20357SPoul-Henning Kamp { 90432c20357SPoul-Henning Kamp pps->ppscap |= PPS_TSFMT_TSPEC; 90532c20357SPoul-Henning Kamp if (pps->ppscap & PPS_CAPTUREASSERT) 90632c20357SPoul-Henning Kamp pps->ppscap |= PPS_OFFSETASSERT; 90732c20357SPoul-Henning Kamp if (pps->ppscap & PPS_CAPTURECLEAR) 90832c20357SPoul-Henning Kamp pps->ppscap |= PPS_OFFSETCLEAR; 90932c20357SPoul-Henning Kamp #ifdef PPS_SYNC 91032c20357SPoul-Henning Kamp if (pps->ppscap & PPS_CAPTUREASSERT) 91132c20357SPoul-Henning Kamp pps->ppscap |= PPS_HARDPPSONASSERT; 91232c20357SPoul-Henning Kamp if (pps->ppscap & PPS_CAPTURECLEAR) 91332c20357SPoul-Henning Kamp pps->ppscap |= PPS_HARDPPSONCLEAR; 91432c20357SPoul-Henning Kamp #endif 91532c20357SPoul-Henning Kamp } 91632c20357SPoul-Henning Kamp 91732c20357SPoul-Henning Kamp void 91832c20357SPoul-Henning Kamp pps_event(struct pps_state *pps, struct timecounter *tc, unsigned count, int event) 91932c20357SPoul-Henning Kamp { 92032c20357SPoul-Henning Kamp struct timespec ts, *tsp, *osp; 92132c20357SPoul-Henning Kamp u_int64_t delta; 92232c20357SPoul-Henning Kamp unsigned tcount, *pcount; 92332c20357SPoul-Henning Kamp int foff, fhard; 92432c20357SPoul-Henning Kamp pps_seq_t *pseq; 92532c20357SPoul-Henning Kamp 92632c20357SPoul-Henning Kamp /* Things would be easier with arrays... */ 92732c20357SPoul-Henning Kamp if (event == PPS_CAPTUREASSERT) { 92832c20357SPoul-Henning Kamp tsp = &pps->ppsinfo.assert_timestamp; 92932c20357SPoul-Henning Kamp osp = &pps->ppsparam.assert_offset; 93032c20357SPoul-Henning Kamp foff = pps->ppsparam.mode & PPS_OFFSETASSERT; 93132c20357SPoul-Henning Kamp fhard = pps->ppsparam.mode & PPS_HARDPPSONASSERT; 93232c20357SPoul-Henning Kamp pcount = &pps->ppscount[0]; 93332c20357SPoul-Henning Kamp pseq = &pps->ppsinfo.assert_sequence; 93432c20357SPoul-Henning Kamp } else { 93532c20357SPoul-Henning Kamp tsp = &pps->ppsinfo.clear_timestamp; 93632c20357SPoul-Henning Kamp osp = &pps->ppsparam.clear_offset; 93732c20357SPoul-Henning Kamp foff = pps->ppsparam.mode & PPS_OFFSETCLEAR; 93832c20357SPoul-Henning Kamp fhard = pps->ppsparam.mode & PPS_HARDPPSONCLEAR; 93932c20357SPoul-Henning Kamp pcount = &pps->ppscount[1]; 94032c20357SPoul-Henning Kamp pseq = &pps->ppsinfo.clear_sequence; 94132c20357SPoul-Henning Kamp } 94232c20357SPoul-Henning Kamp 94332c20357SPoul-Henning Kamp /* The timecounter changed: bail */ 94432c20357SPoul-Henning Kamp if (!pps->ppstc || 94532c20357SPoul-Henning Kamp pps->ppstc->tc_name != tc->tc_name || 94632c20357SPoul-Henning Kamp tc->tc_name != timecounter->tc_name) { 94732c20357SPoul-Henning Kamp pps->ppstc = tc; 94832c20357SPoul-Henning Kamp *pcount = count; 94932c20357SPoul-Henning Kamp return; 95032c20357SPoul-Henning Kamp } 95132c20357SPoul-Henning Kamp 95232c20357SPoul-Henning Kamp /* Nothing really happened */ 95332c20357SPoul-Henning Kamp if (*pcount == count) 95432c20357SPoul-Henning Kamp return; 95532c20357SPoul-Henning Kamp 95632c20357SPoul-Henning Kamp *pcount = count; 95732c20357SPoul-Henning Kamp 95832c20357SPoul-Henning Kamp /* Convert the count to timespec */ 95932c20357SPoul-Henning Kamp ts.tv_sec = tc->tc_offset_sec; 96032c20357SPoul-Henning Kamp tcount = count - tc->tc_offset_count; 96132c20357SPoul-Henning Kamp tcount &= tc->tc_counter_mask; 96232c20357SPoul-Henning Kamp delta = tc->tc_offset_nano; 96332c20357SPoul-Henning Kamp delta += ((u_int64_t)tcount * tc->tc_scale_nano_f); 96432c20357SPoul-Henning Kamp delta >>= 32; 96532c20357SPoul-Henning Kamp delta += ((u_int64_t)tcount * tc->tc_scale_nano_i); 96632c20357SPoul-Henning Kamp delta += boottime.tv_usec * 1000; 96732c20357SPoul-Henning Kamp ts.tv_sec += boottime.tv_sec; 96832c20357SPoul-Henning Kamp while (delta >= 1000000000) { 96932c20357SPoul-Henning Kamp delta -= 1000000000; 97032c20357SPoul-Henning Kamp ts.tv_sec++; 97132c20357SPoul-Henning Kamp } 97232c20357SPoul-Henning Kamp ts.tv_nsec = delta; 97332c20357SPoul-Henning Kamp 97432c20357SPoul-Henning Kamp (*pseq)++; 97532c20357SPoul-Henning Kamp *tsp = ts; 97632c20357SPoul-Henning Kamp 97732c20357SPoul-Henning Kamp if (foff) { 97832c20357SPoul-Henning Kamp timespecadd(tsp, osp); 97932c20357SPoul-Henning Kamp if (tsp->tv_nsec < 0) { 98032c20357SPoul-Henning Kamp tsp->tv_nsec += 1000000000; 98132c20357SPoul-Henning Kamp tsp->tv_sec -= 1; 98232c20357SPoul-Henning Kamp } 98332c20357SPoul-Henning Kamp } 98432c20357SPoul-Henning Kamp #ifdef PPS_SYNC 98532c20357SPoul-Henning Kamp if (fhard) { 98632c20357SPoul-Henning Kamp /* magic, at its best... */ 98732c20357SPoul-Henning Kamp tcount = count - pps->ppscount[2]; 98832c20357SPoul-Henning Kamp pps->ppscount[2] = count; 98932c20357SPoul-Henning Kamp tcount &= tc->tc_counter_mask; 99032c20357SPoul-Henning Kamp delta = ((u_int64_t)tcount * tc->tc_tweak->tc_scale_nano_f); 99132c20357SPoul-Henning Kamp delta >>= 32; 99232c20357SPoul-Henning Kamp delta += ((u_int64_t)tcount * tc->tc_tweak->tc_scale_nano_i); 99332c20357SPoul-Henning Kamp hardpps(tsp, delta); 99432c20357SPoul-Henning Kamp } 99532c20357SPoul-Henning Kamp #endif 99632c20357SPoul-Henning Kamp } 99732c20357SPoul-Henning Kamp 998