[BACK]Return to kern_clock.c CVS log [TXT][DIR] Up to [cvs.NetBSD.org] / src / sys / kern

Annotation of src/sys/kern/kern_clock.c, Revision 1.128

1.128   ! uebayasi    1: /*     $NetBSD$        */
1.52      thorpej     2:
                      3: /*-
1.118     ad          4:  * Copyright (c) 2000, 2004, 2006, 2007, 2008 The NetBSD Foundation, Inc.
1.52      thorpej     5:  * All rights reserved.
                      6:  *
                      7:  * This code is derived from software contributed to The NetBSD Foundation
                      8:  * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
                      9:  * NASA Ames Research Center.
1.94      mycroft    10:  * This code is derived from software contributed to The NetBSD Foundation
                     11:  * by Charles M. Hannum.
1.52      thorpej    12:  *
                     13:  * Redistribution and use in source and binary forms, with or without
                     14:  * modification, are permitted provided that the following conditions
                     15:  * are met:
                     16:  * 1. Redistributions of source code must retain the above copyright
                     17:  *    notice, this list of conditions and the following disclaimer.
                     18:  * 2. Redistributions in binary form must reproduce the above copyright
                     19:  *    notice, this list of conditions and the following disclaimer in the
                     20:  *    documentation and/or other materials provided with the distribution.
                     21:  *
                     22:  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
                     23:  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
                     24:  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
                     25:  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
                     26:  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
                     27:  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
                     28:  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
                     29:  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
                     30:  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
                     31:  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
                     32:  * POSSIBILITY OF SUCH DAMAGE.
                     33:  */
1.19      cgd        34:
                     35: /*-
                     36:  * Copyright (c) 1982, 1986, 1991, 1993
                     37:  *     The Regents of the University of California.  All rights reserved.
                     38:  * (c) UNIX System Laboratories, Inc.
                     39:  * All or some portions of this file are derived from material licensed
                     40:  * to the University of California by American Telephone and Telegraph
                     41:  * Co. or Unix System Laboratories, Inc. and are reproduced herein with
                     42:  * the permission of UNIX System Laboratories, Inc.
                     43:  *
                     44:  * Redistribution and use in source and binary forms, with or without
                     45:  * modification, are permitted provided that the following conditions
                     46:  * are met:
                     47:  * 1. Redistributions of source code must retain the above copyright
                     48:  *    notice, this list of conditions and the following disclaimer.
                     49:  * 2. Redistributions in binary form must reproduce the above copyright
                     50:  *    notice, this list of conditions and the following disclaimer in the
                     51:  *    documentation and/or other materials provided with the distribution.
1.87      agc        52:  * 3. Neither the name of the University nor the names of its contributors
1.19      cgd        53:  *    may be used to endorse or promote products derived from this software
                     54:  *    without specific prior written permission.
                     55:  *
                     56:  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
                     57:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
                     58:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
                     59:  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
                     60:  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
                     61:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
                     62:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
                     63:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
                     64:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
                     65:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
                     66:  * SUCH DAMAGE.
                     67:  *
                     68:  *     @(#)kern_clock.c        8.5 (Berkeley) 1/21/94
                     69:  */
1.78      lukem      70:
                     71: #include <sys/cdefs.h>
1.128   ! uebayasi   72: __KERNEL_RCSID(0, "$NetBSD$");
1.44      jonathan   73:
                     74: #include "opt_ntp.h"
1.80      briggs     75: #include "opt_perfctrs.h"
1.19      cgd        76:
                     77: #include <sys/param.h>
                     78: #include <sys/systm.h>
                     79: #include <sys/callout.h>
                     80: #include <sys/kernel.h>
                     81: #include <sys/proc.h>
                     82: #include <sys/resourcevar.h>
1.25      christos   83: #include <sys/signalvar.h>
1.26      christos   84: #include <sys/sysctl.h>
1.27      jonathan   85: #include <sys/timex.h>
1.45      ross       86: #include <sys/sched.h>
1.82      thorpej    87: #include <sys/time.h>
1.99      kardel     88: #include <sys/timetc.h>
1.109     ad         89: #include <sys/cpu.h>
1.118     ad         90: #include <sys/atomic.h>
                     91:
