xref: /original-bsd/sys/kern/kern_clock.c (revision f0fd5f8a)
1 /*	kern_clock.c	4.48	82/12/17	*/
2 
3 #include "../machine/reg.h"
4 #include "../machine/psl.h"
5 
6 #include "../h/param.h"
7 #include "../h/systm.h"
8 #include "../h/dk.h"
9 #include "../h/callout.h"
10 #include "../h/dir.h"
11 #include "../h/user.h"
12 #include "../h/kernel.h"
13 #include "../h/proc.h"
14 #include "../h/vm.h"
15 #include "../h/text.h"
16 #ifdef MUSH
17 #include "../h/quota.h"
18 #include "../h/share.h"
19 #endif
20 
21 #ifdef vax
22 #include "../vax/mtpr.h"
23 #endif
24 
25 #
26 /*
27  * Clock handling routines.
28  *
29  * This code is written for a machine with only one interval timer,
30  * and does timing and resource utilization estimation statistically
31  * based on the state of the machine hz times a second.  A machine
32  * with proper clocks (running separately in user state, system state,
33  * interrupt state and idle state) as well as a time-of-day clock
34  * would allow a non-approximate implementation.
35  */
36 
37 /*
38  * TODO:
39  *	* Keep more accurate statistics by simulating good interval timers.
40  *	* Use the time-of-day clock on the VAX to keep more accurate time
41  *	  than is possible by repeated use of the interval timer.
42  *	* Allocate more timeout table slots when table overflows.
43  */
44 
45 /* bump a timeval by a small number of usec's */
46 #define	bumptime(tp, usec) \
47 	(tp)->tv_usec += usec; \
48 	if ((tp)->tv_usec >= 1000000) { \
49 		(tp)->tv_usec -= 1000000; \
50 		(tp)->tv_sec++; \
51 	}
52 
53 /*
54  * The (single) hardware interval timer.
55  * We update the events relating to real time, and then
56  * make a gross assumption: that the system has been in the
57  * state it is in (user state, kernel state, interrupt state,
58  * or idle state) for the entire last time interval, and
59  * update statistics accordingly.
60  */
61 /*ARGSUSED*/
62 #ifdef vax
63 hardclock(pc, ps)
64 	caddr_t pc;
65 	int ps;
66 {
67 #endif
68 #ifdef sun
69 hardclock(regs)
70 	struct regs regs;
71 {
72 	int ps = regs.r_sr;
73 	caddr_t pc = (caddr_t)regs.r_pc;
74 #endif
75 	register struct callout *p1;
76 	register struct proc *p;
77 	register int s, cpstate;
78 
79 #ifdef sun
80 	if (USERMODE(ps))		/* aston needs ar0 */
81 		u.u_ar0 = &regs.r_r0;
82 #endif
83 	/*
84 	 * Update real-time timeout queue.
85 	 * At front of queue are some number of events which are ``due''.
86 	 * The time to these is <= 0 and if negative represents the
87 	 * number of ticks which have passed since it was supposed to happen.
88 	 * The rest of the q elements (times > 0) are events yet to happen,
89 	 * where the time for each is given as a delta from the previous.
90 	 * Decrementing just the first of these serves to decrement the time
91 	 * to all events.
92 	 */
93 	for (p1 = calltodo.c_next; p1 && p1->c_time <= 0; p1 = p1->c_next)
94 		--p1->c_time;
95 	if (p1)
96 		--p1->c_time;
97 
98 	/*
99 	 * If the cpu is currently scheduled to a process, then
100 	 * charge it with resource utilization for a tick, updating
101 	 * statistics which run in (user+system) virtual time,
102 	 * such as the cpu time limit and profiling timers.
103 	 * This assumes that the current process has been running
104 	 * the entire last tick.
105 	 */
106 	if (!noproc) {
107 		s = u.u_procp->p_rssize;
108 		u.u_ru.ru_idrss += s; u.u_ru.ru_isrss += 0;	/* XXX */
109 		if (u.u_procp->p_textp) {
110 			register int xrss = u.u_procp->p_textp->x_rssize;
111 
112 			s += xrss;
113 			u.u_ru.ru_ixrss += xrss;
114 		}
115 		if (s > u.u_ru.ru_maxrss)
116 			u.u_ru.ru_maxrss = s;
117 		if ((u.u_ru.ru_utime.tv_sec+u.u_ru.ru_stime.tv_sec+1) >
118 		    u.u_rlimit[RLIMIT_CPU].rlim_cur) {
119 			psignal(u.u_procp, SIGXCPU);
120 			if (u.u_rlimit[RLIMIT_CPU].rlim_cur <
121 			    u.u_rlimit[RLIMIT_CPU].rlim_max)
122 				u.u_rlimit[RLIMIT_CPU].rlim_cur += 5;
123 		}
124 		if (timerisset(&u.u_timer[ITIMER_PROF].it_value) &&
125 		    itimerdecr(&u.u_timer[ITIMER_PROF], tick) == 0)
126 			psignal(u.u_procp, SIGPROF);
127 	}
128 
129 	/*
130 	 * Charge the time out based on the mode the cpu is in.
131 	 * Here again we fudge for the lack of proper interval timers
132 	 * assuming that the current state has been around at least
133 	 * one tick.
134 	 */
135 	if (USERMODE(ps)) {
136 		/*
137 		 * CPU was in user state.  Increment
138 		 * user time counter, and process process-virtual time
139 		 * interval timer.
140 		 */
141 		bumptime(&u.u_ru.ru_utime, tick);
142 		if (timerisset(&u.u_timer[ITIMER_VIRTUAL].it_value) &&
143 		    itimerdecr(&u.u_timer[ITIMER_VIRTUAL], tick) == 0)
144 			psignal(u.u_procp, SIGVTALRM);
145 		if (u.u_procp->p_nice > NZERO)
146 			cpstate = CP_NICE;
147 		else
148 			cpstate = CP_USER;
149 	} else {
150 		/*
151 		 * CPU was in system state.  If profiling kernel
152 		 * increment a counter.  If no process is running
153 		 * then this is a system tick if we were running
154 		 * at a non-zero IPL (in a driver).  If a process is running,
155 		 * then we charge it with system time even if we were
156 		 * at a non-zero IPL, since the system often runs
157 		 * this way during processing of system calls.
158 		 * This is approximate, but the lack of true interval
159 		 * timers makes doing anything else difficult.
160 		 */
161 #ifdef GPROF
162 		int k = pc - s_lowpc;
163 		if (profiling < 2 && k < s_textsize)
164 			kcount[k / sizeof (*kcount)]++;
165 #endif
166 		cpstate = CP_SYS;
167 		if (noproc) {
168 			if (BASEPRI(ps))
169 				cpstate = CP_IDLE;
170 		} else {
171 			bumptime(&u.u_ru.ru_stime, tick);
172 		}
173 	}
174 
175 	/*
176 	 * We maintain statistics shown by user-level statistics
177 	 * programs:  the amount of time in each cpu state, and
178 	 * the amount of time each of DK_NDRIVE ``drives'' is busy.
179 	 */
180 	cp_time[cpstate]++;
181 	for (s = 0; s < DK_NDRIVE; s++)
182 		if (dk_busy&(1<<s))
183 			dk_time[s]++;
184 
185 	/*
186 	 * We adjust the priority of the current process.
187 	 * The priority of a process gets worse as it accumulates
188 	 * CPU time.  The cpu usage estimator (p_cpu) is increased here
189 	 * and the formula for computing priorities (in kern_synch.c)
190 	 * will compute a different value each time the p_cpu increases
191 	 * by 4.  The cpu usage estimator ramps up quite quickly when
192 	 * the process is running (linearly), and decays away exponentially,
193 	 * at a rate which is proportionally slower when the system is
194 	 * busy.  The basic principal is that the system will 90% forget
195 	 * that a process used a lot of CPU time in 5*loadav seconds.
196 	 * This causes the system to favor processes which haven't run
197 	 * much recently, and to round-robin among other processes.
198 	 */
199 	if (!noproc) {
200 		p = u.u_procp;
201 		p->p_cpticks++;
202 		if (++p->p_cpu == 0)
203 			p->p_cpu--;
204 #ifdef MUSH
205 		p->p_quota->q_cost += (p->p_nice > NZERO ?
206 		    (shconsts.sc_tic * ((2*NZERO)-p->p_nice)) / NZERO :
207 		    shconsts.sc_tic) * (((int)avenrun[0]+2)/3);
208 #endif
209 		if ((p->p_cpu&3) == 0) {
210 			(void) setpri(p);
211 			if (p->p_pri >= PUSER)
212 				p->p_pri = p->p_usrpri;
213 		}
214 	}
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 	bumptime(&time, tick);
223 	setsoftclock();
224 }
225 
226 /*
227  * Software priority level clock interrupt.
228  * Run periodic events from timeout queue.
229  */
230 /*ARGSUSED*/
231 #ifdef vax
232 softclock(pc, ps)
233 	caddr_t pc;
234 	int ps;
235 {
236 #endif
237 #ifdef sun
238 softclock()
239 {
240 	int ps = u.u_ar0[PS];
241 	caddr_t pc = (caddr_t)u.u_ar0[PC];
242 #endif
243 
244 	for (;;) {
245 		register struct callout *p1;
246 		register caddr_t arg;
247 		register int (*func)();
248 		register int a, s;
249 
250 		s = spl7();
251 		if ((p1 = calltodo.c_next) == 0 || p1->c_time > 0) {
252 			splx(s);
253 			break;
254 		}
255 		arg = p1->c_arg; func = p1->c_func; a = p1->c_time;
256 		calltodo.c_next = p1->c_next;
257 		p1->c_next = callfree;
258 		callfree = p1;
259 		splx(s);
260 		(*func)(arg, a);
261 	}
262 	/*
263 	 * If trapped user-mode, give it a profiling tick.
264 	 */
265 	if (USERMODE(ps) && u.u_prof.pr_scale) {
266 		u.u_procp->p_flag |= SOWEUPC;
267 		aston();
268 	}
269 }
270 
271 /*
272  * Arrange that (*fun)(arg) is called in tim/hz seconds.
273  */
274 timeout(fun, arg, tim)
275 	int (*fun)();
276 	caddr_t arg;
277 	int tim;
278 {
279 	register struct callout *p1, *p2, *pnew;
280 	register int t;
281 	int s;
282 
283 	t = tim;
284 	s = spl7();
285 	pnew = callfree;
286 	if (pnew == NULL)
287 		panic("timeout table overflow");
288 	callfree = pnew->c_next;
289 	pnew->c_arg = arg;
290 	pnew->c_func = fun;
291 	for (p1 = &calltodo; (p2 = p1->c_next) && p2->c_time < t; p1 = p2)
292 		if (p2->c_time > 0)
293 			t -= p2->c_time;
294 	p1->c_next = pnew;
295 	pnew->c_next = p2;
296 	pnew->c_time = t;
297 	if (p2)
298 		p2->c_time -= t;
299 	splx(s);
300 }
301 
302 /*
303  * untimeout is called to remove a function timeout call
304  * from the callout structure.
305  */
306 untimeout(fun, arg)
307 	int (*fun)();
308 	caddr_t arg;
309 {
310 	register struct callout *p1, *p2;
311 	register int s;
312 
313 	s = spl7();
314 	for (p1 = &calltodo; (p2 = p1->c_next) != 0; p1 = p2) {
315 		if (p2->c_func == fun && p2->c_arg == arg) {
316 			if (p2->c_next && p2->c_time > 0)
317 				p2->c_next->c_time += p2->c_time;
318 			p1->c_next = p2->c_next;
319 			p2->c_next = callfree;
320 			callfree = p2;
321 			break;
322 		}
323 	}
324 	splx(s);
325 }
326 
327 /*
328  * Compute number of hz until specified time.
329  * Used to compute third argument to timeout() from an
330  * absolute time.
331  */
332 hzto(tv)
333 	struct timeval *tv;
334 {
335 	register long ticks;
336 	register long sec;
337 	int s = spl7();
338 
339 	/*
340 	 * If number of milliseconds will fit in 32 bit arithmetic,
341 	 * then compute number of milliseconds to time and scale to
342 	 * ticks.  Otherwise just compute number of hz in time, rounding
343 	 * times greater than representible to maximum value.
344 	 *
345 	 * Delta times less than 25 days can be computed ``exactly''.
346 	 * Maximum value for any timeout in 10ms ticks is 250 days.
347 	 */
348 	sec = tv->tv_sec - time.tv_sec;
349 	if (sec <= 0x7fffffff / 1000 - 1000)
350 		ticks = ((tv->tv_sec - time.tv_sec) * 1000 +
351 			(tv->tv_usec - time.tv_usec) / 1000) / (tick / 1000);
352 	else if (sec <= 0x7fffffff / hz)
353 		ticks = sec * hz;
354 	else
355 		ticks = 0x7fffffff;
356 	splx(s);
357 	return (ticks);
358 }
359