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