|
|
1.1 root 1: /*-
2: * Copyright (c) 1982, 1986, 1991 The Regents of the University of California.
3: * All rights reserved.
4: *
5: * Redistribution and use in source and binary forms, with or without
6: * modification, are permitted provided that the following conditions
7: * are met:
8: * 1. Redistributions of source code must retain the above copyright
9: * notice, this list of conditions and the following disclaimer.
10: * 2. Redistributions in binary form must reproduce the above copyright
11: * notice, this list of conditions and the following disclaimer in the
12: * documentation and/or other materials provided with the distribution.
13: * 3. All advertising materials mentioning features or use of this software
14: * must display the following acknowledgement:
15: * This product includes software developed by the University of
16: * California, Berkeley and its contributors.
17: * 4. Neither the name of the University nor the names of its contributors
18: * may be used to endorse or promote products derived from this software
19: * without specific prior written permission.
20: *
21: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31: * SUCH DAMAGE.
32: *
1.1.1.4 ! root 33: * from: @(#)kern_clock.c 7.16 (Berkeley) 5/9/91
! 34: * kern_clock.c,v 1.6 1993/06/27 06:05:32 andrew Exp
1.1 root 35: */
36:
37: #include "param.h"
38: #include "systm.h"
39: #include "dkstat.h"
40: #include "callout.h"
41: #include "kernel.h"
42: #include "proc.h"
43: #include "resourcevar.h"
44:
45: #include "machine/cpu.h"
46:
47: #ifdef GPROF
48: #include "gprof.h"
49: #endif
50:
1.1.1.4 ! root 51: void gatherstats(clockframe *framep);
! 52: void softclock(clockframe frame);
! 53:
1.1 root 54: /*
55: * Clock handling routines.
56: *
57: * This code is written to operate with two timers which run
58: * independently of each other. The main clock, running at hz
59: * times per second, is used to do scheduling and timeout calculations.
60: * The second timer does resource utilization estimation statistically
61: * based on the state of the machine phz times a second. Both functions
62: * can be performed by a single clock (ie hz == phz), however the
63: * statistics will be much more prone to errors. Ideally a machine
64: * would have separate clocks measuring time spent in user state, system
65: * state, interrupt state, and idle state. These clocks would allow a non-
66: * approximate measure of resource utilization.
67: */
68:
69: /*
70: * TODO:
71: * time of day, system/user timing, timeouts, profiling on separate timers
72: * allocate more timeout table slots when table overflows.
73: */
74:
75: /*
76: * Bump a timeval by a small number of usec's.
77: */
78: #define BUMPTIME(t, usec) { \
79: register struct timeval *tp = (t); \
80: \
81: tp->tv_usec += (usec); \
82: if (tp->tv_usec >= 1000000) { \
83: tp->tv_usec -= 1000000; \
84: tp->tv_sec++; \
85: } \
86: }
87:
88: /*
89: * The hz hardware interval timer.
90: * We update the events relating to real time.
91: * If this timer is also being used to gather statistics,
92: * we run through the statistics gathering routine as well.
93: */
1.1.1.4 ! root 94: void hardclock(frame)
1.1 root 95: clockframe frame;
96: {
97: register struct callout *p1;
98: register struct proc *p = curproc;
99: int needsoft = 0;
100: extern int tickdelta;
101: extern long timedelta;
102:
103: /*
104: * Update real-time timeout queue.
105: * At front of queue are some number of events which are ``due''.
106: * The time to these is <= 0 and if negative represents the
107: * number of ticks which have passed since it was supposed to happen.
108: * The rest of the q elements (times > 0) are events yet to happen,
109: * where the time for each is given as a delta from the previous.
110: * Decrementing just the first of these serves to decrement the time
111: * to all events.
112: */
113: p1 = calltodo.c_next;
114: while (p1) {
115: if (--p1->c_time > 0)
116: break;
117: needsoft = 1;
118: if (p1->c_time == 0)
119: break;
120: p1 = p1->c_next;
121: }
122:
123: /*
124: * Curproc (now in p) is null if no process is running.
125: * We assume that curproc is set in user mode!
126: */
1.1.1.4 ! root 127: if (p) {
! 128: struct pstats *pstats = p->p_stats;
! 129: long secs;
! 130:
1.1 root 131: /*
1.1.1.4 ! root 132: * Charge the time out based on the mode the cpu is in.
! 133: * Here again we fudge for the lack of proper interval timers
! 134: * assuming that the current state has been around at least
! 135: * one tick.
1.1 root 136: */
1.1.1.4 ! root 137: if (CLKF_USERMODE(&frame)) {
! 138: if (pstats->p_prof.pr_scale)
! 139: needsoft = 1;
! 140: /*
! 141: * CPU was in user state. Increment
! 142: * user time counter, and process process-virtual time
! 143: * interval timer.
! 144: */
! 145: BUMPTIME(&p->p_utime, tick);
! 146: if (timerisset(&pstats->p_timer[ITIMER_VIRTUAL].it_value) &&
! 147: itimerdecr(&pstats->p_timer[ITIMER_VIRTUAL], tick) == 0)
! 148: psignal(p, SIGVTALRM);
! 149: } else {
! 150: /*
! 151: * CPU was in system state.
! 152: */
! 153: BUMPTIME(&p->p_stime, tick);
! 154: }
! 155:
1.1 root 156: /*
1.1.1.4 ! root 157: * If the cpu is currently scheduled to a process, then
! 158: * charge it with resource utilization for a tick, updating
! 159: * statistics which run in (user+system) virtual time,
! 160: * such as the cpu time limit and profiling timers.
! 161: * This assumes that the current process has been running
! 162: * the entire last tick.
1.1 root 163: */
1.1.1.4 ! root 164: secs = p->p_utime.tv_sec + p->p_stime.tv_sec + 1;
1.1 root 165:
1.1.1.4 ! root 166: if (secs > p->p_rlimit[RLIMIT_CPU].rlim_cur) {
! 167: if (secs > p->p_rlimit[RLIMIT_CPU].rlim_max)
! 168: psignal(p, SIGKILL);
! 169: else
! 170: psignal(p, SIGXCPU);
1.1 root 171: if (p->p_rlimit[RLIMIT_CPU].rlim_cur <
172: p->p_rlimit[RLIMIT_CPU].rlim_max)
173: p->p_rlimit[RLIMIT_CPU].rlim_cur += 5;
174: }
175: if (timerisset(&pstats->p_timer[ITIMER_PROF].it_value) &&
176: itimerdecr(&pstats->p_timer[ITIMER_PROF], tick) == 0)
177: psignal(p, SIGPROF);
178:
179: /*
180: * We adjust the priority of the current process.
181: * The priority of a process gets worse as it accumulates
182: * CPU time. The cpu usage estimator (p_cpu) is increased here
183: * and the formula for computing priorities (in kern_synch.c)
184: * will compute a different value each time the p_cpu increases
185: * by 4. The cpu usage estimator ramps up quite quickly when
186: * the process is running (linearly), and decays away
187: * exponentially, * at a rate which is proportionally slower
188: * when the system is busy. The basic principal is that the
189: * system will 90% forget that a process used a lot of CPU
190: * time in 5*loadav seconds. This causes the system to favor
191: * processes which haven't run much recently, and to
192: * round-robin among other processes.
193: */
194: p->p_cpticks++;
195: if (++p->p_cpu == 0)
196: p->p_cpu--;
197: if ((p->p_cpu&3) == 0) {
198: setpri(p);
199: if (p->p_pri >= PUSER)
200: p->p_pri = p->p_usrpri;
201: }
202: }
203:
204: /*
205: * If the alternate clock has not made itself known then
206: * we must gather the statistics.
207: */
208: if (phz == 0)
209: gatherstats(&frame);
210:
211: /*
212: * Increment the time-of-day, and schedule
213: * processing of the callouts at a very low cpu priority,
214: * so we don't keep the relatively high clock interrupt
215: * priority any longer than necessary.
216: */
217: if (timedelta == 0)
218: BUMPTIME(&time, tick)
219: else {
220: register delta;
221:
222: if (timedelta < 0) {
223: delta = tick - tickdelta;
224: timedelta += tickdelta;
225: } else {
226: delta = tick + tickdelta;
227: timedelta -= tickdelta;
228: }
229: BUMPTIME(&time, delta);
230: }
1.1.1.3 root 231: #ifdef DCFCLK
1.1.1.4 ! root 232: /* XXX (cgd)
1.1.1.3 root 233: * This is lousy, but until I can get the $&^%&^(!!! signal onto one
234: * of the interrupt's I'll have to poll it. No, it will not work if
235: * you attempt -DHZ=1000, things break.
236: * But keep the NDCFCLK low, to avoid waste of cycles...
237: * [email protected]
238: */
239: dcfclk_worker();
240: #endif
1.1 root 241: if (needsoft) {
1.1.1.4 ! root 242: #ifndef i386 /* XXX -- nasty! (cgd) */
1.1 root 243: if (CLKF_BASEPRI(&frame)) {
244: /*
245: * Save the overhead of a software interrupt;
246: * it will happen as soon as we return, so do it now.
247: */
248: (void) splsoftclock();
249: softclock(frame);
250: } else
1.1.1.4 ! root 251: #endif
1.1 root 252: setsoftclock();
253: }
254: }
255:
256: int dk_ndrive = DK_NDRIVE;
257: /*
258: * Gather statistics on resource utilization.
259: *
260: * We make a gross assumption: that the system has been in the
261: * state it is in (user state, kernel state, interrupt state,
262: * or idle state) for the entire last time interval, and
263: * update statistics accordingly.
264: */
1.1.1.4 ! root 265: void
1.1 root 266: gatherstats(framep)
267: clockframe *framep;
268: {
269: register int cpstate, s;
270:
271: /*
272: * Determine what state the cpu is in.
273: */
274: if (CLKF_USERMODE(framep)) {
275: /*
276: * CPU was in user state.
277: */
278: if (curproc->p_nice > NZERO)
279: cpstate = CP_NICE;
280: else
281: cpstate = CP_USER;
282: } else {
283: /*
284: * CPU was in system state. If profiling kernel
285: * increment a counter. If no process is running
286: * then this is a system tick if we were running
287: * at a non-zero IPL (in a driver). If a process is running,
288: * then we charge it with system time even if we were
289: * at a non-zero IPL, since the system often runs
290: * this way during processing of system calls.
291: * This is approximate, but the lack of true interval
292: * timers makes doing anything else difficult.
293: */
294: cpstate = CP_SYS;
295: if (curproc == NULL && CLKF_BASEPRI(framep))
296: cpstate = CP_IDLE;
297: #ifdef GPROF
1.1.1.2 root 298: s = (u_long) CLKF_PC(framep) - (u_long) s_lowpc;
1.1 root 299: if (profiling < 2 && s < s_textsize)
300: kcount[s / (HISTFRACTION * sizeof (*kcount))]++;
301: #endif
302: }
303: /*
304: * We maintain statistics shown by user-level statistics
305: * programs: the amount of time in each cpu state, and
306: * the amount of time each of DK_NDRIVE ``drives'' is busy.
307: */
308: cp_time[cpstate]++;
309: for (s = 0; s < DK_NDRIVE; s++)
310: if (dk_busy&(1<<s))
311: dk_time[s]++;
312: }
313:
314: /*
315: * Software priority level clock interrupt.
316: * Run periodic events from timeout queue.
317: */
318: /*ARGSUSED*/
1.1.1.4 ! root 319: void
1.1 root 320: softclock(frame)
321: clockframe frame;
322: {
323:
324: for (;;) {
325: register struct callout *p1;
326: register caddr_t arg;
1.1.1.4 ! root 327: register timeout_t func;
1.1 root 328: register int a, s;
329:
330: s = splhigh();
331: if ((p1 = calltodo.c_next) == 0 || p1->c_time > 0) {
332: splx(s);
333: break;
334: }
335: arg = p1->c_arg; func = p1->c_func; a = p1->c_time;
336: calltodo.c_next = p1->c_next;
337: p1->c_next = callfree;
338: callfree = p1;
339: splx(s);
1.1.1.4 ! root 340: #ifndef old_timeout_func
! 341: (*func)(arg); /* new-style doesn't cause ANSI headaches */
! 342: #else
1.1 root 343: (*func)(arg, a);
1.1.1.4 ! root 344: #endif
1.1 root 345: }
1.1.1.2 root 346:
347: /*
348: * If no process to work with, we're finished.
349: */
350: if (curproc == 0) return;
351:
1.1 root 352: /*
353: * If trapped user-mode and profiling, give it
354: * a profiling tick.
355: */
356: if (CLKF_USERMODE(&frame)) {
357: register struct proc *p = curproc;
358:
359: if (p->p_stats->p_prof.pr_scale)
360: profile_tick(p, &frame);
361: /*
362: * Check to see if process has accumulated
363: * more than 10 minutes of user time. If so
364: * reduce priority to give others a chance.
365: */
366: if (p->p_ucred->cr_uid && p->p_nice == NZERO &&
367: p->p_utime.tv_sec > 10 * 60) {
368: p->p_nice = NZERO + 4;
369: setpri(p);
370: p->p_pri = p->p_usrpri;
371: }
372: }
373: }
374:
375: /*
1.1.1.4 ! root 376: * Arrange that (*func)(arg, ticks) is called in t/hz seconds.
1.1 root 377: */
1.1.1.4 ! root 378: void
1.1 root 379: timeout(func, arg, t)
1.1.1.4 ! root 380: timeout_t func;
1.1 root 381: caddr_t arg;
382: register int t;
383: {
384: register struct callout *p1, *p2, *pnew;
385: register int s = splhigh();
386:
387: if (t <= 0)
388: t = 1;
389: pnew = callfree;
390: if (pnew == NULL)
391: panic("timeout table overflow");
392: callfree = pnew->c_next;
393: pnew->c_arg = arg;
394: pnew->c_func = func;
395: for (p1 = &calltodo; (p2 = p1->c_next) && p2->c_time < t; p1 = p2)
396: if (p2->c_time > 0)
397: t -= p2->c_time;
398: p1->c_next = pnew;
399: pnew->c_next = p2;
400: pnew->c_time = t;
401: if (p2)
402: p2->c_time -= t;
403: splx(s);
404: }
405:
406: /*
407: * untimeout is called to remove a function timeout call
408: * from the callout structure.
409: */
1.1.1.4 ! root 410: void
1.1 root 411: untimeout(func, arg)
1.1.1.4 ! root 412: timeout_t func;
1.1 root 413: caddr_t arg;
414: {
415: register struct callout *p1, *p2;
416: register int s;
417:
418: s = splhigh();
419: for (p1 = &calltodo; (p2 = p1->c_next) != 0; p1 = p2) {
420: if (p2->c_func == func && p2->c_arg == arg) {
421: if (p2->c_next && p2->c_time > 0)
422: p2->c_next->c_time += p2->c_time;
423: p1->c_next = p2->c_next;
424: p2->c_next = callfree;
425: callfree = p2;
426: break;
427: }
428: }
429: splx(s);
430: }
431:
432: /*
433: * Compute number of hz until specified time.
434: * Used to compute third argument to timeout() from an
435: * absolute time.
436: */
1.1.1.4 ! root 437: int
1.1 root 438: hzto(tv)
439: struct timeval *tv;
440: {
441: register long ticks;
442: register long sec;
443: int s = splhigh();
444:
445: /*
446: * If number of milliseconds will fit in 32 bit arithmetic,
447: * then compute number of milliseconds to time and scale to
448: * ticks. Otherwise just compute number of hz in time, rounding
449: * times greater than representible to maximum value.
450: *
451: * Delta times less than 25 days can be computed ``exactly''.
452: * Maximum value for any timeout in 10ms ticks is 250 days.
453: */
454: sec = tv->tv_sec - time.tv_sec;
455: if (sec <= 0x7fffffff / 1000 - 1000)
456: ticks = ((tv->tv_sec - time.tv_sec) * 1000 +
457: (tv->tv_usec - time.tv_usec) / 1000) / (tick / 1000);
458: else if (sec <= 0x7fffffff / hz)
459: ticks = sec * hz;
460: else
461: ticks = 0x7fffffff;
462: splx(s);
463: return (ticks);
464: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.