Annotation of 43BSDReno/sys/kern/kern_clock.c, revision 1.1

1.1     ! root        1: /*
        !             2:  * Copyright (c) 1982, 1986 Regents of the University of California.
        !             3:  * All rights reserved.  The Berkeley software License Agreement
        !             4:  * specifies the terms and conditions for redistribution.
        !             5:  *
        !             6:  *     @(#)kern_clock.c        7.10 (Berkeley) 6/30/90
        !             7:  */
        !             8: 
        !             9: #include "param.h"
        !            10: #include "systm.h"
        !            11: #include "dkstat.h"
        !            12: #include "callout.h"
        !            13: #include "user.h"
        !            14: #include "kernel.h"
        !            15: #include "proc.h"
        !            16: #include "vm.h"
        !            17: #include "text.h"
        !            18: 
        !            19: #include "machine/reg.h"
        !            20: #include "machine/psl.h"
        !            21: 
        !            22: #if defined(vax) || defined(tahoe)
        !            23: #include "machine/mtpr.h"
        !            24: #include "machine/clock.h"
        !            25: #endif
        !            26: #if defined(hp300)
        !            27: #include "machine/mtpr.h"
        !            28: #endif
        !            29: #ifdef i386
        !            30: #include "machine/frame.h"
        !            31: #include "machine/segments.h"
        !            32: #endif
        !            33: 
        !            34: #ifdef GPROF
        !            35: #include "gprof.h"
        !            36: #endif
        !            37: 
        !            38: /*
        !            39:  * Clock handling routines.
        !            40:  *
        !            41:  * This code is written to operate with two timers which run
        !            42:  * independently of each other. The main clock, running at hz
        !            43:  * times per second, is used to do scheduling and timeout calculations.
        !            44:  * The second timer does resource utilization estimation statistically
        !            45:  * based on the state of the machine phz times a second. Both functions
        !            46:  * can be performed by a single clock (ie hz == phz), however the 
        !            47:  * statistics will be much more prone to errors. Ideally a machine
        !            48:  * would have separate clocks measuring time spent in user state, system
        !            49:  * state, interrupt state, and idle state. These clocks would allow a non-
        !            50:  * approximate measure of resource utilization.
        !            51:  */
        !            52: 
        !            53: /*
        !            54:  * TODO:
        !            55:  *     time of day, system/user timing, timeouts, profiling on separate timers
        !            56:  *     allocate more timeout table slots when table overflows.
        !            57:  */
        !            58: 
        !            59: /*
        !            60:  * Bump a timeval by a small number of usec's.
        !            61:  */
        !            62: #define BUMPTIME(t, usec) { \
        !            63:        register struct timeval *tp = (t); \
        !            64:  \
        !            65:        tp->tv_usec += (usec); \
        !            66:        if (tp->tv_usec >= 1000000) { \
        !            67:                tp->tv_usec -= 1000000; \
        !            68:                tp->tv_sec++; \
        !            69:        } \
        !            70: }
        !            71: 
        !            72: /*
        !            73:  * The hz hardware interval timer.
        !            74:  * We update the events relating to real time.
        !            75:  * If this timer is also being used to gather statistics,
        !            76:  * we run through the statistics gathering routine as well.
        !            77:  */
        !            78: /*ARGSUSED*/
        !            79: #ifndef i386
        !            80: hardclock(pc, ps)
        !            81:        caddr_t pc;
        !            82:        int ps;
        !            83: #else
        !            84: hardclock(frame)
        !            85:        struct intrframe frame;
        !            86: #define        pc      frame.if_eip
        !            87: #endif
        !            88: {
        !            89:        register struct callout *p1;
        !            90:        register struct proc *p = u.u_procp;
        !            91:        register int s;
        !            92:        int needsoft = 0;
        !            93:        extern int tickdelta;
        !            94:        extern long timedelta;
        !            95: 
        !            96:        /*
        !            97:         * Update real-time timeout queue.
        !            98:         * At front of queue are some number of events which are ``due''.
        !            99:         * The time to these is <= 0 and if negative represents the
        !           100:         * number of ticks which have passed since it was supposed to happen.
        !           101:         * The rest of the q elements (times > 0) are events yet to happen,
        !           102:         * where the time for each is given as a delta from the previous.
        !           103:         * Decrementing just the first of these serves to decrement the time
        !           104:         * to all events.
        !           105:         */
        !           106:        p1 = calltodo.c_next;
        !           107:        while (p1) {
        !           108:                if (--p1->c_time > 0)
        !           109:                        break;
        !           110:                needsoft = 1;
        !           111:                if (p1->c_time == 0)
        !           112:                        break;
        !           113:                p1 = p1->c_next;
        !           114:        }
        !           115: 
        !           116:        /*
        !           117:         * Charge the time out based on the mode the cpu is in.
        !           118:         * Here again we fudge for the lack of proper interval timers
        !           119:         * assuming that the current state has been around at least
        !           120:         * one tick.
        !           121:         */
        !           122: #ifdef i386
        !           123:        if (ISPL(frame.if_cs) == SEL_UPL) {
        !           124: #else
        !           125:        if (USERMODE(ps)) {
        !           126: #endif
        !           127:                if (u.u_prof.pr_scale)
        !           128:                        needsoft = 1;
        !           129:                /*
        !           130:                 * CPU was in user state.  Increment
        !           131:                 * user time counter, and process process-virtual time
        !           132:                 * interval timer. 
        !           133:                 */
        !           134:                BUMPTIME(&p->p_utime, tick);
        !           135:                if (timerisset(&u.u_timer[ITIMER_VIRTUAL].it_value) &&
        !           136:                    itimerdecr(&u.u_timer[ITIMER_VIRTUAL], tick) == 0)
        !           137:                        psignal(p, SIGVTALRM);
        !           138:        } else {
        !           139:                /*
        !           140:                 * CPU was in system state.
        !           141:                 */
        !           142:                if (!noproc)
        !           143:                        BUMPTIME(&p->p_stime, tick);
        !           144:        }
        !           145: 
        !           146:        /*
        !           147:         * If the cpu is currently scheduled to a process, then
        !           148:         * charge it with resource utilization for a tick, updating
        !           149:         * statistics which run in (user+system) virtual time,
        !           150:         * such as the cpu time limit and profiling timers.
        !           151:         * This assumes that the current process has been running
        !           152:         * the entire last tick.
        !           153:         */
        !           154:        if (noproc == 0) {
        !           155:                if ((p->p_utime.tv_sec+p->p_stime.tv_sec+1) >
        !           156:                    u.u_rlimit[RLIMIT_CPU].rlim_cur) {
        !           157:                        psignal(p, SIGXCPU);
        !           158:                        if (u.u_rlimit[RLIMIT_CPU].rlim_cur <
        !           159:                            u.u_rlimit[RLIMIT_CPU].rlim_max)
        !           160:                                u.u_rlimit[RLIMIT_CPU].rlim_cur += 5;
        !           161:                }
        !           162:                if (timerisset(&u.u_timer[ITIMER_PROF].it_value) &&
        !           163:                    itimerdecr(&u.u_timer[ITIMER_PROF], tick) == 0)
        !           164:                        psignal(p, SIGPROF);
        !           165:                s = p->p_rssize;
        !           166:                u.u_ru.ru_idrss += s;
        !           167: #ifdef notdef
        !           168:                u.u_ru.ru_isrss += 0;           /* XXX (haven't got this) */
        !           169: #endif
        !           170:                if (p->p_textp) {
        !           171:                        register int xrss = p->p_textp->x_rssize;
        !           172: 
        !           173:                        s += xrss;
        !           174:                        u.u_ru.ru_ixrss += xrss;
        !           175:                }
        !           176:                if (s > u.u_ru.ru_maxrss)
        !           177:                        u.u_ru.ru_maxrss = s;
        !           178:        }
        !           179: 
        !           180:        /*
        !           181:         * We adjust the priority of the current process.
        !           182:         * The priority of a process gets worse as it accumulates
        !           183:         * CPU time.  The cpu usage estimator (p_cpu) is increased here
        !           184:         * and the formula for computing priorities (in kern_synch.c)
        !           185:         * will compute a different value each time the p_cpu increases
        !           186:         * by 4.  The cpu usage estimator ramps up quite quickly when
        !           187:         * the process is running (linearly), and decays away exponentially,
        !           188:         * at a rate which is proportionally slower when the system is
        !           189:         * busy.  The basic principal is that the system will 90% forget
        !           190:         * that a process used a lot of CPU time in 5*loadav seconds.
        !           191:         * This causes the system to favor processes which haven't run
        !           192:         * much recently, and to round-robin among other processes.
        !           193:         */
        !           194:        if (!noproc) {
        !           195:                p->p_cpticks++;
        !           196:                if (++p->p_cpu == 0)
        !           197:                        p->p_cpu--;
        !           198:                if ((p->p_cpu&3) == 0) {
        !           199:                        (void) setpri(p);
        !           200:                        if (p->p_pri >= PUSER)
        !           201:                                p->p_pri = p->p_usrpri;
        !           202:                }
        !           203:        }
        !           204: 
        !           205:        /*
        !           206:         * If the alternate clock has not made itself known then
        !           207:         * we must gather the statistics.
        !           208:         */
        !           209:        if (phz == 0)
        !           210: #ifdef i386
        !           211:                gatherstats(pc, ISPL(frame.if_cs), frame.if_ppl);
        !           212: #else
        !           213:                gatherstats(pc, ps);
        !           214: #endif
        !           215: 
        !           216:        /*
        !           217:         * Increment the time-of-day, and schedule
        !           218:         * processing of the callouts at a very low cpu priority,
        !           219:         * so we don't keep the relatively high clock interrupt
        !           220:         * priority any longer than necessary.
        !           221:         */
        !           222:        if (timedelta == 0)
        !           223:                BUMPTIME(&time, tick)
        !           224:        else {
        !           225:                register delta;
        !           226: 
        !           227:                if (timedelta < 0) {
        !           228:                        delta = tick - tickdelta;
        !           229:                        timedelta += tickdelta;
        !           230:                } else {
        !           231:                        delta = tick + tickdelta;
        !           232:                        timedelta -= tickdelta;
        !           233:                }
        !           234:                BUMPTIME(&time, delta);
        !           235:        }
        !           236:        if (needsoft) {
        !           237: #ifdef i386
        !           238:                if (frame.if_ppl == 0) {
        !           239: #else
        !           240:                if (BASEPRI(ps)) {
        !           241: #endif
        !           242:                        /*
        !           243:                         * Save the overhead of a software interrupt;
        !           244:                         * it will happen as soon as we return, so do it now.
        !           245:                         */
        !           246:                        (void) splsoftclock();
        !           247: #ifdef i386
        !           248:                        softclock(frame);
        !           249: #else
        !           250:                        softclock(pc, ps);
        !           251: #endif
        !           252:                } else
        !           253:                        setsoftclock();
        !           254:        }
        !           255: }
        !           256: 
        !           257: int    dk_ndrive = DK_NDRIVE;
        !           258: /*
        !           259:  * Gather statistics on resource utilization.
        !           260:  *
        !           261:  * We make a gross assumption: that the system has been in the
        !           262:  * state it is in (user state, kernel state, interrupt state,
        !           263:  * or idle state) for the entire last time interval, and
        !           264:  * update statistics accordingly.
        !           265:  */
        !           266: /*ARGSUSED*/
        !           267: #ifdef i386
        !           268: #undef pc
        !           269: gatherstats(pc, ps, ppl)
        !           270: #else
        !           271: gatherstats(pc, ps)
        !           272: #endif
        !           273:        caddr_t pc;
        !           274:        int ps;
        !           275: {
        !           276:        register int cpstate, s;
        !           277: 
        !           278:        /*
        !           279:         * Determine what state the cpu is in.
        !           280:         */
        !           281: #ifdef i386
        !           282:        if (ps == SEL_UPL) {
        !           283: #else
        !           284:        if (USERMODE(ps)) {
        !           285: #endif
        !           286:                /*
        !           287:                 * CPU was in user state.
        !           288:                 */
        !           289:                if (u.u_procp->p_nice > NZERO)
        !           290:                        cpstate = CP_NICE;
        !           291:                else
        !           292:                        cpstate = CP_USER;
        !           293:        } else {
        !           294:                /*
        !           295:                 * CPU was in system state.  If profiling kernel
        !           296:                 * increment a counter.  If no process is running
        !           297:                 * then this is a system tick if we were running
        !           298:                 * at a non-zero IPL (in a driver).  If a process is running,
        !           299:                 * then we charge it with system time even if we were
        !           300:                 * at a non-zero IPL, since the system often runs
        !           301:                 * this way during processing of system calls.
        !           302:                 * This is approximate, but the lack of true interval
        !           303:                 * timers makes doing anything else difficult.
        !           304:                 */
        !           305:                cpstate = CP_SYS;
        !           306: #if defined(i386)
        !           307:                if (noproc && ps == 0)
        !           308: #else
        !           309:                if (noproc && BASEPRI(ps))
        !           310: #endif
        !           311:                        cpstate = CP_IDLE;
        !           312: #ifdef GPROF
        !           313:                s = pc - s_lowpc;
        !           314:                if (profiling < 2 && s < s_textsize)
        !           315:                        kcount[s / (HISTFRACTION * sizeof (*kcount))]++;
        !           316: #endif
        !           317:        }
        !           318:        /*
        !           319:         * We maintain statistics shown by user-level statistics
        !           320:         * programs:  the amount of time in each cpu state, and
        !           321:         * the amount of time each of DK_NDRIVE ``drives'' is busy.
        !           322:         */
        !           323:        cp_time[cpstate]++;
        !           324:        for (s = 0; s < DK_NDRIVE; s++)
        !           325:                if (dk_busy&(1<<s))
        !           326:                        dk_time[s]++;
        !           327: }
        !           328: 
        !           329: /*
        !           330:  * Software priority level clock interrupt.
        !           331:  * Run periodic events from timeout queue.
        !           332:  */
        !           333: /*ARGSUSED*/
        !           334: #ifdef i386
        !           335: softclock(frame)
        !           336:        struct  intrframe frame;
        !           337: #define        pc      frame.if_eip
        !           338: #else
        !           339: softclock(pc, ps)
        !           340:        caddr_t pc;
        !           341:        int ps;
        !           342: #endif
        !           343: {
        !           344: 
        !           345:        for (;;) {
        !           346:                register struct callout *p1;
        !           347:                register caddr_t arg;
        !           348:                register int (*func)();
        !           349:                register int a, s;
        !           350: 
        !           351:                s = splhigh();
        !           352:                if ((p1 = calltodo.c_next) == 0 || p1->c_time > 0) {
        !           353:                        splx(s);
        !           354:                        break;
        !           355:                }
        !           356:                arg = p1->c_arg; func = p1->c_func; a = p1->c_time;
        !           357:                calltodo.c_next = p1->c_next;
        !           358:                p1->c_next = callfree;
        !           359:                callfree = p1;
        !           360:                splx(s);
        !           361:                (*func)(arg, a);
        !           362:        }
        !           363:        /*
        !           364:         * If trapped user-mode and profiling, give it
        !           365:         * a profiling tick.
        !           366:         */
        !           367: #ifdef i386
        !           368:        if (ISPL(frame.if_cs) == SEL_UPL) {
        !           369: #else
        !           370:        if (USERMODE(ps)) {
        !           371: #endif
        !           372:                register struct proc *p = u.u_procp;
        !           373: 
        !           374:                if (u.u_prof.pr_scale) {
        !           375:                        p->p_flag |= SOWEUPC;
        !           376:                        aston();
        !           377:                }
        !           378:                /*
        !           379:                 * Check to see if process has accumulated
        !           380:                 * more than 10 minutes of user time.  If so
        !           381:                 * reduce priority to give others a chance.
        !           382:                 */
        !           383:                if (p->p_uid && p->p_nice == NZERO &&
        !           384:                    p->p_utime.tv_sec > 10 * 60) {
        !           385:                        p->p_nice = NZERO+4;
        !           386:                        (void) setpri(p);
        !           387:                        p->p_pri = p->p_usrpri;
        !           388:                }
        !           389:        }
        !           390: }
        !           391: 
        !           392: /*
        !           393:  * Arrange that (*fun)(arg) is called in t/hz seconds.
        !           394:  */
        !           395: timeout(fun, arg, t)
        !           396:        int (*fun)();
        !           397:        caddr_t arg;
        !           398:        register int t;
        !           399: {
        !           400:        register struct callout *p1, *p2, *pnew;
        !           401:        register int s = splhigh();
        !           402: 
        !           403:        if (t <= 0)
        !           404:                t = 1;
        !           405:        pnew = callfree;
        !           406:        if (pnew == NULL)
        !           407:                panic("timeout table overflow");
        !           408:        callfree = pnew->c_next;
        !           409:        pnew->c_arg = arg;
        !           410:        pnew->c_func = fun;
        !           411:        for (p1 = &calltodo; (p2 = p1->c_next) && p2->c_time < t; p1 = p2)
        !           412:                if (p2->c_time > 0)
        !           413:                        t -= p2->c_time;
        !           414:        p1->c_next = pnew;
        !           415:        pnew->c_next = p2;
        !           416:        pnew->c_time = t;
        !           417:        if (p2)
        !           418:                p2->c_time -= t;
        !           419:        splx(s);
        !           420: }
        !           421: 
        !           422: /*
        !           423:  * untimeout is called to remove a function timeout call
        !           424:  * from the callout structure.
        !           425:  */
        !           426: untimeout(fun, arg)
        !           427:        int (*fun)();
        !           428:        caddr_t arg;
        !           429: {
        !           430:        register struct callout *p1, *p2;
        !           431:        register int s;
        !           432: 
        !           433:        s = splhigh();
        !           434:        for (p1 = &calltodo; (p2 = p1->c_next) != 0; p1 = p2) {
        !           435:                if (p2->c_func == fun && p2->c_arg == arg) {
        !           436:                        if (p2->c_next && p2->c_time > 0)
        !           437:                                p2->c_next->c_time += p2->c_time;
        !           438:                        p1->c_next = p2->c_next;
        !           439:                        p2->c_next = callfree;
        !           440:                        callfree = p2;
        !           441:                        break;
        !           442:                }
        !           443:        }
        !           444:        splx(s);
        !           445: }
        !           446: 
        !           447: /*
        !           448:  * Compute number of hz until specified time.
        !           449:  * Used to compute third argument to timeout() from an
        !           450:  * absolute time.
        !           451:  */
        !           452: hzto(tv)
        !           453:        struct timeval *tv;
        !           454: {
        !           455:        register long ticks;
        !           456:        register long sec;
        !           457:        int s = splhigh();
        !           458: 
        !           459:        /*
        !           460:         * If number of milliseconds will fit in 32 bit arithmetic,
        !           461:         * then compute number of milliseconds to time and scale to
        !           462:         * ticks.  Otherwise just compute number of hz in time, rounding
        !           463:         * times greater than representible to maximum value.
        !           464:         *
        !           465:         * Delta times less than 25 days can be computed ``exactly''.
        !           466:         * Maximum value for any timeout in 10ms ticks is 250 days.
        !           467:         */
        !           468:        sec = tv->tv_sec - time.tv_sec;
        !           469:        if (sec <= 0x7fffffff / 1000 - 1000)
        !           470:                ticks = ((tv->tv_sec - time.tv_sec) * 1000 +
        !           471:                        (tv->tv_usec - time.tv_usec) / 1000) / (tick / 1000);
        !           472:        else if (sec <= 0x7fffffff / hz)
        !           473:                ticks = sec * hz;
        !           474:        else
        !           475:                ticks = 0x7fffffff;
        !           476:        splx(s);
        !           477:        return (ticks);
        !           478: }
        !           479: 
        !           480: /* ARGSUSED */
        !           481: profil(p, uap, retval)
        !           482:        struct proc *p;
        !           483:        register struct args {
        !           484:                short   *bufbase;
        !           485:                unsigned bufsize;
        !           486:                unsigned pcoffset;
        !           487:                unsigned pcscale;
        !           488:        } *uap;
        !           489:        int *retval;
        !           490: {
        !           491:        register struct uprof *upp = &u.u_prof;
        !           492: 
        !           493:        upp->pr_base = uap->bufbase;
        !           494:        upp->pr_size = uap->bufsize;
        !           495:        upp->pr_off = uap->pcoffset;
        !           496:        upp->pr_scale = uap->pcscale;
        !           497:        return (0);
        !           498: }

unix.superglobalmegacorp.com

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