1.19      cgd        92: #ifdef GPROF
                     93: #include <sys/gmon.h>
                     94: #endif
                     95:
                     96: /*
                     97:  * Clock handling routines.
                     98:  *
                     99:  * This code is written to operate with two timers that run independently of
                    100:  * each other.  The main clock, running hz times per second, is used to keep
                    101:  * track of real time.  The second timer handles kernel and user profiling,
                    102:  * and does resource use estimation.  If the second timer is programmable,
                    103:  * it is randomized to avoid aliasing between the two clocks.  For example,
1.90      wiz       104:  * the randomization prevents an adversary from always giving up the CPU
1.19      cgd       105:  * just before its quantum expires.  Otherwise, it would never accumulate
1.90      wiz       106:  * CPU ticks.  The mean frequency of the second timer is stathz.
1.19      cgd       107:  *
                    108:  * If no second timer exists, stathz will be zero; in this case we drive
                    109:  * profiling and statistics off the main clock.  This WILL NOT be accurate;
                    110:  * do not do it unless absolutely necessary.
                    111:  *
                    112:  * The statistics clock may (or may not) be run at a higher rate while
                    113:  * profiling.  This profile clock runs at profhz.  We require that profhz
                    114:  * be an integral multiple of stathz.
                    115:  *
                    116:  * If the statistics clock is running fast, it must be divided by the ratio
                    117:  * profhz/stathz for statistics.  (For profiling, every tick counts.)
                    118:  */
                    119:
                    120: int    stathz;
                    121: int    profhz;
1.80      briggs    122: int    profsrc;
1.75      simonb    123: int    schedhz;
1.19      cgd       124: int    profprocs;
1.100     drochner  125: int    hardclock_ticks;
1.114     ad        126: static int hardscheddiv; /* hard => sched divider (used if schedhz == 0) */
1.70      sommerfe  127: static int psdiv;                      /* prof => stat divider */
1.22      cgd       128: int    psratio;                        /* ratio: prof / stat */
1.19      cgd       129:
1.99      kardel    130: static u_int get_intr_timecount(struct timecounter *);
                    131:
                    132: static struct timecounter intr_timecounter = {
                    133:        get_intr_timecount,     /* get_timecount */
                    134:        0,                      /* no poll_pps */
                    135:        ~0u,                    /* counter_mask */
                    136:        0,                      /* frequency */
                    137:        "clockinterrupt",       /* name */
1.102     christos  138:        0,                      /* quality - minimum implementation level for a clock */
                    139:        NULL,                   /* prev */
                    140:        NULL,                   /* next */
1.99      kardel    141: };
                    142:
                    143: static u_int
1.104     yamt      144: get_intr_timecount(struct timecounter *tc)
1.99      kardel    145: {
1.104     yamt      146:
1.100     drochner  147:        return (u_int)hardclock_ticks;
1.99      kardel    148: }
1.73      thorpej   149:
1.66      thorpej   150: /*
1.19      cgd       151:  * Initialize clock frequencies and start both clocks running.
                    152:  */
                    153: void
1.63      thorpej   154: initclocks(void)
1.19      cgd       155: {
1.55      augustss  156:        int i;
1.19      cgd       157:
                    158:        /*
                    159:         * Set divisors to 1 (normal case) and let the machine-specific
                    160:         * code do its bit.
                    161:         */
1.70      sommerfe  162:        psdiv = 1;
1.99      kardel    163:        /*
                    164:         * provide minimum default time counter
                    165:         * will only run at interrupt resolution
                    166:         */
                    167:        intr_timecounter.tc_frequency = hz;
                    168:        tc_init(&intr_timecounter);
1.19      cgd       169:        cpu_initclocks();
                    170:
                    171:        /*
1.108     yamt      172:         * Compute profhz and stathz, fix profhz if needed.
1.19      cgd       173:         */
                    174:        i = stathz ? stathz : hz;
                    175:        if (profhz == 0)
                    176:                profhz = i;
                    177:        psratio = profhz / i;
1.91      yamt      178:        if (schedhz == 0) {
                    179:                /* 16Hz is best */
1.114     ad        180:                hardscheddiv = hz / 16;
                    181:                if (hardscheddiv <= 0)
                    182:                        panic("hardscheddiv");
1.91      yamt      183:        }
1.31      mycroft   184:
1.19      cgd       185: }
                    186:
                    187: /*
                    188:  * The real-time timer, interrupting hz times per second.
                    189:  */
                    190: void
