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