|
|
1.1 root 1: /*
2: * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
3: *
4: * @APPLE_LICENSE_HEADER_START@
5: *
6: * Portions Copyright (c) 1999 Apple Computer, Inc. All Rights
7: * Reserved. This file contains Original Code and/or Modifications of
8: * Original Code as defined in and that are subject to the Apple Public
9: * Source License Version 1.1 (the "License"). You may not use this file
10: * except in compliance with the License. Please obtain a copy of the
11: * License at http://www.apple.com/publicsource and read it before using
12: * this file.
13: *
14: * The Original Code and all software distributed under the License are
15: * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
16: * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
17: * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
18: * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
19: * License for the specific language governing rights and limitations
20: * under the License.
21: *
22: * @APPLE_LICENSE_HEADER_END@
23: */
24:
25: /* Copyright (c) 1995 NeXT Computer, Inc. All Rights Reserved */
26: /*-
27: * Copyright (c) 1982, 1986, 1991, 1993
28: * The Regents of the University of California. All rights reserved.
29: * (c) UNIX System Laboratories, Inc.
30: * All or some portions of this file are derived from material licensed
31: * to the University of California by American Telephone and Telegraph
32: * Co. or Unix System Laboratories, Inc. and are reproduced herein with
33: * the permission of UNIX System Laboratories, Inc.
34: *
35: * Redistribution and use in source and binary forms, with or without
36: * modification, are permitted provided that the following conditions
37: * are met:
38: * 1. Redistributions of source code must retain the above copyright
39: * notice, this list of conditions and the following disclaimer.
40: * 2. Redistributions in binary form must reproduce the above copyright
41: * notice, this list of conditions and the following disclaimer in the
42: * documentation and/or other materials provided with the distribution.
43: * 3. All advertising materials mentioning features or use of this software
44: * must display the following acknowledgement:
45: * This product includes software developed by the University of
46: * California, Berkeley and its contributors.
47: * 4. Neither the name of the University nor the names of its contributors
48: * may be used to endorse or promote products derived from this software
49: * without specific prior written permission.
50: *
51: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
52: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
53: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
54: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
55: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
56: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
57: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
58: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
59: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
60: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
61: * SUCH DAMAGE.
62: *
63: * @(#)kern_clock.c 8.5 (Berkeley) 1/21/94
64: */
65:
66: #include <simple_clock.h>
67: #include <cpus.h>
68:
69: #include <machine/reg.h>
70: #include <machine/spl.h>
71:
72: #include <sys/param.h>
73: #include <sys/systm.h>
74: #include <sys/dkstat.h>
75: #include <sys/callout.h>
76: #include <sys/resourcevar.h>
77: #include <sys/kernel.h>
78: #include <sys/proc.h>
79:
80: #ifdef GPROF
81: #include <sys/gmon.h>
82: #endif
83:
84: #include <bsd/machine/cpu.h>
85:
86: #include <kern/thread.h>
87: #include <mach/machine.h>
88: #include <kern/sched.h>
89: #include <kern/thread_call.h>
90: #include <mach/time_value.h>
91: #include <kern/timer.h>
92: #include <kern/xpr.h>
93:
94: #include <kern/assert.h>
95:
96: #include <mach/boolean.h>
97:
98: /*
99: * Clock handling routines.
100: *
101: * This code is written to operate with two timers which run
102: * independently of each other. The main clock, running at hz
103: * times per second, is used to do scheduling and timeout calculations.
104: * The second timer does resource utilization estimation statistically
105: * based on the state of the machine phz times a second. Both functions
106: * can be performed by a single clock (ie hz == phz), however the
107: * statistics will be much more prone to errors. Ideally a machine
108: * would have separate clocks measuring time spent in user state, system
109: * state, interrupt state, and idle state. These clocks would allow a non-
110: * approximate measure of resource utilization.
111: */
112: #define BUMPTIME(t, usec) { \
113: register volatile struct timeval *tp = (t); \
114: \
115: tp->tv_usec += (usec); \
116: if (tp->tv_usec >= 1000000) { \
117: tp->tv_usec -= 1000000; \
118: tp->tv_sec++; \
119: } \
120: }
121:
122: /*
123: * The hz hardware interval timer.
124: * We update the events relating to real time.
125: * If this timer is also being used to gather statistics,
126: * we run through the statistics gathering routine as well.
127: */
128:
129: #if SIMPLE_CLOCK
130: tvalspec_t last_hardclock[NCPUS];
131: #endif /* SIMPLE_CLOCK */
132:
133:
134: /*ARGSUSED*/
135: void
136: hardclock(pc, ps)
137: int ps;
138: caddr_t pc;
139: {
140: register struct callout *p1;
141: register struct proc *p;
142: register int s;
143: #if SIMPLE_CLOCK
144: tvalspec_t new_hardclock, delta_hardclock;
145: unsigned int myticks;
146: #define tick myticks
147: #endif /* SIMPLE_CLOCK */
148:
149: extern int tickdelta;
150: extern long timedelta;
151: register thread_t thread;
152:
153: thread = current_thread();
154:
155: #if SIMPLE_CLOCK
156: /*
157: * Simple hardware timer does not restart on overflow, hence
158: * interrupts do not happen at a constant rate. Must call
159: * machine-dependent routine to find out how much time has
160: * elapsed since last interrupt.
161: *
162: * On NeXT we use SIMPLE_CLOCK because hardclock is called
163: * at softint0 level, and although time won't drift, there's
164: * a fair amount of "jitter". --mike
165: */
166: new_hardclock = clock_get_counter(System);
167: delta_hardclock = new_hardclock;
168: SUB_TVALSPEC(&delta_hardclock, &last_hardclock[cpu_number()]);
169: myticks = (delta_hardclock.tv_sec * USEC_PER_SEC) +
170: (delta_hardclock.tv_nsec / NSEC_PER_USEC);
171: last_hardclock[cpu_number()] = new_hardclock;
172:
173: /*
174: * NOTE: tick was #define'd to myticks above.
175: */
176: #endif /* SIMPLE_CLOCK */
177:
178: /*
179: * Charge the time out based on the mode the cpu is in.
180: * Here again we fudge for the lack of proper interval timers
181: * assuming that the current state has been around at least
182: * one tick.
183: */
184: p = current_proc();
185: if (USERMODE(ps)) {
186: if (p) {
187: if (p->p_stats->p_prof.pr_scale) {
188: p->p_flag |= P_OWEUPC;
189: ast_on(cpu_number(), AST_UNIX);
190: }
191: }
192:
193: /*
194: * CPU was in user state. Increment
195: * user time counter, and process process-virtual time
196: * interval timer.
197: */
198: if (timerisset(&p->p_stats->p_timer[ITIMER_VIRTUAL].it_value) &&
199: itimerdecr(&p->p_stats->p_timer[ITIMER_VIRTUAL], tick) == 0)
200: psignal(p, SIGVTALRM);
201: }
202:
203: /*
204: * If the cpu is currently scheduled to a process, then
205: * charge it with resource utilization for a tick, updating
206: * statistics which run in (user+system) virtual time,
207: * such as the cpu time limit and profiling timers.
208: * This assumes that the current process has been running
209: * the entire last tick.
210: */
211: if (p && !(thread->state & TH_IDLE))
212: {
213: if (p->p_limit->pl_rlimit[RLIMIT_CPU].rlim_cur != RLIM_INFINITY) {
214: time_value_t sys_time, user_time;
215:
216: thread_read_times(thread, &user_time, &sys_time);
217: if ((sys_time.seconds + user_time.seconds + 1) >
218: p->p_limit->pl_rlimit[RLIMIT_CPU].rlim_cur) {
219: psignal(p, SIGXCPU);
220: if (p->p_limit->pl_rlimit[RLIMIT_CPU].rlim_cur <
221: p->p_limit->pl_rlimit[RLIMIT_CPU].rlim_max)
222: p->p_limit->pl_rlimit[RLIMIT_CPU].rlim_cur += 5;
223: }
224: }
225: if (timerisset(&p->p_stats->p_timer[ITIMER_PROF].it_value) &&
226: itimerdecr(&p->p_stats->p_timer[ITIMER_PROF], tick) == 0)
227: psignal(p, SIGPROF);
228: }
229:
230: /*
231: * Increment the time-of-day, and schedule
232: * processing of the callouts at a very low cpu priority,
233: * so we don't keep the relatively high clock interrupt
234: * priority any longer than necessary.
235: */
236:
237: /*
238: * Gather the statistics.
239: */
240: gatherstats(pc, ps);
241:
242: #if NCPUS > 1
243: if (cpu_number() != master_cpu)
244: return;
245: #endif /* NCPUS > 1 */
246:
247: if (timedelta != 0) {
248: register delta;
249: clock_res_t nsdelta = tickdelta * NSEC_PER_USEC;
250:
251: if (timedelta < 0) {
252: delta = tick - tickdelta;
253: timedelta += tickdelta;
254: nsdelta = -nsdelta;
255: } else {
256: delta = tick + tickdelta;
257: timedelta -= tickdelta;
258: }
259: clock_adjust_counter(Calendar, nsdelta);
260: }
261: microtime(&time);
262: }
263:
264: #if SIMPLE_CLOCK
265: #undef tick
266: #endif /* SIMPLE_CLOCK */
267:
268: /*
269: * Gather statistics on resource utilization.
270: *
271: * We make a gross assumption: that the system has been in the
272: * state it is in (user state, kernel state, interrupt state,
273: * or idle state) for the entire last time interval, and
274: * update statistics accordingly.
275: */
276: /*ARGSUSED*/
277: void
278: gatherstats(pc, ps)
279: caddr_t pc;
280: int ps;
281: {
282: register int cpstate, s;
283:
284: #ifdef GPROF
285: struct gmonparam *p = &_gmonparam;
286: #endif
287:
288: /*
289: * Determine what state the cpu is in.
290: */
291: if (USERMODE(ps)) {
292: /*
293: * CPU was in user state.
294: */
295: if (current_proc()->p_nice > NZERO)
296: cpstate = CP_NICE;
297: else
298: cpstate = CP_USER;
299: } else {
300: /*
301: * CPU was in system state. If profiling kernel
302: * increment a counter. If no process is running
303: * then this is a system tick if we were running
304: * at a non-zero IPL (in a driver). If a process is running,
305: * then we charge it with system time even if we were
306: * at a non-zero IPL, since the system often runs
307: * this way during processing of system calls.
308: * This is approximate, but the lack of true interval
309: * timers makes doing anything else difficult.
310: */
311: cpstate = CP_SYS;
312: if ((current_thread()->state & TH_IDLE) && BASEPRI(ps))
313: cpstate = CP_IDLE;
314: #ifdef GPROF
315: if (p->state == GMON_PROF_ON) {
316: s = pc - p->lowpc;
317: if (s < p->textsize) {
318: s /= (HISTFRACTION * sizeof(*p->kcount));
319: p->kcount[s]++;
320: }
321: }
322: #endif
323: }
324: /*
325: * We maintain statistics shown by user-level statistics
326: * programs: the amount of time in each cpu state, and
327: * the amount of time each of DK_NDRIVE ``drives'' is busy.
328: */
329: cp_time[cpstate]++;
330: for (s = 0; s < DK_NDRIVE; s++)
331: if (dk_busy & (1 << s))
332: dk_time[s]++;
333: }
334:
335: /*
336: * Arrange that (*fun)(arg) is called in t/hz seconds.
337: */
338: void
339: timeout(ftn, arg, ticks)
340: void (*ftn) __P((void *));
341: void *arg;
342: register int ticks;
343: {
344: int s;
345: tvalspec_t deadline;
346: extern
347: tvalspec_t tick_stamp;
348:
349: if (ticks <= 0)
350: ticks = 1;
351:
352: s = splhigh();
353: deadline = ticks_to_tvalspec(ticks);
354: ADD_TVALSPEC(&deadline, &tick_stamp);
355:
356: thread_call_func_delayed(
357: (thread_call_func_t)ftn,
358: (thread_call_spec_t)arg, deadline);
359: splx(s);
360: }
361:
362: /*
363: * untimeout is called to remove a function timeout call
364: * from the callout structure.
365: */
366: int
367: untimeout(ftn, arg)
368: void (*ftn) __P((void *));
369: void *arg;
370: {
371: thread_call_func_cancel(
372: (thread_call_func_t)ftn,
373: (thread_call_spec_t)arg, FALSE);
374:
375: return TRUE; /* XXX cheat */
376: }
377:
378: /*
379: * Compute number of hz until specified time.
380: * Used to compute third argument to timeout() from an
381: * absolute time.
382: */
383: hzto(tv)
384: struct timeval *tv;
385: {
386: register long ticks;
387: register long sec;
388: int s = splhigh();
389:
390: /*
391: * If number of milliseconds will fit in 32 bit arithmetic,
392: * then compute number of milliseconds to time and scale to
393: * ticks. Otherwise just compute number of hz in time, rounding
394: * times greater than representible to maximum value.
395: *
396: * Delta times less than 25 days can be computed ``exactly''.
397: * Maximum value for any timeout in 10ms ticks is 250 days.
398: */
399: sec = tv->tv_sec - time.tv_sec;
400: if (sec <= 0x7fffffff / 1000 - 1000)
401: ticks = ((tv->tv_sec - time.tv_sec) * 1000 +
402: (tv->tv_usec - time.tv_usec) / 1000)
403: / (tick / 1000);
404: else if (sec <= 0x7fffffff / hz)
405: ticks = sec * hz;
406: else
407: ticks = 0x7fffffff;
408: splx(s);
409: return (ticks);
410: }
411:
412: /*
413: * Convert ticks to a timeval
414: */
415: ticks_to_timeval(ticks, tvp)
416: register long ticks;
417: struct timeval *tvp;
418: {
419: tvp->tv_sec = ticks/hz;
420: tvp->tv_usec = (ticks%hz) * tick;
421: ASSERT(tvp->tv_usec < 1000000);
422: }
423:
424: /*
425: * Return information about system clocks.
426: */
427: int
428: sysctl_clockrate(where, sizep)
429: register char *where;
430: size_t *sizep;
431: {
432: struct clockinfo clkinfo;
433:
434: /*
435: * Construct clockinfo structure.
436: */
437: clkinfo.hz = hz;
438: clkinfo.tick = tick;
439: clkinfo.profhz = hz;
440: clkinfo.stathz = hz;
441: return (sysctl_rdstruct(where, sizep, NULL, &clkinfo, sizeof(clkinfo)));
442: }
443:
444: /*
445: * Start profiling on a process.
446: *
447: * Kernel profiling passes kernel_proc which never exits and hence
448: * keeps the profile clock running constantly.
449: */
450: void
451: startprofclock(p)
452: register struct proc *p;
453: {
454: if ((p->p_flag & P_PROFIL) == 0)
455: p->p_flag |= P_PROFIL;
456: }
457:
458: /*
459: * Stop profiling on a process.
460: */
461: void
462: stopprofclock(p)
463: register struct proc *p;
464: {
465: if (p->p_flag & P_PROFIL)
466: p->p_flag &= ~P_PROFIL;
467: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.