1.63      thorpej   191: hardclock(struct clockframe *frame)
1.19      cgd       192: {
1.82      thorpej   193:        struct lwp *l;
1.120     ad        194:        struct cpu_info *ci;
1.19      cgd       195:
1.120     ad        196:        ci = curcpu();
1.114     ad        197:        l = ci->ci_data.cpu_onproc;
1.120     ad        198:
                    199:        timer_tick(l, CLKF_USERMODE(frame));
1.19      cgd       200:
                    201:        /*
                    202:         * If no separate statistics clock is available, run it from here.
                    203:         */
                    204:        if (stathz == 0)
                    205:                statclock(frame);
1.114     ad        206:        /*
                    207:         * If no separate schedclock is provided, call it here
                    208:         * at about 16 Hz.
                    209:         */
                    210:        if (schedhz == 0) {
                    211:                if ((int)(--ci->ci_schedstate.spc_schedticks) <= 0) {
                    212:                        schedclock(l);
                    213:                        ci->ci_schedstate.spc_schedticks = hardscheddiv;
                    214:                }
                    215:        }
1.108     yamt      216:        if ((--ci->ci_schedstate.spc_ticks) <= 0)
                    217:                sched_tick(ci);
1.93      perry     218:
1.123     ad        219:        if (CPU_IS_PRIMARY(ci)) {
1.121     ad        220:                hardclock_ticks++;
                    221:                tc_ticktock();
                    222:        }
1.19      cgd       223:
                    224:        /*
1.126     pooka     225:         * Update real-time timeout queue.
1.106     ad        226:         */
1.109     ad        227:        callout_hardclock();
1.19      cgd       228: }
                    229:
                    230: /*
                    231:  * Start profiling on a process.
                    232:  *
                    233:  * Kernel profiling passes proc0 which never exits and hence
                    234:  * keeps the profile clock running constantly.
                    235:  */
                    236: void
1.63      thorpej   237: startprofclock(struct proc *p)
1.19      cgd       238: {
                    239:
1.109     ad        240:        KASSERT(mutex_owned(&p->p_stmutex));
1.105     ad        241:
                    242:        if ((p->p_stflag & PST_PROFIL) == 0) {
                    243:                p->p_stflag |= PST_PROFIL;
1.80      briggs    244:                /*
                    245:                 * This is only necessary if using the clock as the
                    246:                 * profiling source.
                    247:                 */
1.70      sommerfe  248:                if (++profprocs == 1 && stathz != 0)
                    249:                        psdiv = psratio;
1.19      cgd       250:        }
                    251: }
                    252:
                    253: /*
                    254:  * Stop profiling on a process.
                    255:  */
                    256: void
1.63      thorpej   257: stopprofclock(struct proc *p)
1.19      cgd       258: {
                    259:
1.109     ad        260:        KASSERT(mutex_owned(&p->p_stmutex));
1.105     ad        261:
                    262:        if (p->p_stflag & PST_PROFIL) {
                    263:                p->p_stflag &= ~PST_PROFIL;
1.80      briggs    264:                /*
                    265:                 * This is only necessary if using the clock as the
                    266:                 * profiling source.
                    267:                 */
1.70      sommerfe  268:                if (--profprocs == 0 && stathz != 0)
                    269:                        psdiv = 1;
1.19      cgd       270:        }
                    271: }
                    272:
