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