xref: /csrg-svn/sys/kern/kern_clock.c (revision 8944)
1*8944Sroot /*	kern_clock.c	4.43	82/10/30	*/
29Sbill 
39Sbill #include "../h/param.h"
49Sbill #include "../h/systm.h"
5329Sbill #include "../h/dk.h"
62768Swnj #include "../h/callout.h"
79Sbill #include "../h/dir.h"
89Sbill #include "../h/user.h"
98028Sroot #include "../h/kernel.h"
109Sbill #include "../h/proc.h"
119Sbill #include "../h/psl.h"
129Sbill #include "../h/vm.h"
139Sbill #include "../h/text.h"
147490Skre #ifdef MUSH
157490Skre #include "../h/quota.h"
167490Skre #include "../h/share.h"
177490Skre #endif
189Sbill 
198124Sroot /*
208124Sroot  * Clock handling routines.
218124Sroot  *
228124Sroot  * This code is written for a machine with only one interval timer,
238124Sroot  * and does timing and resource utilization estimation statistically
248124Sroot  * based on the state of the machine hz times a second.  A machine
258124Sroot  * with proper clocks (running separately in user state, system state,
268124Sroot  * interrupt state and idle state) as well as a time-of-day clock
278124Sroot  * would allow a non-approximate implementation.
288124Sroot  */
291559Sbill 
308124Sroot /*
318124Sroot  * TODO:
328124Sroot  *	* Keep more accurate statistics by simulating good interval timers.
338124Sroot  *	* Use the time-of-day clock on the VAX to keep more accurate time
348124Sroot  *	  than is possible by repeated use of the interval timer.
358124Sroot  *	* Allocate more timeout table slots when table overflows.
368124Sroot  */
379Sbill 
388124Sroot /* bump a timeval by a small number of usec's */
398124Sroot #define	bumptime(tp, usec) \
408124Sroot 	(tp)->tv_usec += usec; \
418097Sroot 	if ((tp)->tv_usec >= 1000000) { \
428097Sroot 		(tp)->tv_usec -= 1000000; \
438097Sroot 		(tp)->tv_sec++; \
448097Sroot 	}
455247Sroot 
468124Sroot /*
478124Sroot  * The (single) hardware interval timer.
488124Sroot  * We update the events relating to real time, and then
498124Sroot  * make a gross assumption: that the system has been in the
508124Sroot  * state it is in (user state, kernel state, interrupt state,
518124Sroot  * or idle state) for the entire last time interval, and
528124Sroot  * update statistics accordingly.
538124Sroot  */
542609Swnj /*ARGSUSED*/
55*8944Sroot #if vax
562442Swnj hardclock(pc, ps)
572450Swnj 	caddr_t pc;
58*8944Sroot 	int ps;
599Sbill {
60*8944Sroot #endif
61*8944Sroot #if sun
62*8944Sroot hardclock(regs)
63*8944Sroot 	struct regs regs;
64*8944Sroot {
65*8944Sroot 	int ps = regs.r_sr;
66*8944Sroot 	caddr_t pc = (caddr_t)regs.r_pc;
67*8944Sroot #endif
682768Swnj 	register struct callout *p1;
698097Sroot 	register struct proc *p;
702442Swnj 	register int s, cpstate;
719Sbill 
728124Sroot 	/*
738124Sroot 	 * Update real-time timeout queue.
748124Sroot 	 * At front of queue are some number of events which are ``due''.
758124Sroot 	 * The time to these is <= 0 and if negative represents the
768124Sroot 	 * number of ticks which have passed since it was supposed to happen.
778124Sroot 	 * The rest of the q elements (times > 0) are events yet to happen,
788124Sroot 	 * where the time for each is given as a delta from the previous.
798124Sroot 	 * Decrementing just the first of these serves to decrement the time
808124Sroot 	 * to all events.
818124Sroot 	 */
823542Swnj 	for (p1 = calltodo.c_next; p1 && p1->c_time <= 0; p1 = p1->c_next)
838112Sroot 		--p1->c_time;
843542Swnj 	if (p1)
858112Sroot 		--p1->c_time;
86138Sbill 
878124Sroot 	/*
888124Sroot 	 * If the cpu is currently scheduled to a process, then
898124Sroot 	 * charge it with resource utilization for a tick, updating
908124Sroot 	 * statistics which run in (user+system) virtual time,
918124Sroot 	 * such as the cpu time limit and profiling timers.
928124Sroot 	 * This assumes that the current process has been running
938124Sroot 	 * the entire last tick.
948124Sroot 	 */
959Sbill 	if (!noproc) {
969Sbill 		s = u.u_procp->p_rssize;
978097Sroot 		u.u_ru.ru_idrss += s; u.u_ru.ru_isrss += 0;	/* XXX */
989Sbill 		if (u.u_procp->p_textp) {
999Sbill 			register int xrss = u.u_procp->p_textp->x_rssize;
1009Sbill 
1019Sbill 			s += xrss;
1028028Sroot 			u.u_ru.ru_ixrss += xrss;
1039Sbill 		}
1048028Sroot 		if (s > u.u_ru.ru_maxrss)
1058028Sroot 			u.u_ru.ru_maxrss = s;
1068028Sroot 		if ((u.u_ru.ru_utime.tv_sec+u.u_ru.ru_stime.tv_sec+1) >
1078028Sroot 		    u.u_rlimit[RLIMIT_CPU].rlim_cur) {
108375Sbill 			psignal(u.u_procp, SIGXCPU);
1098028Sroot 			if (u.u_rlimit[RLIMIT_CPU].rlim_cur <
1108028Sroot 			    u.u_rlimit[RLIMIT_CPU].rlim_max)
1118028Sroot 				u.u_rlimit[RLIMIT_CPU].rlim_cur += 5;
112375Sbill 		}
1138097Sroot 		if (timerisset(&u.u_timer[ITIMER_PROF].it_value) &&
1148097Sroot 		    itimerdecr(&u.u_timer[ITIMER_PROF], tick) == 0)
1158097Sroot 			psignal(u.u_procp, SIGPROF);
1169Sbill 	}
1178097Sroot 
1188124Sroot 	/*
1198124Sroot 	 * Charge the time out based on the mode the cpu is in.
1208124Sroot 	 * Here again we fudge for the lack of proper interval timers
1218124Sroot 	 * assuming that the current state has been around at least
1228124Sroot 	 * one tick.
1238124Sroot 	 */
1249Sbill 	if (USERMODE(ps)) {
1258124Sroot 		/*
1268124Sroot 		 * CPU was in user state.  Increment
1278124Sroot 		 * user time counter, and process process-virtual time
1288124Sroot 		 * interval timer.
1298124Sroot 		 */
1308124Sroot 		bumptime(&u.u_ru.ru_utime, tick);
1318097Sroot 		if (timerisset(&u.u_timer[ITIMER_VIRTUAL].it_value) &&
1328097Sroot 		    itimerdecr(&u.u_timer[ITIMER_VIRTUAL], tick) == 0)
1338097Sroot 			psignal(u.u_procp, SIGVTALRM);
1348028Sroot 		if (u.u_procp->p_nice > NZERO)
135305Sbill 			cpstate = CP_NICE;
136305Sbill 		else
137305Sbill 			cpstate = CP_USER;
1389Sbill 	} else {
1398124Sroot 		/*
1408124Sroot 		 * CPU was in system state.  If profiling kernel
1418124Sroot 		 * increment a counter.  If no process is running
1428124Sroot 		 * then this is a system tick if we were running
1438124Sroot 		 * at a non-zero IPL (in a driver).  If a process is running,
1448124Sroot 		 * then we charge it with system time even if we were
1458124Sroot 		 * at a non-zero IPL, since the system often runs
1468124Sroot 		 * this way during processing of system calls.
1478124Sroot 		 * This is approximate, but the lack of true interval
1488124Sroot 		 * timers makes doing anything else difficult.
1498124Sroot 		 */
1507388Sroot #ifdef GPROF
1517388Sroot 		int k = pc - s_lowpc;
1527388Sroot 		if (profiling < 2 && k < s_textsize)
1537388Sroot 			kcount[k / sizeof (*kcount)]++;
1544968Swnj #endif
155305Sbill 		cpstate = CP_SYS;
1567315Ssam 		if (noproc) {
157*8944Sroot 			if (BASEPRI(ps))
1587315Ssam 				cpstate = CP_IDLE;
1598028Sroot 		} else {
1608124Sroot 			bumptime(&u.u_ru.ru_stime, tick);
1618028Sroot 		}
1629Sbill 	}
1638097Sroot 
1648124Sroot 	/*
1658124Sroot 	 * We maintain statistics shown by user-level statistics
1668124Sroot 	 * programs:  the amount of time in each cpu state, and
1678124Sroot 	 * the amount of time each of DK_NDRIVE ``drives'' is busy.
1688124Sroot 	 */
1691408Sbill 	cp_time[cpstate]++;
1702442Swnj 	for (s = 0; s < DK_NDRIVE; s++)
1712442Swnj 		if (dk_busy&(1<<s))
1722442Swnj 			dk_time[s]++;
1738097Sroot 
1748124Sroot 	/*
1758124Sroot 	 * We adjust the priority of the current process.
1768124Sroot 	 * The priority of a process gets worse as it accumulates
1778124Sroot 	 * CPU time.  The cpu usage estimator (p_cpu) is increased here
1788124Sroot 	 * and the formula for computing priorities (in kern_synch.c)
1798124Sroot 	 * will compute a different value each time the p_cpu increases
1808124Sroot 	 * by 4.  The cpu usage estimator ramps up quite quickly when
1818124Sroot 	 * the process is running (linearly), and decays away exponentially,
1828124Sroot 	 * at a rate which is proportionally slower when the system is
1838124Sroot 	 * busy.  The basic principal is that the system will 90% forget
1848124Sroot 	 * that a process used a lot of CPU time in 5*loadav seconds.
1858124Sroot 	 * This causes the system to favor processes which haven't run
1868124Sroot 	 * much recently, and to round-robin among other processes.
1878124Sroot 	 */
1889Sbill 	if (!noproc) {
1898097Sroot 		p = u.u_procp;
1908097Sroot 		p->p_cpticks++;
1918097Sroot 		if (++p->p_cpu == 0)
1928097Sroot 			p->p_cpu--;
1937490Skre #ifdef MUSH
1948097Sroot 		p->p_quota->q_cost += (p->p_nice > NZERO ?
1958097Sroot 		    (shconsts.sc_tic * ((2*NZERO)-p->p_nice)) / NZERO :
1967490Skre 		    shconsts.sc_tic) * (((int)avenrun[0]+2)/3);
1977490Skre #endif
1988124Sroot 		if ((p->p_cpu&3) == 0) {
1998097Sroot 			(void) setpri(p);
2008097Sroot 			if (p->p_pri >= PUSER)
2018097Sroot 				p->p_pri = p->p_usrpri;
2029Sbill 		}
2039Sbill 	}
2048124Sroot 
2058124Sroot 	/*
2068124Sroot 	 * Increment the time-of-day, and schedule
2078124Sroot 	 * processing of the callouts at a very low cpu priority,
2088124Sroot 	 * so we don't keep the relatively high clock interrupt
2098124Sroot 	 * priority any longer than necessary.
2108124Sroot 	 */
2118124Sroot 	bumptime(&time, tick);
2122442Swnj 	setsoftclock();
2132442Swnj }
2142442Swnj 
2158124Sroot /*
2168124Sroot  * Software priority level clock interrupt.
2178124Sroot  * Run periodic events from timeout queue.
2188124Sroot  */
2192609Swnj /*ARGSUSED*/
220*8944Sroot #if vax
2212442Swnj softclock(pc, ps)
2222450Swnj 	caddr_t pc;
223*8944Sroot 	int ps;
2242442Swnj {
225*8944Sroot #endif
226*8944Sroot #if sun
227*8944Sroot softclock(sirret, regs)
228*8944Sroot 	caddr_t sirreg;
229*8944Sroot 	struct regs regs;
230*8944Sroot {
231*8944Sroot 	int ps = regs.r_sr;
232*8944Sroot 	caddr_t pc = (caddr_t)regs.r_pc;
233*8944Sroot #endif
2342442Swnj 
2358097Sroot 	for (;;) {
2368124Sroot 		register struct callout *p1;
2378124Sroot 		register caddr_t arg;
2388124Sroot 		register int (*func)();
2398124Sroot 		register int a, s;
2408124Sroot 
2418097Sroot 		s = spl7();
2428097Sroot 		if ((p1 = calltodo.c_next) == 0 || p1->c_time > 0) {
2438097Sroot 			splx(s);
2448097Sroot 			break;
2452442Swnj 		}
2468124Sroot 		arg = p1->c_arg; func = p1->c_func; a = p1->c_time;
2478097Sroot 		calltodo.c_next = p1->c_next;
2488097Sroot 		p1->c_next = callfree;
2498097Sroot 		callfree = p1;
2508097Sroot 		(void) splx(s);
2518112Sroot 		(*func)(arg, a);
2522442Swnj 	}
2539Sbill }
2549Sbill 
2559Sbill /*
2568097Sroot  * Arrange that (*fun)(arg) is called in tim/hz seconds.
2579Sbill  */
2589Sbill timeout(fun, arg, tim)
2592450Swnj 	int (*fun)();
2602450Swnj 	caddr_t arg;
2618097Sroot 	int tim;
2629Sbill {
2633542Swnj 	register struct callout *p1, *p2, *pnew;
2649Sbill 	register int t;
2659Sbill 	int s;
2669Sbill 
2679Sbill 	t = tim;
2689Sbill 	s = spl7();
2693542Swnj 	pnew = callfree;
2703542Swnj 	if (pnew == NULL)
2713542Swnj 		panic("timeout table overflow");
2723542Swnj 	callfree = pnew->c_next;
2733542Swnj 	pnew->c_arg = arg;
2743542Swnj 	pnew->c_func = fun;
2753542Swnj 	for (p1 = &calltodo; (p2 = p1->c_next) && p2->c_time < t; p1 = p2)
2763542Swnj 		t -= p2->c_time;
2773542Swnj 	p1->c_next = pnew;
2783542Swnj 	pnew->c_next = p2;
2793542Swnj 	pnew->c_time = t;
2803542Swnj 	if (p2)
2813542Swnj 		p2->c_time -= t;
2829Sbill 	splx(s);
2839Sbill }
2847305Ssam 
2857305Ssam /*
2867305Ssam  * untimeout is called to remove a function timeout call
2877305Ssam  * from the callout structure.
2887305Ssam  */
2898097Sroot untimeout(fun, arg)
2907305Ssam 	int (*fun)();
2917305Ssam 	caddr_t arg;
2927305Ssam {
2937305Ssam 	register struct callout *p1, *p2;
2947305Ssam 	register int s;
2957305Ssam 
2967305Ssam 	s = spl7();
2977305Ssam 	for (p1 = &calltodo; (p2 = p1->c_next) != 0; p1 = p2) {
2987305Ssam 		if (p2->c_func == fun && p2->c_arg == arg) {
2998112Sroot 			if (p2->c_next && p2->c_time > 0)
3007305Ssam 				p2->c_next->c_time += p2->c_time;
3017305Ssam 			p1->c_next = p2->c_next;
3027305Ssam 			p2->c_next = callfree;
3037305Ssam 			callfree = p2;
3047305Ssam 			break;
3057305Ssam 		}
3067305Ssam 	}
3077305Ssam 	splx(s);
3087305Ssam }
3098112Sroot 
3108124Sroot /*
3118124Sroot  * Compute number of hz until specified time.
3128124Sroot  * Used to compute third argument to timeout() from an
3138124Sroot  * absolute time.
3148124Sroot  */
3158112Sroot hzto(tv)
3168112Sroot 	struct timeval *tv;
3178112Sroot {
3188124Sroot 	register long ticks;
3198124Sroot 	register long sec;
3208112Sroot 	int s = spl7();
3218112Sroot 
3228124Sroot 	/*
3238124Sroot 	 * If number of milliseconds will fit in 32 bit arithmetic,
3248124Sroot 	 * then compute number of milliseconds to time and scale to
3258124Sroot 	 * ticks.  Otherwise just compute number of hz in time, rounding
3268124Sroot 	 * times greater than representible to maximum value.
3278124Sroot 	 *
3288124Sroot 	 * Delta times less than 25 days can be computed ``exactly''.
3298124Sroot 	 * Maximum value for any timeout in 10ms ticks is 250 days.
3308124Sroot 	 */
3318124Sroot 	sec = tv->tv_sec - time.tv_sec;
3328124Sroot 	if (sec <= 0x7fffffff / 1000 - 1000)
3338124Sroot 		ticks = ((tv->tv_sec - time.tv_sec) * 1000 +
3348124Sroot 			(tv->tv_usec - time.tv_usec) / 1000) / (tick / 1000);
3358124Sroot 	else if (sec <= 0x7fffffff / hz)
3368124Sroot 		ticks = sec * hz;
3378124Sroot 	else
3388124Sroot 		ticks = 0x7fffffff;
3398112Sroot 	splx(s);
3408112Sroot 	return (ticks);
3418112Sroot }
342