1.80      briggs    273: #if defined(PERFCTRS)
                    274: /*
                    275:  * Independent profiling "tick" in case we're using a separate
                    276:  * clock or profiling event source.  Currently, that's just
                    277:  * performance counters--hence the wrapper.
                    278:  */
                    279: void
                    280: proftick(struct clockframe *frame)
                    281: {
                    282: #ifdef GPROF
1.93      perry     283:         struct gmonparam *g;
                    284:         intptr_t i;
1.80      briggs    285: #endif
1.105     ad        286:        struct lwp *l;
1.80      briggs    287:        struct proc *p;
                    288:
1.114     ad        289:        l = curcpu()->ci_data.cpu_onproc;
1.105     ad        290:        p = (l ? l->l_proc : NULL);
1.80      briggs    291:        if (CLKF_USERMODE(frame)) {
1.105     ad        292:                mutex_spin_enter(&p->p_stmutex);
                    293:                if (p->p_stflag & PST_PROFIL)
                    294:                        addupc_intr(l, CLKF_PC(frame));
                    295:                mutex_spin_exit(&p->p_stmutex);
1.80      briggs    296:        } else {
                    297: #ifdef GPROF
                    298:                g = &_gmonparam;
                    299:                if (g->state == GMON_PROF_ON) {
                    300:                        i = CLKF_PC(frame) - g->lowpc;
                    301:                        if (i < g->textsize) {
                    302:                                i /= HISTFRACTION * sizeof(*g->kcount);
                    303:                                g->kcount[i]++;
                    304:                        }
                    305:                }
                    306: #endif
1.111     ad        307: #ifdef LWP_PC
                    308:                if (p != NULL && (p->p_stflag & PST_PROFIL) != 0)
1.112     ad        309:                        addupc_intr(l, LWP_PC(l));
1.93      perry     310: #endif
1.80      briggs    311:        }
                    312: }
                    313: #endif
                    314:
1.108     yamt      315: void
                    316: schedclock(struct lwp *l)
                    317: {
                    318:        if ((l->l_flag & LW_IDLE) != 0)
                    319:                return;
                    320:
                    321:        sched_schedclock(l);
                    322: }
                    323:
1.19      cgd       324: /*
                    325:  * Statistics clock.  Grab profile sample, and if divider reaches 0,
                    326:  * do process and kernel statistics.
                    327:  */
                    328: void
