|
|
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.