kern_clock.c revision 151747
197403Sobrien/*- 297403Sobrien * Copyright (c) 1982, 1986, 1991, 1993 3132720Skan * The Regents of the University of California. All rights reserved. 497403Sobrien * (c) UNIX System Laboratories, Inc. 597403Sobrien * All or some portions of this file are derived from material licensed 697403Sobrien * to the University of California by American Telephone and Telegraph 797403Sobrien * Co. or Unix System Laboratories, Inc. and are reproduced herein with 897403Sobrien * the permission of UNIX System Laboratories, Inc. 997403Sobrien * 1097403Sobrien * Redistribution and use in source and binary forms, with or without 1197403Sobrien * modification, are permitted provided that the following conditions 1297403Sobrien * are met: 1397403Sobrien * 1. Redistributions of source code must retain the above copyright 1497403Sobrien * notice, this list of conditions and the following disclaimer. 1597403Sobrien * 2. Redistributions in binary form must reproduce the above copyright 1697403Sobrien * notice, this list of conditions and the following disclaimer in the 1797403Sobrien * documentation and/or other materials provided with the distribution. 1897403Sobrien * 4. Neither the name of the University nor the names of its contributors 1997403Sobrien * may be used to endorse or promote products derived from this software 2097403Sobrien * without specific prior written permission. 2197403Sobrien * 2297403Sobrien * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 2397403Sobrien * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2497403Sobrien * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2597403Sobrien * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 2697403Sobrien * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2797403Sobrien * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2897403Sobrien * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2997403Sobrien * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 3097403Sobrien * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 3197403Sobrien * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32132720Skan * SUCH DAMAGE. 3397403Sobrien * 3497403Sobrien * @(#)kern_clock.c 8.5 (Berkeley) 1/21/94 3597403Sobrien */ 3697403Sobrien 3797403Sobrien#include <sys/cdefs.h> 3897403Sobrien__FBSDID("$FreeBSD: head/sys/kern/kern_clock.c 151747 2005-10-27 17:22:47Z emaste $"); 3997403Sobrien 40132720Skan#include "opt_device_polling.h" 41132720Skan#include "opt_hwpmc_hooks.h" 4297403Sobrien#include "opt_ntp.h" 4397403Sobrien#include "opt_watchdog.h" 4497403Sobrien 4597403Sobrien#include <sys/param.h> 46117397Skan#include <sys/systm.h> 47117397Skan#include <sys/callout.h> 4897403Sobrien#include <sys/kdb.h> 4997403Sobrien#include <sys/kernel.h> 5097403Sobrien#include <sys/lock.h> 5197403Sobrien#include <sys/ktr.h> 5297403Sobrien#include <sys/mutex.h> 5397403Sobrien#include <sys/proc.h> 5497403Sobrien#include <sys/resource.h> 55132720Skan#include <sys/resourcevar.h> 5697403Sobrien#include <sys/sched.h> 57132720Skan#include <sys/signalvar.h> 5897403Sobrien#include <sys/smp.h> 5997403Sobrien#include <vm/vm.h> 6097403Sobrien#include <vm/pmap.h> 61132720Skan#include <vm/vm_map.h> 6297403Sobrien#include <sys/sysctl.h> 6397403Sobrien#include <sys/bus.h> 6497403Sobrien#include <sys/interrupt.h> 65132720Skan#include <sys/limits.h> 6697403Sobrien#include <sys/timetc.h> 6797403Sobrien 6897403Sobrien#include <machine/cpu.h> 69132720Skan 7097403Sobrien#ifdef GPROF 7197403Sobrien#include <sys/gmon.h> 7297403Sobrien#endif 73132720Skan 7497403Sobrien#ifdef HWPMC_HOOKS 7597403Sobrien#include <sys/pmckern.h> 7697403Sobrien#endif 77132720Skan 7897403Sobrien#ifdef DEVICE_POLLING 7997403Sobrienextern void hardclock_device_poll(void); 8097403Sobrien#endif /* DEVICE_POLLING */ 81132720Skan 8297403Sobrienstatic void initclocks(void *dummy); 8397403SobrienSYSINIT(clocks, SI_SUB_CLOCKS, SI_ORDER_FIRST, initclocks, NULL) 8497403Sobrien 8597403Sobrien/* Some of these don't belong here, but it's easiest to concentrate them. */ 86132720Skanlong cp_time[CPUSTATES]; 8797403Sobrien 88132720Skanstatic int 8997403Sobriensysctl_kern_cp_time(SYSCTL_HANDLER_ARGS) 9097403Sobrien{ 9197403Sobrien int error; 92132720Skan#ifdef SCTL_MASK32 9397403Sobrien int i; 9497403Sobrien unsigned int cp_time32[CPUSTATES]; 9597403Sobrien 96132720Skan if (req->flags & SCTL_MASK32) { 9797403Sobrien if (!req->oldptr) 9897403Sobrien return SYSCTL_OUT(req, 0, sizeof(cp_time32)); 9997403Sobrien for (i = 0; i < CPUSTATES; i++) 100132720Skan cp_time32[i] = (unsigned int)cp_time[i]; 10197403Sobrien error = SYSCTL_OUT(req, cp_time32, sizeof(cp_time32)); 10297403Sobrien } else 10397403Sobrien#endif 104132720Skan { 10597403Sobrien if (!req->oldptr) 10697403Sobrien return SYSCTL_OUT(req, 0, sizeof(cp_time)); 10797403Sobrien error = SYSCTL_OUT(req, cp_time, sizeof(cp_time)); 108132720Skan } 10997403Sobrien return error; 11097403Sobrien} 11197403Sobrien 112132720SkanSYSCTL_PROC(_kern, OID_AUTO, cp_time, CTLTYPE_LONG|CTLFLAG_RD, 11397403Sobrien 0,0, sysctl_kern_cp_time, "LU", "CPU time statistics"); 11497403Sobrien 11597403Sobrien#ifdef SW_WATCHDOG 11697403Sobrien#include <sys/watchdog.h> 117132720Skan 11897403Sobrienstatic int watchdog_ticks; 119132720Skanstatic int watchdog_enabled; 12097403Sobrienstatic void watchdog_fire(void); 12197403Sobrienstatic void watchdog_config(void *, u_int, int *); 12297403Sobrien#endif /* SW_WATCHDOG */ 123132720Skan 12497403Sobrien/* 12597403Sobrien * Clock handling routines. 12697403Sobrien * 127132720Skan * This code is written to operate with two timers that run independently of 12897403Sobrien * each other. 12997403Sobrien * 13097403Sobrien * The main timer, running hz times per second, is used to trigger interval 131132720Skan * timers, timeouts and rescheduling as needed. 13297403Sobrien * 13397403Sobrien * The second timer handles kernel and user profiling, 13497403Sobrien * and does resource use estimation. If the second timer is programmable, 135132720Skan * it is randomized to avoid aliasing between the two clocks. For example, 13697403Sobrien * the randomization prevents an adversary from always giving up the cpu 13797403Sobrien * just before its quantum expires. Otherwise, it would never accumulate 13897403Sobrien * cpu ticks. The mean frequency of the second timer is stathz. 139132720Skan * 14097403Sobrien * If no second timer exists, stathz will be zero; in this case we drive 14197403Sobrien * profiling and statistics off the main clock. This WILL NOT be accurate; 14297403Sobrien * do not do it unless absolutely necessary. 143132720Skan * 14497403Sobrien * The statistics clock may (or may not) be run at a higher rate while 14597403Sobrien * profiling. This profile clock runs at profhz. We require that profhz 14697403Sobrien * be an integral multiple of stathz. 147132720Skan * 14897403Sobrien * If the statistics clock is running fast, it must be divided by the ratio 14997403Sobrien * profhz/stathz for statistics. (For profiling, every tick counts.) 150117397Skan * 151117397Skan * Time-of-day is maintained using a "timecounter", which may or may 152117397Skan * not be related to the hardware generating the above mentioned 153117397Skan * interrupts. 154117397Skan */ 155117397Skan 156117397Skanint stathz; 157117397Skanint profhz; 15897403Sobrienint profprocs; 15997403Sobrienint ticks; 16097403Sobrienint psratio; 161132720Skan 16297403Sobrien/* 163117397Skan * Initialize clock frequencies and start both clocks running. 16497403Sobrien */ 16597403Sobrien/* ARGSUSED*/ 16697403Sobrienstatic void 167132720Skaninitclocks(dummy) 168132720Skan void *dummy; 169132720Skan{ 17097403Sobrien register int i; 17197403Sobrien 17297403Sobrien /* 17397403Sobrien * Set divisors to 1 (normal case) and let the machine-specific 174132720Skan * code do its bit. 17597403Sobrien */ 17697403Sobrien cpu_initclocks(); 17797403Sobrien 17897403Sobrien /* 179132720Skan * Compute profhz/stathz, and fix profhz if needed. 18097403Sobrien */ 181132720Skan i = stathz ? stathz : hz; 18297403Sobrien if (profhz == 0) 18397403Sobrien profhz = i; 18497403Sobrien psratio = profhz / i; 185117397Skan#ifdef SW_WATCHDOG 186117397Skan EVENTHANDLER_REGISTER(watchdog_list, watchdog_config, NULL, 0); 187117397Skan#endif 188117397Skan} 189117397Skan 190117397Skan/* 191117397Skan * Each time the real-time timer fires, this function is called on all CPUs. 192117397Skan * Note that hardclock() calls hardclock_process() for the boot CPU, so only 193117397Skan * the other CPUs in the system need to call this function. 194117397Skan */ 195117397Skanvoid 196117397Skanhardclock_process(frame) 197117397Skan register struct clockframe *frame; 198117397Skan{ 199117397Skan struct pstats *pstats; 200117397Skan struct thread *td = curthread; 201117397Skan struct proc *p = td->td_proc; 202117397Skan 203117397Skan /* 204117397Skan * Run current process's virtual and profile time, as needed. 205117397Skan */ 206117397Skan mtx_lock_spin_flags(&sched_lock, MTX_QUIET); 207117397Skan if (p->p_flag & P_SA) { 208117397Skan /* XXXKSE What to do? */ 209117397Skan } else { 21097403Sobrien pstats = p->p_stats; 211132720Skan if (CLKF_USERMODE(frame) && 212117397Skan timevalisset(&pstats->p_timer[ITIMER_VIRTUAL].it_value) && 21397403Sobrien itimerdecr(&pstats->p_timer[ITIMER_VIRTUAL], tick) == 0) { 214132720Skan p->p_sflag |= PS_ALRMPEND; 215117397Skan td->td_flags |= TDF_ASTPENDING; 21697403Sobrien } 217132720Skan if (timevalisset(&pstats->p_timer[ITIMER_PROF].it_value) && 218117397Skan itimerdecr(&pstats->p_timer[ITIMER_PROF], tick) == 0) { 21997403Sobrien p->p_sflag |= PS_PROFPEND; 220132720Skan td->td_flags |= TDF_ASTPENDING; 221117397Skan } 22297403Sobrien } 223132720Skan mtx_unlock_spin_flags(&sched_lock, MTX_QUIET); 224117397Skan 225117397Skan#ifdef HWPMC_HOOKS 226117397Skan if (PMC_CPU_HAS_SAMPLES(PCPU_GET(cpuid))) 22797403Sobrien PMC_CALL_HOOK_UNLOCKED(curthread, PMC_FN_DO_SAMPLES, NULL); 228132720Skan#endif 229117397Skan} 230117397Skan 23197403Sobrien/* 232132720Skan * The real-time timer, interrupting hz times per second. 233117397Skan */ 23497403Sobrienvoid 235132720Skanhardclock(frame) 236117397Skan register struct clockframe *frame; 237117397Skan{ 23897403Sobrien int need_softclock = 0; 239132720Skan 240117397Skan CTR0(KTR_CLK, "hardclock fired"); 24197403Sobrien hardclock_process(frame); 242132720Skan 243117397Skan tc_ticktock(); 244117397Skan /* 24597403Sobrien * If no separate statistics clock is available, run it from here. 246132720Skan * 247117397Skan * XXX: this only works for UP 248117397Skan */ 24997403Sobrien if (stathz == 0) { 250132720Skan profclock(frame); 251117397Skan statclock(frame); 25297403Sobrien } 253132720Skan 254117397Skan#ifdef DEVICE_POLLING 25597403Sobrien hardclock_device_poll(); /* this is very short and quick */ 256132720Skan#endif /* DEVICE_POLLING */ 257117397Skan 25897403Sobrien /* 259132720Skan * Process callouts at a very low cpu priority, so we don't keep the 260117397Skan * relatively high clock interrupt priority any longer than necessary. 261117397Skan */ 26297403Sobrien mtx_lock_spin_flags(&callout_lock, MTX_QUIET); 263132720Skan ticks++; 264117397Skan if (TAILQ_FIRST(&callwheel[ticks & callwheelmask]) != NULL) { 26597403Sobrien need_softclock = 1; 266132720Skan } else if (softticks + 1 == ticks) 267117397Skan ++softticks; 26897403Sobrien mtx_unlock_spin_flags(&callout_lock, MTX_QUIET); 269132720Skan 270117397Skan /* 27197403Sobrien * swi_sched acquires sched_lock, so we don't want to call it with 27297403Sobrien * callout_lock held; incorrect locking order. 27397403Sobrien */ 274117397Skan if (need_softclock) 275117397Skan swi_sched(softclock_ih, 0); 276117397Skan 277117397Skan#ifdef SW_WATCHDOG 278117397Skan if (watchdog_enabled > 0 && --watchdog_ticks <= 0) 279117397Skan watchdog_fire(); 280117397Skan#endif /* SW_WATCHDOG */ 281117397Skan} 282117397Skan 283117397Skan/* 284117397Skan * Compute number of ticks in the specified amount of time. 28597403Sobrien */ 286132720Skanint 287117397Skantvtohz(tv) 288117397Skan struct timeval *tv; 289132720Skan{ 290132720Skan register unsigned long ticks; 291117397Skan register long sec, usec; 292132720Skan 293132720Skan /* 294117397Skan * If the number of usecs in the whole seconds part of the time 295117397Skan * difference fits in a long, then the total number of usecs will 296117397Skan * fit in an unsigned long. Compute the total and convert it to 297132720Skan * ticks, rounding up and adding 1 to allow for the current tick 298132720Skan * to expire. Rounding also depends on unsigned long arithmetic 299117397Skan * to avoid overflow. 300132720Skan * 30197403Sobrien * Otherwise, if the number of ticks in the whole seconds part of 302117397Skan * the time difference fits in a long, then convert the parts to 303117397Skan * ticks separately and add, using similar rounding methods and 304117397Skan * overflow avoidance. This method would work in the previous 305117397Skan * case but it is slightly slower and assumes that hz is integral. 306117397Skan * 307117397Skan * Otherwise, round the time difference down to the maximum 308117397Skan * representable value. 309117397Skan * 310117397Skan * If ints have 32 bits, then the maximum value for any timeout in 311117397Skan * 10ms ticks is 248 days. 312117397Skan */ 313117397Skan sec = tv->tv_sec; 314117397Skan usec = tv->tv_usec; 315117397Skan if (usec < 0) { 31697403Sobrien sec--; 317132720Skan usec += 1000000; 318117397Skan } 319132720Skan if (sec < 0) { 320132720Skan#ifdef DIAGNOSTIC 321117397Skan if (usec > 0) { 322132720Skan sec++; 323132720Skan usec -= 1000000; 324117397Skan } 325117397Skan printf("tvotohz: negative time difference %ld sec %ld usec\n", 326117397Skan sec, usec); 327117397Skan#endif 328132720Skan ticks = 1; 329132720Skan } else if (sec <= LONG_MAX / 1000000) 330117397Skan ticks = (sec * 1000000 + (unsigned long)usec + (tick - 1)) 331132720Skan / tick + 1; 332132720Skan else if (sec <= LONG_MAX / hz) 333117397Skan ticks = sec * hz 334132720Skan + ((unsigned long)usec + (tick - 1)) / tick + 1; 335132720Skan else 336117397Skan ticks = LONG_MAX; 337132720Skan if (ticks > INT_MAX) 33897403Sobrien ticks = INT_MAX; 339117397Skan return ((int)ticks); 340117397Skan} 341117397Skan 342117397Skan/* 343117397Skan * Start profiling on a process. 344117397Skan * 345117397Skan * Kernel profiling passes proc0 which never exits and hence 346117397Skan * keeps the profile clock running constantly. 347117397Skan */ 348117397Skanvoid 34997403Sobrienstartprofclock(p) 350132720Skan register struct proc *p; 351117397Skan{ 352132720Skan 353132720Skan /* 354117397Skan * XXX; Right now sched_lock protects statclock(), but perhaps 355132720Skan * it should be protected later on by a time_lock, which would 356132720Skan * cover psdiv, etc. as well. 357117397Skan */ 358132720Skan PROC_LOCK_ASSERT(p, MA_OWNED); 35997403Sobrien if (p->p_flag & P_STOPPROF) 360132720Skan return; 361117397Skan if ((p->p_flag & P_PROFIL) == 0) { 36297403Sobrien mtx_lock_spin(&sched_lock); 36397403Sobrien p->p_flag |= P_PROFIL; 36497403Sobrien if (++profprocs == 1) 365132720Skan cpu_startprofclock(); 366107606Sobrien mtx_unlock_spin(&sched_lock); 367107606Sobrien } 36897403Sobrien} 36997403Sobrien 37097403Sobrien/* 371117397Skan * Stop profiling on a process. 372132720Skan */ 373132720Skanvoid 374132720Skanstopprofclock(p) 375132720Skan register struct proc *p; 376117397Skan{ 37797403Sobrien 37897403Sobrien PROC_LOCK_ASSERT(p, MA_OWNED); 37997403Sobrien if (p->p_flag & P_PROFIL) { 38097403Sobrien if (p->p_profthreads != 0) { 38197403Sobrien p->p_flag |= P_STOPPROF; 38297403Sobrien while (p->p_profthreads != 0) 38397403Sobrien msleep(&p->p_profthreads, &p->p_mtx, PPAUSE, 384117397Skan "stopprof", 0); 385132720Skan p->p_flag &= ~P_STOPPROF; 386132720Skan } 387132720Skan if ((p->p_flag & P_PROFIL) == 0) 388132720Skan return; 389132720Skan mtx_lock_spin(&sched_lock); 390132720Skan p->p_flag &= ~P_PROFIL; 391132720Skan if (--profprocs == 0) 392132720Skan cpu_stopprofclock(); 393117397Skan mtx_unlock_spin(&sched_lock); 39497403Sobrien } 39597403Sobrien} 396117397Skan 397132720Skan/* 398132720Skan * Statistics clock. Grab profile sample, and if divider reaches 0, 399132720Skan * do process and kernel statistics. Most of the statistics are only 400132720Skan * used by user-level statistics programs. The main exceptions are 401132720Skan * ke->ke_uticks, p->p_rux.rux_sticks, p->p_rux.rux_iticks, and p->p_estcpu. 402132720Skan * This should be called by all active processors. 403132720Skan */ 404132720Skanvoid 405117397Skanstatclock(frame) 406132720Skan register struct clockframe *frame; 40797403Sobrien{ 40897403Sobrien struct rusage *ru; 40997403Sobrien struct vmspace *vm; 410117397Skan struct thread *td; 411117397Skan struct proc *p; 412117397Skan long rss; 413117397Skan 414117397Skan td = curthread; 415117397Skan p = td->td_proc; 416132720Skan 417132720Skan mtx_lock_spin_flags(&sched_lock, MTX_QUIET); 418132720Skan if (CLKF_USERMODE(frame)) { 419132720Skan /* 420132720Skan * Charge the time as appropriate. 421117397Skan */ 42297403Sobrien if (p->p_flag & P_SA) 42397403Sobrien thread_statclock(1); 42497403Sobrien p->p_rux.rux_uticks++; 42597403Sobrien if (p->p_nice > NZERO) 42697403Sobrien cp_time[CP_NICE]++; 42797403Sobrien else 428132720Skan cp_time[CP_USER]++; 429132720Skan } else { 430132720Skan /* 43197403Sobrien * Came from kernel mode, so we were: 432132720Skan * - handling an interrupt, 433132720Skan * - doing syscall or trap work on behalf of the current 43497403Sobrien * user process, or 43597403Sobrien * - spinning in the idle loop. 43697403Sobrien * Whichever it is, charge the time as appropriate. 437132720Skan * Note that we charge interrupts to the current process, 438132720Skan * regardless of whether they are ``for'' that process, 439132720Skan * so that we know how much of its real time was spent 44097403Sobrien * in ``non-process'' (i.e., interrupt) work. 441132720Skan */ 442132720Skan if ((td->td_pflags & TDP_ITHREAD) || 443132720Skan td->td_intr_nesting_level >= 2) { 44497403Sobrien p->p_rux.rux_iticks++; 44597403Sobrien cp_time[CP_INTR]++; 446132720Skan } else { 44797403Sobrien if (p->p_flag & P_SA) 448132720Skan thread_statclock(0); 44997403Sobrien td->td_sticks++; 45097403Sobrien p->p_rux.rux_sticks++; 451132720Skan if (td != PCPU_GET(idlethread)) 45297403Sobrien cp_time[CP_SYS]++; 45397403Sobrien else 45497403Sobrien cp_time[CP_IDLE]++; 455132720Skan } 456132720Skan } 457132720Skan CTR4(KTR_SCHED, "statclock: %p(%s) prio %d stathz %d", 458132720Skan td, td->td_proc->p_comm, td->td_priority, (stathz)?stathz:hz); 45997403Sobrien 46097403Sobrien sched_clock(td); 46197403Sobrien 46297403Sobrien /* Update resource usage integrals and maximums. */ 463132720Skan MPASS(p->p_stats != NULL); 46497403Sobrien MPASS(p->p_vmspace != NULL); 46597403Sobrien vm = p->p_vmspace; 466117397Skan ru = &p->p_stats->p_ru; 467132720Skan ru->ru_ixrss += pgtok(vm->vm_tsize); 468132720Skan ru->ru_idrss += pgtok(vm->vm_dsize); 46997403Sobrien ru->ru_isrss += pgtok(vm->vm_ssize); 47097403Sobrien rss = pgtok(vmspace_resident_count(vm)); 471132720Skan if (ru->ru_maxrss < rss) 472132720Skan ru->ru_maxrss = rss; 47397403Sobrien mtx_unlock_spin_flags(&sched_lock, MTX_QUIET); 474132720Skan} 475132720Skan 476132720Skanvoid 47797403Sobrienprofclock(frame) 478132720Skan register struct clockframe *frame; 47997403Sobrien{ 480132720Skan struct thread *td; 48197403Sobrien#ifdef GPROF 48297403Sobrien struct gmonparam *g; 48397403Sobrien int i; 48497403Sobrien#endif 48597403Sobrien 48697403Sobrien td = curthread; 48797403Sobrien if (CLKF_USERMODE(frame)) { 488132720Skan /* 489132720Skan * Came from user mode; CPU was in user state. 49097403Sobrien * If this process is being profiled, record the tick. 49197403Sobrien * if there is no related user location yet, don't 49297403Sobrien * bother trying to count it. 49397403Sobrien */ 49497403Sobrien if (td->td_proc->p_flag & P_PROFIL) 49597403Sobrien addupc_intr(td, CLKF_PC(frame), 1); 49697403Sobrien } 497132720Skan#ifdef GPROF 498132720Skan else { 49997403Sobrien /* 50097403Sobrien * Kernel statistics are just like addupc_intr, only easier. 501117397Skan */ 502117397Skan g = &_gmonparam; 503117397Skan if (g->state == GMON_PROF_ON) { 504117397Skan i = CLKF_PC(frame) - g->lowpc; 505117397Skan if (i < g->textsize) { 506132720Skan i /= HISTFRACTION * sizeof(*g->kcount); 50797403Sobrien g->kcount[i]++; 50897403Sobrien } 509117397Skan } 510117397Skan } 511117397Skan#endif 512117397Skan} 513117397Skan 514117397Skan/* 515117397Skan * Return information about system clocks. 516132720Skan */ 51797403Sobrienstatic int 518132720Skansysctl_kern_clockrate(SYSCTL_HANDLER_ARGS) 519132720Skan{ 520132720Skan struct clockinfo clkinfo; 521132720Skan /* 52297403Sobrien * Construct clockinfo structure. 52397403Sobrien */ 524117397Skan bzero(&clkinfo, sizeof(clkinfo)); 525117397Skan clkinfo.hz = hz; 526117397Skan clkinfo.tick = tick; 527117397Skan clkinfo.profhz = profhz; 528117397Skan clkinfo.stathz = stathz ? stathz : hz; 529117397Skan return (sysctl_handle_opaque(oidp, &clkinfo, sizeof clkinfo, req)); 530117397Skan} 531117397Skan 532132720SkanSYSCTL_PROC(_kern, KERN_CLOCKRATE, clockrate, CTLTYPE_STRUCT|CTLFLAG_RD, 53397403Sobrien 0, 0, sysctl_kern_clockrate, "S,clockinfo", 534132720Skan "Rate and period of various kernel clocks"); 535132720Skan 536132720Skan#ifdef SW_WATCHDOG 537132720Skan 53897403Sobrienstatic void 53997403Sobrienwatchdog_config(void *unused __unused, u_int cmd, int *err) 540117397Skan{ 541117397Skan u_int u; 542117397Skan 543117397Skan u = cmd & WD_INTERVAL; 544117397Skan if ((cmd & WD_ACTIVE) && u >= WD_TO_1SEC) { 545117397Skan watchdog_ticks = (1 << (u - WD_TO_1SEC)) * hz; 546117397Skan watchdog_enabled = 1; 547117397Skan *err = 0; 548117397Skan } else { 549132720Skan watchdog_enabled = 0; 55097403Sobrien } 55197403Sobrien} 55297403Sobrien 55397403Sobrien/* 55497403Sobrien * Handle a watchdog timeout by dumping interrupt information and 55597403Sobrien * then either dropping to DDB or panicing. 55697403Sobrien */ 55797403Sobrienstatic void 558117397Skanwatchdog_fire(void) 559117397Skan{ 560117397Skan int nintr; 561117397Skan u_int64_t inttotal; 562117397Skan u_long *curintr; 563117397Skan char *curname; 564132720Skan 56597403Sobrien curintr = intrcnt; 56697403Sobrien curname = intrnames; 567117397Skan inttotal = 0; 568117397Skan nintr = eintrcnt - intrcnt; 569117397Skan 570117397Skan printf("interrupt total\n"); 571117397Skan while (--nintr >= 0) { 572117397Skan if (*curintr) 573117397Skan printf("%-12s %20lu\n", curname, *curintr); 574117397Skan curname += strlen(curname) + 1; 575117397Skan inttotal += *curintr++; 576132720Skan } 57797403Sobrien printf("Total %20ju\n", (uintmax_t)inttotal); 57897403Sobrien 579117397Skan#ifdef KDB 580117397Skan kdb_backtrace(); 581117397Skan kdb_enter("watchdog timeout"); 582117397Skan#else 583117397Skan panic("watchdog timeout"); 584132720Skan#endif /* KDB */ 58597403Sobrien} 586132720Skan 587132720Skan#endif /* SW_WATCHDOG */ 588132720Skan