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