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