1.63      thorpej   329: statclock(struct clockframe *frame)
1.19      cgd       330: {
                    331: #ifdef GPROF
1.55      augustss  332:        struct gmonparam *g;
1.68      eeh       333:        intptr_t i;
1.19      cgd       334: #endif
1.60      thorpej   335:        struct cpu_info *ci = curcpu();
                    336:        struct schedstate_percpu *spc = &ci->ci_schedstate;
1.55      augustss  337:        struct proc *p;
1.98      christos  338:        struct lwp *l;
1.19      cgd       339:
1.70      sommerfe  340:        /*
                    341:         * Notice changes in divisor frequency, and adjust clock
                    342:         * frequency accordingly.
                    343:         */
                    344:        if (spc->spc_psdiv != psdiv) {
                    345:                spc->spc_psdiv = psdiv;
                    346:                spc->spc_pscnt = psdiv;
                    347:                if (psdiv == 1) {
                    348:                        setstatclockrate(stathz);
                    349:                } else {
1.93      perry     350:                        setstatclockrate(profhz);
1.70      sommerfe  351:                }
                    352:        }
1.114     ad        353:        l = ci->ci_data.cpu_onproc;
1.108     yamt      354:        if ((l->l_flag & LW_IDLE) != 0) {
                    355:                /*
                    356:                 * don't account idle lwps as swapper.
                    357:                 */
                    358:                p = NULL;
                    359:        } else {
                    360:                p = l->l_proc;
1.105     ad        361:                mutex_spin_enter(&p->p_stmutex);
1.108     yamt      362:        }
                    363:
1.19      cgd       364:        if (CLKF_USERMODE(frame)) {
1.105     ad        365:                if ((p->p_stflag & PST_PROFIL) && profsrc == PROFSRC_CLOCK)
                    366:                        addupc_intr(l, CLKF_PC(frame));
                    367:                if (--spc->spc_pscnt > 0) {
                    368:                        mutex_spin_exit(&p->p_stmutex);
1.19      cgd       369:                        return;
1.105     ad        370:                }
                    371:
1.19      cgd       372:                /*
                    373:                 * Came from user mode; CPU was in user state.
                    374:                 * If this process is being profiled record the tick.
                    375:                 */
                    376:                p->p_uticks++;
                    377:                if (p->p_nice > NZERO)
1.60      thorpej   378:                        spc->spc_cp_time[CP_NICE]++;
1.19      cgd       379:                else
1.60      thorpej   380:                        spc->spc_cp_time[CP_USER]++;
1.19      cgd       381:        } else {
                    382: #ifdef GPROF
                    383:                /*
                    384:                 * Kernel statistics are just like addupc_intr, only easier.
                    385:                 */
                    386:                g = &_gmonparam;
1.80      briggs    387:                if (profsrc == PROFSRC_CLOCK && g->state == GMON_PROF_ON) {
1.19      cgd       388:                        i = CLKF_PC(frame) - g->lowpc;
                    389:                        if (i < g->textsize) {
                    390:                                i /= HISTFRACTION * sizeof(*g->kcount);
                    391:                                g->kcount[i]++;
                    392:                        }
                    393:                }
                    394: #endif
1.82      thorpej   395: #ifdef LWP_PC
1.108     yamt      396:                if (p != NULL && profsrc == PROFSRC_CLOCK &&
                    397:                    (p->p_stflag & PST_PROFIL)) {
1.105     ad        398:                        addupc_intr(l, LWP_PC(l));
1.108     yamt      399:                }
1.72      mycroft   400: #endif
1.105     ad        401:                if (--spc->spc_pscnt > 0) {
                    402:                        if (p != NULL)
                    403:                                mutex_spin_exit(&p->p_stmutex);
1.19      cgd       404:                        return;
1.105     ad        405:                }
1.19      cgd       406:                /*
                    407:                 * Came from kernel mode, so we were:
                    408:                 * - handling an interrupt,
                    409:                 * - doing syscall or trap work on behalf of the current
                    410:                 *   user process, or
                    411:                 * - spinning in the idle loop.
                    412:                 * Whichever it is, charge the time as appropriate.
                    413:                 * Note that we charge interrupts to the current process,
                    414:                 * regardless of whether they are ``for'' that process,
                    415:                 * so that we know how much of its real time was spent
                    416:                 * in ``non-process'' (i.e., interrupt) work.
                    417:                 */
1.114     ad        418:                if (CLKF_INTR(frame) || (curlwp->l_pflag & LP_INTR) != 0) {
1.108     yamt      419:                        if (p != NULL) {
1.19      cgd       420:                                p->p_iticks++;
1.108     yamt      421:                        }
1.60      thorpej   422:                        spc->spc_cp_time[CP_INTR]++;
1.19      cgd       423:                } else if (p != NULL) {
                    424:                        p->p_sticks++;
1.60      thorpej   425:                        spc->spc_cp_time[CP_SYS]++;
1.108     yamt      426:                } else {
1.60      thorpej   427:                        spc->spc_cp_time[CP_IDLE]++;
1.108     yamt      428:                }
1.19      cgd       429:        }
1.70      sommerfe  430:        spc->spc_pscnt = psdiv;
1.19      cgd       431:
1.97      elad      432:        if (p != NULL) {
1.125     rmind     433:                atomic_inc_uint(&l->l_cpticks);
1.105     ad        434:                mutex_spin_exit(&p->p_stmutex);
1.108     yamt      435:        }
1.19      cgd       436: }

CVSweb <webmaster@jp.NetBSD.org>