Annotation of kernel/bsd/kern/kern_clock.c, revision 1.1.1.1

1.1       root        1: /*
                      2:  * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
                      3:  *
                      4:  * @APPLE_LICENSE_HEADER_START@
                      5:  * 
                      6:  * Portions Copyright (c) 1999 Apple Computer, Inc.  All Rights
                      7:  * Reserved.  This file contains Original Code and/or Modifications of
                      8:  * Original Code as defined in and that are subject to the Apple Public
                      9:  * Source License Version 1.1 (the "License").  You may not use this file
                     10:  * except in compliance with the License.  Please obtain a copy of the
                     11:  * License at http://www.apple.com/publicsource and read it before using
                     12:  * this file.
                     13:  * 
                     14:  * The Original Code and all software distributed under the License are
                     15:  * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
                     16:  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
                     17:  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
                     18:  * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT.  Please see the
                     19:  * License for the specific language governing rights and limitations
                     20:  * under the License.
                     21:  * 
                     22:  * @APPLE_LICENSE_HEADER_END@
                     23:  */
                     24: 
                     25: /* Copyright (c) 1995 NeXT Computer, Inc. All Rights Reserved */
                     26: /*-
                     27:  * Copyright (c) 1982, 1986, 1991, 1993
                     28:  *     The Regents of the University of California.  All rights reserved.
                     29:  * (c) UNIX System Laboratories, Inc.
                     30:  * All or some portions of this file are derived from material licensed
                     31:  * to the University of California by American Telephone and Telegraph
                     32:  * Co. or Unix System Laboratories, Inc. and are reproduced herein with
                     33:  * the permission of UNIX System Laboratories, Inc.
                     34:  *
                     35:  * Redistribution and use in source and binary forms, with or without
                     36:  * modification, are permitted provided that the following conditions
                     37:  * are met:
                     38:  * 1. Redistributions of source code must retain the above copyright
                     39:  *    notice, this list of conditions and the following disclaimer.
                     40:  * 2. Redistributions in binary form must reproduce the above copyright
                     41:  *    notice, this list of conditions and the following disclaimer in the
                     42:  *    documentation and/or other materials provided with the distribution.
                     43:  * 3. All advertising materials mentioning features or use of this software
                     44:  *    must display the following acknowledgement:
                     45:  *     This product includes software developed by the University of
                     46:  *     California, Berkeley and its contributors.
                     47:  * 4. Neither the name of the University nor the names of its contributors
                     48:  *    may be used to endorse or promote products derived from this software
                     49:  *    without specific prior written permission.
                     50:  *
                     51:  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
                     52:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
                     53:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
                     54:  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
                     55:  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
                     56:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
                     57:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
                     58:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
                     59:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
                     60:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
                     61:  * SUCH DAMAGE.
                     62:  *
                     63:  *     @(#)kern_clock.c        8.5 (Berkeley) 1/21/94
                     64:  */
                     65: 
                     66: #include <simple_clock.h>
                     67: #include <cpus.h>
                     68: 
                     69: #include <machine/reg.h>
                     70: #include <machine/spl.h>
                     71: 
                     72: #include <sys/param.h>
                     73: #include <sys/systm.h>
                     74: #include <sys/dkstat.h>
                     75: #include <sys/callout.h>
                     76: #include <sys/resourcevar.h>
                     77: #include <sys/kernel.h>
                     78: #include <sys/proc.h>
                     79: 
                     80: #ifdef GPROF
                     81: #include <sys/gmon.h>
                     82: #endif
                     83: 
                     84: #include <bsd/machine/cpu.h>
                     85: 
                     86: #include <kern/thread.h>
                     87: #include <mach/machine.h>
                     88: #include <kern/sched.h>
                     89: #include <kern/thread_call.h>
                     90: #include <mach/time_value.h>
                     91: #include <kern/timer.h>
                     92: #include <kern/xpr.h>
                     93: 
                     94: #include <kern/assert.h>
                     95: 
                     96: #include <mach/boolean.h>
                     97: 
                     98: /*
                     99:  * Clock handling routines.
                    100:  *
                    101:  * This code is written to operate with two timers which run
                    102:  * independently of each other. The main clock, running at hz
                    103:  * times per second, is used to do scheduling and timeout calculations.
                    104:  * The second timer does resource utilization estimation statistically
                    105:  * based on the state of the machine phz times a second. Both functions
                    106:  * can be performed by a single clock (ie hz == phz), however the 
                    107:  * statistics will be much more prone to errors. Ideally a machine
                    108:  * would have separate clocks measuring time spent in user state, system
                    109:  * state, interrupt state, and idle state. These clocks would allow a non-
                    110:  * approximate measure of resource utilization.
                    111:  */
                    112: #define BUMPTIME(t, usec) { \
                    113:        register volatile struct timeval *tp = (t); \
                    114:  \
                    115:        tp->tv_usec += (usec); \
                    116:        if (tp->tv_usec >= 1000000) { \
                    117:                tp->tv_usec -= 1000000; \
                    118:                tp->tv_sec++; \
                    119:        } \
                    120: }
                    121: 
                    122: /*
                    123:  * The hz hardware interval timer.
                    124:  * We update the events relating to real time.
                    125:  * If this timer is also being used to gather statistics,
                    126:  * we run through the statistics gathering routine as well.
                    127:  */
                    128: 
                    129: #if    SIMPLE_CLOCK
                    130: tvalspec_t     last_hardclock[NCPUS];
                    131: #endif /* SIMPLE_CLOCK */
                    132: 
                    133: 
                    134: /*ARGSUSED*/
                    135: void
                    136: hardclock(pc, ps)
                    137:        int ps;
                    138:        caddr_t pc;
                    139: {
                    140:        register struct callout *p1;
                    141:        register struct proc *p;
                    142:        register int s;
                    143: #if    SIMPLE_CLOCK
                    144:        tvalspec_t new_hardclock, delta_hardclock;
                    145:        unsigned int myticks;
                    146: #define        tick    myticks
                    147: #endif /* SIMPLE_CLOCK */
                    148: 
                    149:        extern int tickdelta;
                    150:        extern long timedelta;
                    151:        register thread_t       thread;
                    152: 
                    153:        thread = current_thread();
                    154: 
                    155: #if    SIMPLE_CLOCK
                    156:        /*
                    157:         *      Simple hardware timer does not restart on overflow, hence
                    158:         *      interrupts do not happen at a constant rate.  Must call
                    159:         *      machine-dependent routine to find out how much time has
                    160:         *      elapsed since last interrupt.
                    161:         *
                    162:         *      On NeXT we use SIMPLE_CLOCK because hardclock is called
                    163:         *      at softint0 level, and although time won't drift, there's
                    164:         *      a fair amount of "jitter". --mike
                    165:         */
                    166:        new_hardclock = clock_get_counter(System);
                    167:        delta_hardclock = new_hardclock;
                    168:        SUB_TVALSPEC(&delta_hardclock, &last_hardclock[cpu_number()]);
                    169:        myticks = (delta_hardclock.tv_sec * USEC_PER_SEC) +
                    170:                        (delta_hardclock.tv_nsec / NSEC_PER_USEC);
                    171:        last_hardclock[cpu_number()] = new_hardclock;
                    172: 
                    173:        /*
                    174:         *      NOTE: tick was #define'd to myticks above.
                    175:         */
                    176: #endif /* SIMPLE_CLOCK */
                    177:        
                    178:        /*
                    179:         * Charge the time out based on the mode the cpu is in.
                    180:         * Here again we fudge for the lack of proper interval timers
                    181:         * assuming that the current state has been around at least
                    182:         * one tick.
                    183:         */
                    184:        p = current_proc();
                    185:        if (USERMODE(ps)) {             
                    186:                if (p) {
                    187:                        if (p->p_stats->p_prof.pr_scale) {
                    188:                                p->p_flag |= P_OWEUPC;
                    189:                                ast_on(cpu_number(), AST_UNIX);
                    190:                        }
                    191:                }
                    192: 
                    193:                /*
                    194:                 * CPU was in user state.  Increment
                    195:                 * user time counter, and process process-virtual time
                    196:                 * interval timer. 
                    197:                 */
                    198:                if (timerisset(&p->p_stats->p_timer[ITIMER_VIRTUAL].it_value) &&
                    199:                    itimerdecr(&p->p_stats->p_timer[ITIMER_VIRTUAL], tick) == 0)
                    200:                        psignal(p, SIGVTALRM);
                    201:        }
                    202: 
                    203:        /*
                    204:         * If the cpu is currently scheduled to a process, then
                    205:         * charge it with resource utilization for a tick, updating
                    206:         * statistics which run in (user+system) virtual time,
                    207:         * such as the cpu time limit and profiling timers.
                    208:         * This assumes that the current process has been running
                    209:         * the entire last tick.
                    210:         */
                    211:        if (p && !(thread->state & TH_IDLE))
                    212:        {               
                    213:                if (p->p_limit->pl_rlimit[RLIMIT_CPU].rlim_cur != RLIM_INFINITY) {
                    214:                    time_value_t        sys_time, user_time;
                    215: 
                    216:                    thread_read_times(thread, &user_time, &sys_time);
                    217:                    if ((sys_time.seconds + user_time.seconds + 1) >
                    218:                        p->p_limit->pl_rlimit[RLIMIT_CPU].rlim_cur) {
                    219:                        psignal(p, SIGXCPU);
                    220:                        if (p->p_limit->pl_rlimit[RLIMIT_CPU].rlim_cur <
                    221:                            p->p_limit->pl_rlimit[RLIMIT_CPU].rlim_max)
                    222:                                p->p_limit->pl_rlimit[RLIMIT_CPU].rlim_cur += 5;
                    223:                        }
                    224:                }
                    225:                if (timerisset(&p->p_stats->p_timer[ITIMER_PROF].it_value) &&
                    226:                    itimerdecr(&p->p_stats->p_timer[ITIMER_PROF], tick) == 0)
                    227:                        psignal(p, SIGPROF);
                    228:        }
                    229: 
                    230:        /*
                    231:         * Increment the time-of-day, and schedule
                    232:         * processing of the callouts at a very low cpu priority,
                    233:         * so we don't keep the relatively high clock interrupt
                    234:         * priority any longer than necessary.
                    235:         */
                    236: 
                    237:        /*
                    238:         * Gather the statistics.
                    239:         */
                    240:        gatherstats(pc, ps);
                    241: 
                    242: #if    NCPUS > 1
                    243:        if (cpu_number() != master_cpu)
                    244:                return;
                    245: #endif /* NCPUS > 1 */
                    246: 
                    247:        if (timedelta != 0) {
                    248:                register delta;
                    249:                clock_res_t nsdelta = tickdelta * NSEC_PER_USEC;
                    250: 
                    251:                if (timedelta < 0) {
                    252:                        delta = tick - tickdelta;
                    253:                        timedelta += tickdelta;
                    254:                        nsdelta = -nsdelta;
                    255:                } else {
                    256:                        delta = tick + tickdelta;
                    257:                        timedelta -= tickdelta;
                    258:                }
                    259:                clock_adjust_counter(Calendar, nsdelta);
                    260:        }
                    261:        microtime(&time);
                    262: }
                    263: 
                    264: #if    SIMPLE_CLOCK
                    265: #undef tick
                    266: #endif /* SIMPLE_CLOCK */
                    267: 
                    268: /*
                    269:  * Gather statistics on resource utilization.
                    270:  *
                    271:  * We make a gross assumption: that the system has been in the
                    272:  * state it is in (user state, kernel state, interrupt state,
                    273:  * or idle state) for the entire last time interval, and
                    274:  * update statistics accordingly.
                    275:  */
                    276: /*ARGSUSED*/
                    277: void
                    278: gatherstats(pc, ps)
                    279:        caddr_t pc;
                    280:        int ps;
                    281: {
                    282:        register int cpstate, s;
                    283: 
                    284: #ifdef GPROF
                    285:     struct gmonparam *p = &_gmonparam;
                    286: #endif
                    287: 
                    288:        /*
                    289:         * Determine what state the cpu is in.
                    290:         */
                    291:        if (USERMODE(ps)) {
                    292:                /*
                    293:                 * CPU was in user state.
                    294:                 */
                    295:                if (current_proc()->p_nice > NZERO)
                    296:                        cpstate = CP_NICE;
                    297:                else
                    298:                        cpstate = CP_USER;
                    299:        } else {
                    300:                /*
                    301:                 * CPU was in system state.  If profiling kernel
                    302:                 * increment a counter.  If no process is running
                    303:                 * then this is a system tick if we were running
                    304:                 * at a non-zero IPL (in a driver).  If a process is running,
                    305:                 * then we charge it with system time even if we were
                    306:                 * at a non-zero IPL, since the system often runs
                    307:                 * this way during processing of system calls.
                    308:                 * This is approximate, but the lack of true interval
                    309:                 * timers makes doing anything else difficult.
                    310:                 */
                    311:                cpstate = CP_SYS;
                    312:                if ((current_thread()->state & TH_IDLE) && BASEPRI(ps))
                    313:                        cpstate = CP_IDLE;
                    314: #ifdef GPROF
                    315:                if (p->state == GMON_PROF_ON) {
                    316:                        s = pc - p->lowpc;
                    317:                        if (s < p->textsize) {
                    318:                                s /= (HISTFRACTION * sizeof(*p->kcount));
                    319:                                p->kcount[s]++;
                    320:                        }
                    321:                }
                    322: #endif
                    323:        }
                    324:        /*
                    325:         * We maintain statistics shown by user-level statistics
                    326:         * programs:  the amount of time in each cpu state, and
                    327:         * the amount of time each of DK_NDRIVE ``drives'' is busy.
                    328:         */
                    329:        cp_time[cpstate]++;
                    330:        for (s = 0; s < DK_NDRIVE; s++)
                    331:                if (dk_busy & (1 << s))
                    332:                        dk_time[s]++;
                    333: }
                    334: 
                    335: /*
                    336:  * Arrange that (*fun)(arg) is called in t/hz seconds.
                    337:  */
                    338: void
                    339: timeout(ftn, arg, ticks)
                    340:        void (*ftn) __P((void *));
                    341:        void *arg;
                    342:        register int ticks;
                    343: {
                    344:        int             s;
                    345:        tvalspec_t      deadline;
                    346:        extern
                    347:            tvalspec_t  tick_stamp;
                    348: 
                    349:        if (ticks <= 0)
                    350:                ticks = 1;
                    351: 
                    352:        s = splhigh();
                    353:        deadline = ticks_to_tvalspec(ticks);
                    354:        ADD_TVALSPEC(&deadline, &tick_stamp);
                    355: 
                    356:        thread_call_func_delayed(
                    357:                        (thread_call_func_t)ftn,
                    358:                        (thread_call_spec_t)arg, deadline);
                    359:        splx(s);
                    360: }
                    361: 
                    362: /*
                    363:  * untimeout is called to remove a function timeout call
                    364:  * from the callout structure.
                    365:  */
                    366: int
                    367: untimeout(ftn, arg)
                    368:        void (*ftn) __P((void *));
                    369:        void *arg;
                    370: {
                    371:        thread_call_func_cancel(
                    372:                        (thread_call_func_t)ftn,
                    373:                        (thread_call_spec_t)arg, FALSE);
                    374: 
                    375:        return TRUE;    /* XXX cheat */
                    376: }
                    377: 
                    378: /*
                    379:  * Compute number of hz until specified time.
                    380:  * Used to compute third argument to timeout() from an
                    381:  * absolute time.
                    382:  */
                    383: hzto(tv)
                    384:        struct timeval *tv;
                    385: {
                    386:        register long ticks;
                    387:        register long sec;
                    388:        int s = splhigh();
                    389:        
                    390:        /*
                    391:         * If number of milliseconds will fit in 32 bit arithmetic,
                    392:         * then compute number of milliseconds to time and scale to
                    393:         * ticks.  Otherwise just compute number of hz in time, rounding
                    394:         * times greater than representible to maximum value.
                    395:         *
                    396:         * Delta times less than 25 days can be computed ``exactly''.
                    397:         * Maximum value for any timeout in 10ms ticks is 250 days.
                    398:         */
                    399:        sec = tv->tv_sec - time.tv_sec;
                    400:        if (sec <= 0x7fffffff / 1000 - 1000)
                    401:                ticks = ((tv->tv_sec - time.tv_sec) * 1000 +
                    402:                        (tv->tv_usec - time.tv_usec) / 1000)
                    403:                                / (tick / 1000);
                    404:        else if (sec <= 0x7fffffff / hz)
                    405:                ticks = sec * hz;
                    406:        else
                    407:                ticks = 0x7fffffff;
                    408:        splx(s);
                    409:        return (ticks);
                    410: }
                    411: 
                    412: /*
                    413:  * Convert ticks to a timeval
                    414:  */
                    415: ticks_to_timeval(ticks, tvp)
                    416:        register long ticks;
                    417:        struct timeval *tvp;
                    418: {
                    419:        tvp->tv_sec = ticks/hz;
                    420:        tvp->tv_usec = (ticks%hz) * tick;
                    421:        ASSERT(tvp->tv_usec < 1000000);
                    422: }
                    423: 
                    424: /*
                    425:  * Return information about system clocks.
                    426:  */
                    427: int
                    428: sysctl_clockrate(where, sizep)
                    429:        register char *where;
                    430:        size_t *sizep;
                    431: {
                    432:        struct clockinfo clkinfo;
                    433: 
                    434:        /*
                    435:         * Construct clockinfo structure.
                    436:         */
                    437:        clkinfo.hz = hz;
                    438:        clkinfo.tick = tick;
                    439:        clkinfo.profhz = hz;
                    440:        clkinfo.stathz = hz;
                    441:        return (sysctl_rdstruct(where, sizep, NULL, &clkinfo, sizeof(clkinfo)));
                    442: }
                    443: 
                    444: /*
                    445:  * Start profiling on a process.
                    446:  *
                    447:  * Kernel profiling passes kernel_proc which never exits and hence
                    448:  * keeps the profile clock running constantly.
                    449:  */
                    450: void
                    451: startprofclock(p)
                    452:        register struct proc *p;
                    453: {
                    454:        if ((p->p_flag & P_PROFIL) == 0)
                    455:                p->p_flag |= P_PROFIL;
                    456: }
                    457: 
                    458: /*
                    459:  * Stop profiling on a process.
                    460:  */
                    461: void
                    462: stopprofclock(p)
                    463:        register struct proc *p;
                    464: {
                    465:        if (p->p_flag & P_PROFIL)
                    466:                p->p_flag &= ~P_PROFIL;
                    467: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.