1df8bae1dSRodney W. Grimes /*- 2df8bae1dSRodney W. Grimes * Copyright (c) 1982, 1986, 1991, 1993 3df8bae1dSRodney W. Grimes * The Regents of the University of California. All rights reserved. 4df8bae1dSRodney W. Grimes * (c) UNIX System Laboratories, Inc. 5df8bae1dSRodney W. Grimes * All or some portions of this file are derived from material licensed 6df8bae1dSRodney W. Grimes * to the University of California by American Telephone and Telegraph 7df8bae1dSRodney W. Grimes * Co. or Unix System Laboratories, Inc. and are reproduced herein with 8df8bae1dSRodney W. Grimes * the permission of UNIX System Laboratories, Inc. 9df8bae1dSRodney W. Grimes * 10df8bae1dSRodney W. Grimes * Redistribution and use in source and binary forms, with or without 11df8bae1dSRodney W. Grimes * modification, are permitted provided that the following conditions 12df8bae1dSRodney W. Grimes * are met: 13df8bae1dSRodney W. Grimes * 1. Redistributions of source code must retain the above copyright 14df8bae1dSRodney W. Grimes * notice, this list of conditions and the following disclaimer. 15df8bae1dSRodney W. Grimes * 2. Redistributions in binary form must reproduce the above copyright 16df8bae1dSRodney W. Grimes * notice, this list of conditions and the following disclaimer in the 17df8bae1dSRodney W. Grimes * documentation and/or other materials provided with the distribution. 18df8bae1dSRodney W. Grimes * 3. All advertising materials mentioning features or use of this software 19df8bae1dSRodney W. Grimes * must display the following acknowledgement: 20df8bae1dSRodney W. Grimes * This product includes software developed by the University of 21df8bae1dSRodney W. Grimes * California, Berkeley and its contributors. 22df8bae1dSRodney W. Grimes * 4. Neither the name of the University nor the names of its contributors 23df8bae1dSRodney W. Grimes * may be used to endorse or promote products derived from this software 24df8bae1dSRodney W. Grimes * without specific prior written permission. 25df8bae1dSRodney W. Grimes * 26df8bae1dSRodney W. Grimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 27df8bae1dSRodney W. Grimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 28df8bae1dSRodney W. Grimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 29df8bae1dSRodney W. Grimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 30df8bae1dSRodney W. Grimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 31df8bae1dSRodney W. Grimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 32df8bae1dSRodney W. Grimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 33df8bae1dSRodney W. Grimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 34df8bae1dSRodney W. Grimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 35df8bae1dSRodney W. Grimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 36df8bae1dSRodney W. Grimes * SUCH DAMAGE. 37df8bae1dSRodney W. Grimes * 38df8bae1dSRodney W. Grimes * @(#)kern_clock.c 8.5 (Berkeley) 1/21/94 39c3aac50fSPeter Wemm * $FreeBSD$ 40df8bae1dSRodney W. Grimes */ 41df8bae1dSRodney W. Grimes 4232c20357SPoul-Henning Kamp #include "opt_ntp.h" 4332c20357SPoul-Henning Kamp 44df8bae1dSRodney W. Grimes #include <sys/param.h> 45df8bae1dSRodney W. Grimes #include <sys/systm.h> 46df8bae1dSRodney W. Grimes #include <sys/callout.h> 47df8bae1dSRodney W. Grimes #include <sys/kernel.h> 48f34fa851SJohn Baldwin #include <sys/lock.h> 4961d80e90SJohn Baldwin #include <sys/ktr.h> 5035e0e5b3SJohn Baldwin #include <sys/mutex.h> 51df8bae1dSRodney W. Grimes #include <sys/proc.h> 52e4625663SJeff Roberson #include <sys/resource.h> 53df8bae1dSRodney W. Grimes #include <sys/resourcevar.h> 54b43179fbSJeff Roberson #include <sys/sched.h> 55797f2d22SPoul-Henning Kamp #include <sys/signalvar.h> 566caa8a15SJohn Baldwin #include <sys/smp.h> 578a129caeSDavid Greenman #include <vm/vm.h> 58efeaf95aSDavid Greenman #include <vm/pmap.h> 59efeaf95aSDavid Greenman #include <vm/vm_map.h> 60797f2d22SPoul-Henning Kamp #include <sys/sysctl.h> 618088699fSJohn Baldwin #include <sys/bus.h> 628088699fSJohn Baldwin #include <sys/interrupt.h> 63e7fa55afSPoul-Henning Kamp #include <sys/timetc.h> 64df8bae1dSRodney W. Grimes 65df8bae1dSRodney W. Grimes #include <machine/cpu.h> 66b1037dcdSBruce Evans #include <machine/limits.h> 67df8bae1dSRodney W. Grimes 68df8bae1dSRodney W. Grimes #ifdef GPROF 69df8bae1dSRodney W. Grimes #include <sys/gmon.h> 70df8bae1dSRodney W. Grimes #endif 71df8bae1dSRodney W. Grimes 72e4fc250cSLuigi Rizzo #ifdef DEVICE_POLLING 73daccb638SLuigi Rizzo extern void init_device_poll(void); 74e4fc250cSLuigi Rizzo extern void hardclock_device_poll(void); 75e4fc250cSLuigi Rizzo #endif /* DEVICE_POLLING */ 76eae8fc2cSSteve Passe 774d77a549SAlfred Perlstein static void initclocks(void *dummy); 782b14f991SJulian Elischer SYSINIT(clocks, SI_SUB_CLOCKS, SI_ORDER_FIRST, initclocks, NULL) 792b14f991SJulian Elischer 80f23b4c91SGarrett Wollman /* Some of these don't belong here, but it's easiest to concentrate them. */ 81eae8fc2cSSteve Passe long cp_time[CPUSTATES]; 82f23b4c91SGarrett Wollman 837f112b04SRobert Watson SYSCTL_OPAQUE(_kern, OID_AUTO, cp_time, CTLFLAG_RD, &cp_time, sizeof(cp_time), 847f112b04SRobert Watson "LU", "CPU time statistics"); 857f112b04SRobert Watson 863bac064fSPoul-Henning Kamp /* 87df8bae1dSRodney W. Grimes * Clock handling routines. 88df8bae1dSRodney W. Grimes * 89b05dcf3cSPoul-Henning Kamp * This code is written to operate with two timers that run independently of 90b05dcf3cSPoul-Henning Kamp * each other. 917ec73f64SPoul-Henning Kamp * 92b05dcf3cSPoul-Henning Kamp * The main timer, running hz times per second, is used to trigger interval 93b05dcf3cSPoul-Henning Kamp * timers, timeouts and rescheduling as needed. 947ec73f64SPoul-Henning Kamp * 95b05dcf3cSPoul-Henning Kamp * The second timer handles kernel and user profiling, 96b05dcf3cSPoul-Henning Kamp * and does resource use estimation. If the second timer is programmable, 97b05dcf3cSPoul-Henning Kamp * it is randomized to avoid aliasing between the two clocks. For example, 98b05dcf3cSPoul-Henning Kamp * the randomization prevents an adversary from always giving up the cpu 99df8bae1dSRodney W. Grimes * just before its quantum expires. Otherwise, it would never accumulate 100df8bae1dSRodney W. Grimes * cpu ticks. The mean frequency of the second timer is stathz. 101b05dcf3cSPoul-Henning Kamp * 102b05dcf3cSPoul-Henning Kamp * If no second timer exists, stathz will be zero; in this case we drive 103b05dcf3cSPoul-Henning Kamp * profiling and statistics off the main clock. This WILL NOT be accurate; 104b05dcf3cSPoul-Henning Kamp * do not do it unless absolutely necessary. 105b05dcf3cSPoul-Henning Kamp * 106df8bae1dSRodney W. Grimes * The statistics clock may (or may not) be run at a higher rate while 107b05dcf3cSPoul-Henning Kamp * profiling. This profile clock runs at profhz. We require that profhz 108b05dcf3cSPoul-Henning Kamp * be an integral multiple of stathz. 109b05dcf3cSPoul-Henning Kamp * 110b05dcf3cSPoul-Henning Kamp * If the statistics clock is running fast, it must be divided by the ratio 111b05dcf3cSPoul-Henning Kamp * profhz/stathz for statistics. (For profiling, every tick counts.) 112df8bae1dSRodney W. Grimes * 1137ec73f64SPoul-Henning Kamp * Time-of-day is maintained using a "timecounter", which may or may 1147ec73f64SPoul-Henning Kamp * not be related to the hardware generating the above mentioned 1157ec73f64SPoul-Henning Kamp * interrupts. 116df8bae1dSRodney W. Grimes */ 117df8bae1dSRodney W. Grimes 118df8bae1dSRodney W. Grimes int stathz; 119df8bae1dSRodney W. Grimes int profhz; 120238dd320SJake Burkholder int profprocs; 121df8bae1dSRodney W. Grimes int ticks; 122238dd320SJake Burkholder int psratio; 123df8bae1dSRodney W. Grimes 124df8bae1dSRodney W. Grimes /* 125df8bae1dSRodney W. Grimes * Initialize clock frequencies and start both clocks running. 126df8bae1dSRodney W. Grimes */ 1272b14f991SJulian Elischer /* ARGSUSED*/ 1282b14f991SJulian Elischer static void 129d841aaa7SBruce Evans initclocks(dummy) 130d841aaa7SBruce Evans void *dummy; 131df8bae1dSRodney W. Grimes { 132df8bae1dSRodney W. Grimes register int i; 133df8bae1dSRodney W. Grimes 134df8bae1dSRodney W. Grimes /* 135df8bae1dSRodney W. Grimes * Set divisors to 1 (normal case) and let the machine-specific 136df8bae1dSRodney W. Grimes * code do its bit. 137df8bae1dSRodney W. Grimes */ 138df8bae1dSRodney W. Grimes cpu_initclocks(); 139df8bae1dSRodney W. Grimes 140e4fc250cSLuigi Rizzo #ifdef DEVICE_POLLING 141daccb638SLuigi Rizzo init_device_poll(); 142e4fc250cSLuigi Rizzo #endif 143df8bae1dSRodney W. Grimes /* 144df8bae1dSRodney W. Grimes * Compute profhz/stathz, and fix profhz if needed. 145df8bae1dSRodney W. Grimes */ 146df8bae1dSRodney W. Grimes i = stathz ? stathz : hz; 147df8bae1dSRodney W. Grimes if (profhz == 0) 148df8bae1dSRodney W. Grimes profhz = i; 149df8bae1dSRodney W. Grimes psratio = profhz / i; 150df8bae1dSRodney W. Grimes } 151df8bae1dSRodney W. Grimes 152df8bae1dSRodney W. Grimes /* 153238dd320SJake Burkholder * Each time the real-time timer fires, this function is called on all CPUs. 154238dd320SJake Burkholder * Note that hardclock() calls hardclock_process() for the boot CPU, so only 155238dd320SJake Burkholder * the other CPUs in the system need to call this function. 1566caa8a15SJohn Baldwin */ 1576caa8a15SJohn Baldwin void 158238dd320SJake Burkholder hardclock_process(frame) 159238dd320SJake Burkholder register struct clockframe *frame; 1606caa8a15SJohn Baldwin { 1616caa8a15SJohn Baldwin struct pstats *pstats; 162238dd320SJake Burkholder struct thread *td = curthread; 163b40ce416SJulian Elischer struct proc *p = td->td_proc; 1646caa8a15SJohn Baldwin 1656caa8a15SJohn Baldwin /* 1666caa8a15SJohn Baldwin * Run current process's virtual and profile time, as needed. 1676caa8a15SJohn Baldwin */ 168238dd320SJake Burkholder mtx_lock_spin_flags(&sched_lock, MTX_QUIET); 169b40ce416SJulian Elischer if (p->p_flag & P_KSES) { 170b40ce416SJulian Elischer /* XXXKSE What to do? */ 171b40ce416SJulian Elischer } else { 1726caa8a15SJohn Baldwin pstats = p->p_stats; 173238dd320SJake Burkholder if (CLKF_USERMODE(frame) && 1746caa8a15SJohn Baldwin timevalisset(&pstats->p_timer[ITIMER_VIRTUAL].it_value) && 175b40ce416SJulian Elischer itimerdecr(&pstats->p_timer[ITIMER_VIRTUAL], tick) == 0) { 176b40ce416SJulian Elischer p->p_sflag |= PS_ALRMPEND; 177b40ce416SJulian Elischer td->td_kse->ke_flags |= KEF_ASTPENDING; 178b40ce416SJulian Elischer } 1796caa8a15SJohn Baldwin if (timevalisset(&pstats->p_timer[ITIMER_PROF].it_value) && 180b40ce416SJulian Elischer itimerdecr(&pstats->p_timer[ITIMER_PROF], tick) == 0) { 181b40ce416SJulian Elischer p->p_sflag |= PS_PROFPEND; 182b40ce416SJulian Elischer td->td_kse->ke_flags |= KEF_ASTPENDING; 183b40ce416SJulian Elischer } 184b40ce416SJulian Elischer } 185238dd320SJake Burkholder mtx_unlock_spin_flags(&sched_lock, MTX_QUIET); 1866caa8a15SJohn Baldwin } 1876caa8a15SJohn Baldwin 1886caa8a15SJohn Baldwin /* 189df8bae1dSRodney W. Grimes * The real-time timer, interrupting hz times per second. 190df8bae1dSRodney W. Grimes */ 191df8bae1dSRodney W. Grimes void 192df8bae1dSRodney W. Grimes hardclock(frame) 193df8bae1dSRodney W. Grimes register struct clockframe *frame; 194df8bae1dSRodney W. Grimes { 195fa2fbc3dSJake Burkholder int need_softclock = 0; 196df8bae1dSRodney W. Grimes 197c9f4877dSJake Burkholder CTR0(KTR_CLK, "hardclock fired"); 198238dd320SJake Burkholder hardclock_process(frame); 199b05dcf3cSPoul-Henning Kamp 200e7fa55afSPoul-Henning Kamp tc_ticktock(); 201df8bae1dSRodney W. Grimes /* 202df8bae1dSRodney W. Grimes * If no separate statistics clock is available, run it from here. 2036caa8a15SJohn Baldwin * 2046caa8a15SJohn Baldwin * XXX: this only works for UP 205df8bae1dSRodney W. Grimes */ 206238dd320SJake Burkholder if (stathz == 0) { 207238dd320SJake Burkholder profclock(frame); 208df8bae1dSRodney W. Grimes statclock(frame); 209238dd320SJake Burkholder } 210df8bae1dSRodney W. Grimes 211e4fc250cSLuigi Rizzo #ifdef DEVICE_POLLING 212daccb638SLuigi Rizzo hardclock_device_poll(); /* this is very short and quick */ 213e4fc250cSLuigi Rizzo #endif /* DEVICE_POLLING */ 2143f31c649SGarrett Wollman 215b05dcf3cSPoul-Henning Kamp /* 216b05dcf3cSPoul-Henning Kamp * Process callouts at a very low cpu priority, so we don't keep the 217b05dcf3cSPoul-Henning Kamp * relatively high clock interrupt priority any longer than necessary. 218b05dcf3cSPoul-Henning Kamp */ 21921a7a9aeSJohn Baldwin mtx_lock_spin_flags(&callout_lock, MTX_QUIET); 220fa2fbc3dSJake Burkholder ticks++; 221b05dcf3cSPoul-Henning Kamp if (TAILQ_FIRST(&callwheel[ticks & callwheelmask]) != NULL) { 222fa2fbc3dSJake Burkholder need_softclock = 1; 223b05dcf3cSPoul-Henning Kamp } else if (softticks + 1 == ticks) 224b05dcf3cSPoul-Henning Kamp ++softticks; 22521a7a9aeSJohn Baldwin mtx_unlock_spin_flags(&callout_lock, MTX_QUIET); 226fa2fbc3dSJake Burkholder 227fa2fbc3dSJake Burkholder /* 228062d8ff5SJohn Baldwin * swi_sched acquires sched_lock, so we don't want to call it with 229fa2fbc3dSJake Burkholder * callout_lock held; incorrect locking order. 230fa2fbc3dSJake Burkholder */ 231fa2fbc3dSJake Burkholder if (need_softclock) 232c86b6ff5SJohn Baldwin swi_sched(softclock_ih, 0); 233ab36c067SJustin T. Gibbs } 234ab36c067SJustin T. Gibbs 235df8bae1dSRodney W. Grimes /* 236227ee8a1SPoul-Henning Kamp * Compute number of ticks in the specified amount of time. 237df8bae1dSRodney W. Grimes */ 238df8bae1dSRodney W. Grimes int 239227ee8a1SPoul-Henning Kamp tvtohz(tv) 240df8bae1dSRodney W. Grimes struct timeval *tv; 241df8bae1dSRodney W. Grimes { 2426976af69SBruce Evans register unsigned long ticks; 2436976af69SBruce Evans register long sec, usec; 244df8bae1dSRodney W. Grimes 245df8bae1dSRodney W. Grimes /* 2466976af69SBruce Evans * If the number of usecs in the whole seconds part of the time 2476976af69SBruce Evans * difference fits in a long, then the total number of usecs will 2486976af69SBruce Evans * fit in an unsigned long. Compute the total and convert it to 2496976af69SBruce Evans * ticks, rounding up and adding 1 to allow for the current tick 2506976af69SBruce Evans * to expire. Rounding also depends on unsigned long arithmetic 2516976af69SBruce Evans * to avoid overflow. 252df8bae1dSRodney W. Grimes * 2536976af69SBruce Evans * Otherwise, if the number of ticks in the whole seconds part of 2546976af69SBruce Evans * the time difference fits in a long, then convert the parts to 2556976af69SBruce Evans * ticks separately and add, using similar rounding methods and 2566976af69SBruce Evans * overflow avoidance. This method would work in the previous 2576976af69SBruce Evans * case but it is slightly slower and assumes that hz is integral. 2586976af69SBruce Evans * 2596976af69SBruce Evans * Otherwise, round the time difference down to the maximum 2606976af69SBruce Evans * representable value. 2616976af69SBruce Evans * 2626976af69SBruce Evans * If ints have 32 bits, then the maximum value for any timeout in 2636976af69SBruce Evans * 10ms ticks is 248 days. 264df8bae1dSRodney W. Grimes */ 265227ee8a1SPoul-Henning Kamp sec = tv->tv_sec; 266227ee8a1SPoul-Henning Kamp usec = tv->tv_usec; 2676976af69SBruce Evans if (usec < 0) { 2686976af69SBruce Evans sec--; 2696976af69SBruce Evans usec += 1000000; 2706976af69SBruce Evans } 2716976af69SBruce Evans if (sec < 0) { 2726976af69SBruce Evans #ifdef DIAGNOSTIC 273b05dcf3cSPoul-Henning Kamp if (usec > 0) { 2747ec73f64SPoul-Henning Kamp sec++; 2757ec73f64SPoul-Henning Kamp usec -= 1000000; 2767ec73f64SPoul-Henning Kamp } 277227ee8a1SPoul-Henning Kamp printf("tvotohz: negative time difference %ld sec %ld usec\n", 2786976af69SBruce Evans sec, usec); 2796976af69SBruce Evans #endif 2806976af69SBruce Evans ticks = 1; 2816976af69SBruce Evans } else if (sec <= LONG_MAX / 1000000) 2826976af69SBruce Evans ticks = (sec * 1000000 + (unsigned long)usec + (tick - 1)) 2836976af69SBruce Evans / tick + 1; 2846976af69SBruce Evans else if (sec <= LONG_MAX / hz) 2856976af69SBruce Evans ticks = sec * hz 2866976af69SBruce Evans + ((unsigned long)usec + (tick - 1)) / tick + 1; 2876976af69SBruce Evans else 2886976af69SBruce Evans ticks = LONG_MAX; 2896976af69SBruce Evans if (ticks > INT_MAX) 2906976af69SBruce Evans ticks = INT_MAX; 291d6116663SAlexander Langer return ((int)ticks); 292df8bae1dSRodney W. Grimes } 293df8bae1dSRodney W. Grimes 294df8bae1dSRodney W. Grimes /* 295df8bae1dSRodney W. Grimes * Start profiling on a process. 296df8bae1dSRodney W. Grimes * 297df8bae1dSRodney W. Grimes * Kernel profiling passes proc0 which never exits and hence 298df8bae1dSRodney W. Grimes * keeps the profile clock running constantly. 299df8bae1dSRodney W. Grimes */ 300df8bae1dSRodney W. Grimes void 301df8bae1dSRodney W. Grimes startprofclock(p) 302df8bae1dSRodney W. Grimes register struct proc *p; 303df8bae1dSRodney W. Grimes { 304df8bae1dSRodney W. Grimes 30501cd094cSJohn Baldwin /* 30601cd094cSJohn Baldwin * XXX; Right now sched_lock protects statclock(), but perhaps 30701cd094cSJohn Baldwin * it should be protected later on by a time_lock, which would 30801cd094cSJohn Baldwin * cover psdiv, etc. as well. 30901cd094cSJohn Baldwin */ 3109ed346baSBosko Milekic mtx_lock_spin(&sched_lock); 311a282253aSJulian Elischer if (p->p_sflag & PS_STOPPROF) { 312a282253aSJulian Elischer mtx_unlock_spin(&sched_lock); 313a282253aSJulian Elischer return; 314a282253aSJulian Elischer } 31501cd094cSJohn Baldwin if ((p->p_sflag & PS_PROFIL) == 0) { 31601cd094cSJohn Baldwin p->p_sflag |= PS_PROFIL; 317238dd320SJake Burkholder if (++profprocs == 1) 318238dd320SJake Burkholder cpu_startprofclock(); 319df8bae1dSRodney W. Grimes } 3209ed346baSBosko Milekic mtx_unlock_spin(&sched_lock); 321df8bae1dSRodney W. Grimes } 322df8bae1dSRodney W. Grimes 323df8bae1dSRodney W. Grimes /* 324df8bae1dSRodney W. Grimes * Stop profiling on a process. 325df8bae1dSRodney W. Grimes */ 326df8bae1dSRodney W. Grimes void 327df8bae1dSRodney W. Grimes stopprofclock(p) 328df8bae1dSRodney W. Grimes register struct proc *p; 329df8bae1dSRodney W. Grimes { 330df8bae1dSRodney W. Grimes 331a282253aSJulian Elischer PROC_LOCK_ASSERT(p, MA_OWNED); 332a282253aSJulian Elischer retry: 3339ed346baSBosko Milekic mtx_lock_spin(&sched_lock); 33401cd094cSJohn Baldwin if (p->p_sflag & PS_PROFIL) { 335a282253aSJulian Elischer if (p->p_profthreads) { 336a282253aSJulian Elischer p->p_sflag |= PS_STOPPROF; 337a282253aSJulian Elischer mtx_unlock_spin(&sched_lock); 338a282253aSJulian Elischer msleep(&p->p_profthreads, &p->p_mtx, PPAUSE, 339a282253aSJulian Elischer "stopprof", NULL); 340a282253aSJulian Elischer goto retry; 341a282253aSJulian Elischer } 342a282253aSJulian Elischer p->p_sflag &= ~(PS_PROFIL|PS_STOPPROF); 343238dd320SJake Burkholder if (--profprocs == 0) 344238dd320SJake Burkholder cpu_stopprofclock(); 345df8bae1dSRodney W. Grimes } 3469ed346baSBosko Milekic mtx_unlock_spin(&sched_lock); 347df8bae1dSRodney W. Grimes } 348df8bae1dSRodney W. Grimes 349df8bae1dSRodney W. Grimes /* 350238dd320SJake Burkholder * Statistics clock. Grab profile sample, and if divider reaches 0, 351238dd320SJake Burkholder * do process and kernel statistics. Most of the statistics are only 35271a62f8aSBruce Evans * used by user-level statistics programs. The main exceptions are 353238dd320SJake Burkholder * ke->ke_uticks, p->p_sticks, p->p_iticks, and p->p_estcpu. 354238dd320SJake Burkholder * This should be called by all active processors. 355df8bae1dSRodney W. Grimes */ 356df8bae1dSRodney W. Grimes void 357238dd320SJake Burkholder statclock(frame) 358238dd320SJake Burkholder register struct clockframe *frame; 359df8bae1dSRodney W. Grimes { 3608a129caeSDavid Greenman struct pstats *pstats; 3618a129caeSDavid Greenman struct rusage *ru; 3628a129caeSDavid Greenman struct vmspace *vm; 363238dd320SJake Burkholder struct thread *td; 364238dd320SJake Burkholder struct kse *ke; 365238dd320SJake Burkholder struct proc *p; 366238dd320SJake Burkholder long rss; 3678a129caeSDavid Greenman 368238dd320SJake Burkholder td = curthread; 369238dd320SJake Burkholder p = td->td_proc; 370238dd320SJake Burkholder 371238dd320SJake Burkholder mtx_lock_spin_flags(&sched_lock, MTX_QUIET); 372238dd320SJake Burkholder ke = td->td_kse; 373238dd320SJake Burkholder if (CLKF_USERMODE(frame)) { 374df8bae1dSRodney W. Grimes /* 37571a62f8aSBruce Evans * Charge the time as appropriate. 376df8bae1dSRodney W. Grimes */ 3778798d4f9SDavid Xu if (p->p_flag & P_KSES) 3786f8132a8SJulian Elischer thread_add_ticks_intr(1, 1); 379e4625663SJeff Roberson p->p_uticks++; 3806f8132a8SJulian Elischer if (ke->ke_ksegrp->kg_nice > NZERO) 381df8bae1dSRodney W. Grimes cp_time[CP_NICE]++; 382df8bae1dSRodney W. Grimes else 383df8bae1dSRodney W. Grimes cp_time[CP_USER]++; 384df8bae1dSRodney W. Grimes } else { 385df8bae1dSRodney W. Grimes /* 386df8bae1dSRodney W. Grimes * Came from kernel mode, so we were: 387df8bae1dSRodney W. Grimes * - handling an interrupt, 388df8bae1dSRodney W. Grimes * - doing syscall or trap work on behalf of the current 389df8bae1dSRodney W. Grimes * user process, or 390df8bae1dSRodney W. Grimes * - spinning in the idle loop. 391df8bae1dSRodney W. Grimes * Whichever it is, charge the time as appropriate. 392df8bae1dSRodney W. Grimes * Note that we charge interrupts to the current process, 393df8bae1dSRodney W. Grimes * regardless of whether they are ``for'' that process, 394df8bae1dSRodney W. Grimes * so that we know how much of its real time was spent 395df8bae1dSRodney W. Grimes * in ``non-process'' (i.e., interrupt) work. 396df8bae1dSRodney W. Grimes */ 397b40ce416SJulian Elischer if ((td->td_ithd != NULL) || td->td_intr_nesting_level >= 2) { 398e4625663SJeff Roberson p->p_iticks++; 399df8bae1dSRodney W. Grimes cp_time[CP_INTR]++; 4000384fff8SJason Evans } else { 4018798d4f9SDavid Xu if (p->p_flag & P_KSES) 4026f8132a8SJulian Elischer thread_add_ticks_intr(0, 1); 403e4625663SJeff Roberson td->td_sticks++; 404e4625663SJeff Roberson p->p_sticks++; 405b40ce416SJulian Elischer if (p != PCPU_GET(idlethread)->td_proc) 406df8bae1dSRodney W. Grimes cp_time[CP_SYS]++; 4070384fff8SJason Evans else 408df8bae1dSRodney W. Grimes cp_time[CP_IDLE]++; 409df8bae1dSRodney W. Grimes } 4100384fff8SJason Evans } 411df8bae1dSRodney W. Grimes 412a282253aSJulian Elischer sched_clock(td); 413f5e9e8ecSBruce Evans 414f5e9e8ecSBruce Evans /* Update resource usage integrals and maximums. */ 415f5e9e8ecSBruce Evans if ((pstats = p->p_stats) != NULL && 416f5e9e8ecSBruce Evans (ru = &pstats->p_ru) != NULL && 417f5e9e8ecSBruce Evans (vm = p->p_vmspace) != NULL) { 4181c6d46f9SLuoqi Chen ru->ru_ixrss += pgtok(vm->vm_tsize); 4191c6d46f9SLuoqi Chen ru->ru_idrss += pgtok(vm->vm_dsize); 4201c6d46f9SLuoqi Chen ru->ru_isrss += pgtok(vm->vm_ssize); 4211c6d46f9SLuoqi Chen rss = pgtok(vmspace_resident_count(vm)); 422f5e9e8ecSBruce Evans if (ru->ru_maxrss < rss) 423f5e9e8ecSBruce Evans ru->ru_maxrss = rss; 424f5e9e8ecSBruce Evans } 425238dd320SJake Burkholder mtx_unlock_spin_flags(&sched_lock, MTX_QUIET); 4266caa8a15SJohn Baldwin } 4276c567274SJohn Baldwin 4286caa8a15SJohn Baldwin void 429238dd320SJake Burkholder profclock(frame) 4306caa8a15SJohn Baldwin register struct clockframe *frame; 4316caa8a15SJohn Baldwin { 432238dd320SJake Burkholder struct thread *td; 433238dd320SJake Burkholder #ifdef GPROF 434238dd320SJake Burkholder struct gmonparam *g; 435238dd320SJake Burkholder int i; 436238dd320SJake Burkholder #endif 4376caa8a15SJohn Baldwin 438238dd320SJake Burkholder if (CLKF_USERMODE(frame)) { 439238dd320SJake Burkholder /* 440238dd320SJake Burkholder * Came from user mode; CPU was in user state. 441238dd320SJake Burkholder * If this process is being profiled, record the tick. 442a282253aSJulian Elischer * if there is no related user location yet, don't 443a282253aSJulian Elischer * bother trying to count it. 444238dd320SJake Burkholder */ 445238dd320SJake Burkholder td = curthread; 446a282253aSJulian Elischer if ((td->td_proc->p_sflag & PS_PROFIL) && 447a282253aSJulian Elischer !(td->td_flags & TDF_UPCALLING)) 448238dd320SJake Burkholder addupc_intr(td->td_kse, CLKF_PC(frame), 1); 449238dd320SJake Burkholder } 450238dd320SJake Burkholder #ifdef GPROF 451238dd320SJake Burkholder else { 452238dd320SJake Burkholder /* 453238dd320SJake Burkholder * Kernel statistics are just like addupc_intr, only easier. 454238dd320SJake Burkholder */ 455238dd320SJake Burkholder g = &_gmonparam; 456238dd320SJake Burkholder if (g->state == GMON_PROF_ON) { 457238dd320SJake Burkholder i = CLKF_PC(frame) - g->lowpc; 458238dd320SJake Burkholder if (i < g->textsize) { 459238dd320SJake Burkholder i /= HISTFRACTION * sizeof(*g->kcount); 460238dd320SJake Burkholder g->kcount[i]++; 461238dd320SJake Burkholder } 462238dd320SJake Burkholder } 463238dd320SJake Burkholder } 464238dd320SJake Burkholder #endif 465df8bae1dSRodney W. Grimes } 466df8bae1dSRodney W. Grimes 467df8bae1dSRodney W. Grimes /* 468df8bae1dSRodney W. Grimes * Return information about system clocks. 469df8bae1dSRodney W. Grimes */ 470787d58f2SPoul-Henning Kamp static int 47182d9ae4eSPoul-Henning Kamp sysctl_kern_clockrate(SYSCTL_HANDLER_ARGS) 472df8bae1dSRodney W. Grimes { 473df8bae1dSRodney W. Grimes struct clockinfo clkinfo; 474df8bae1dSRodney W. Grimes /* 475df8bae1dSRodney W. Grimes * Construct clockinfo structure. 476df8bae1dSRodney W. Grimes */ 477a9a0f15aSBruce Evans bzero(&clkinfo, sizeof(clkinfo)); 478df8bae1dSRodney W. Grimes clkinfo.hz = hz; 479df8bae1dSRodney W. Grimes clkinfo.tick = tick; 480df8bae1dSRodney W. Grimes clkinfo.profhz = profhz; 481df8bae1dSRodney W. Grimes clkinfo.stathz = stathz ? stathz : hz; 482ae0eb976SPoul-Henning Kamp return (sysctl_handle_opaque(oidp, &clkinfo, sizeof clkinfo, req)); 483df8bae1dSRodney W. Grimes } 4843f31c649SGarrett Wollman 485946bb7a2SPoul-Henning Kamp SYSCTL_PROC(_kern, KERN_CLOCKRATE, clockrate, CTLTYPE_STRUCT|CTLFLAG_RD, 486af1408e3SLuigi Rizzo 0, 0, sysctl_kern_clockrate, "S,clockinfo", 487af1408e3SLuigi Rizzo "Rate and period of various kernel clocks"); 488