|
|
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: /* ! 26: * Mach Operating System ! 27: * Copyright (c) 1989 Carnegie-Mellon University ! 28: * Copyright (c) 1988 Carnegie-Mellon University ! 29: * Copyright (c) 1987 Carnegie-Mellon University ! 30: * All rights reserved. The CMU software License Agreement specifies ! 31: * the terms and conditions for use and redistribution. ! 32: */ ! 33: ! 34: #import <cpus.h> ! 35: #import <stat_time.h> ! 36: ! 37: #import <sys/param.h> ! 38: #import <sys/kernel.h> ! 39: #import <mach/kern_return.h> ! 40: #import <mach/port.h> ! 41: #import <kern/queue.h> ! 42: #import <kern/thread.h> ! 43: #import <mach/time_value.h> ! 44: #import <kern/timer.h> ! 45: #import <bsd/machine/cpu.h> ! 46: ! 47: #import <kernserv/macro_help.h> ! 48: ! 49: timer_t current_timer[NCPUS]; ! 50: timer_data_t kernel_timer[NCPUS]; ! 51: ! 52: /* ! 53: * init_timers initializes all non-thread timers and puts the ! 54: * service routine on the callout queue. All timers must be ! 55: * serviced by the callout routine once an hour. ! 56: */ ! 57: init_timers() ! 58: { ! 59: register int i; ! 60: register timer_t this_timer; ! 61: ! 62: /* ! 63: * Initialize all the kernel timers and start the one ! 64: * for this cpu (master) slaves start theirs later. ! 65: */ ! 66: this_timer = &kernel_timer[0]; ! 67: for ( i=0 ; i<NCPUS ; i++, this_timer++) { ! 68: timer_init(this_timer); ! 69: current_timer[i] = (timer_t) 0; ! 70: } ! 71: ! 72: start_timer(&kernel_timer[cpu_number()]); ! 73: } ! 74: ! 75: /* ! 76: * timer_init initializes a single timer. ! 77: */ ! 78: timer_init(this_timer) ! 79: register ! 80: timer_t this_timer; ! 81: { ! 82: this_timer->low_bits = 0; ! 83: this_timer->high_bits = 0; ! 84: this_timer->tstamp = 0; ! 85: this_timer->high_bits_check = 0; ! 86: } ! 87: ! 88: #if STAT_TIME ! 89: #else STAT_TIME ! 90: /* ! 91: * start_timer starts the given timer for this cpu. It is called ! 92: * exactly once for each cpu during the boot sequence. ! 93: */ ! 94: void ! 95: start_timer(timer) ! 96: timer_t timer; ! 97: { ! 98: timer->tstamp = get_timestamp(); ! 99: current_timer[cpu_number()] = timer; ! 100: } ! 101: ! 102: /* ! 103: * time_trap_uentry does trap entry timing. Caller must lock out ! 104: * interrupts and take a timestamp. ts is a timestamp taken after ! 105: * interrupts were locked out. Must only be called if trap was ! 106: * from user mode. ! 107: */ ! 108: void ! 109: time_trap_uentry(ts) ! 110: unsigned ts; ! 111: { ! 112: int elapsed; ! 113: int mycpu; ! 114: timer_t mytimer; ! 115: ! 116: /* ! 117: * Calculate elapsed time. ! 118: */ ! 119: mycpu = cpu_number(); ! 120: mytimer = current_timer[mycpu]; ! 121: elapsed = ts - mytimer->tstamp; ! 122: #ifdef TIMER_MAX ! 123: if (elapsed < 0) elapsed += TIMER_MAX; ! 124: #endif TIMER_MAX ! 125: ! 126: /* ! 127: * Update current timer. ! 128: */ ! 129: mytimer->low_bits += elapsed; ! 130: mytimer->tstamp = 0; ! 131: ! 132: /* ! 133: * Record new timer. ! 134: */ ! 135: mytimer = &(active_threads[mycpu]->system_timer); ! 136: current_timer[mycpu] = mytimer; ! 137: mytimer->tstamp = ts; ! 138: } ! 139: ! 140: /* ! 141: * time_trap_uexit does trap exit timing. Caller must lock out ! 142: * interrupts and take a timestamp. ts is a timestamp taken after ! 143: * interrupts were locked out. Must only be called if returning to ! 144: * user mode. ! 145: */ ! 146: void ! 147: time_trap_uexit(ts) ! 148: { ! 149: int elapsed; ! 150: int mycpu; ! 151: timer_t mytimer; ! 152: ! 153: /* ! 154: * Calculate elapsed time. ! 155: */ ! 156: mycpu = cpu_number(); ! 157: mytimer = current_timer[mycpu]; ! 158: elapsed = ts - mytimer->tstamp; ! 159: #ifdef TIMER_MAX ! 160: if (elapsed < 0) elapsed += TIMER_MAX; ! 161: #endif TIMER_MAX ! 162: ! 163: /* ! 164: * Update current timer. ! 165: */ ! 166: mytimer->low_bits += elapsed; ! 167: mytimer->tstamp = 0; ! 168: ! 169: /* ! 170: * Normalize old and new timers if needed. ! 171: */ ! 172: if (mytimer->low_bits & TIMER_LOW_FULL) { ! 173: timer_normalize(mytimer); /* SYSTEMMODE */ ! 174: } ! 175: ! 176: mytimer = &(active_threads[mycpu]->user_timer); ! 177: ! 178: if (mytimer->low_bits & TIMER_LOW_FULL) { ! 179: timer_normalize(mytimer); /* USERMODE */ ! 180: } ! 181: ! 182: /* ! 183: * Record new timer. ! 184: */ ! 185: current_timer[mycpu] = mytimer; ! 186: mytimer->tstamp = ts; ! 187: } ! 188: ! 189: /* ! 190: * time_int_entry does interrupt entry timing. Caller must lock out ! 191: * interrupts and take a timestamp. ts is a timestamp taken after ! 192: * interrupts were locked out. new_timer is the new timer to ! 193: * switch to. This routine returns the currently running timer, ! 194: * which MUST be pushed onto the stack by the caller, or otherwise ! 195: * saved for time_int_exit. ! 196: */ ! 197: timer_t ! 198: time_int_entry(ts,new_timer) ! 199: unsigned ts; ! 200: timer_t new_timer; ! 201: { ! 202: int elapsed; ! 203: int mycpu; ! 204: timer_t mytimer; ! 205: ! 206: /* ! 207: * Calculate elapsed time. ! 208: */ ! 209: mycpu = cpu_number(); ! 210: mytimer = current_timer[mycpu]; ! 211: ! 212: elapsed = ts - mytimer->tstamp; ! 213: #ifdef TIMER_MAX ! 214: if (elapsed < 0) elapsed += TIMER_MAX; ! 215: #endif TIMER_MAX ! 216: ! 217: /* ! 218: * Update current timer. ! 219: */ ! 220: mytimer->low_bits += elapsed; ! 221: mytimer->tstamp = 0; ! 222: ! 223: /* ! 224: * Switch to new timer, and save old one on stack. ! 225: */ ! 226: new_timer->tstamp = ts; ! 227: current_timer[mycpu] = new_timer; ! 228: return(mytimer); ! 229: } ! 230: ! 231: /* ! 232: * time_int_exit does interrupt exit timing. Caller must lock out ! 233: * interrupts and take a timestamp. ts is a timestamp taken after ! 234: * interrupts were locked out. old_timer is the timer value pushed ! 235: * onto the stack or otherwise saved after time_int_entry returned ! 236: * it. ! 237: */ ! 238: void ! 239: time_int_exit(ts, old_timer) ! 240: unsigned ts; ! 241: timer_t old_timer; ! 242: { ! 243: int elapsed; ! 244: int mycpu; ! 245: timer_t mytimer; ! 246: ! 247: /* ! 248: * Calculate elapsed time. ! 249: */ ! 250: mycpu = cpu_number(); ! 251: mytimer = current_timer[mycpu]; ! 252: elapsed = ts - mytimer->tstamp; ! 253: #ifdef TIMER_MAX ! 254: if (elapsed < 0) elapsed += TIMER_MAX; ! 255: #endif TIMER_MAX ! 256: ! 257: /* ! 258: * Update current timer. ! 259: */ ! 260: mytimer->low_bits += elapsed; ! 261: mytimer->tstamp = 0; ! 262: ! 263: /* ! 264: * If normalization requested, do it. ! 265: */ ! 266: if (mytimer->low_bits & TIMER_LOW_FULL) { ! 267: timer_normalize(mytimer); ! 268: } ! 269: if (old_timer->low_bits & TIMER_LOW_FULL) { ! 270: timer_normalize(old_timer); ! 271: } ! 272: ! 273: /* ! 274: * Start timer that was running before interrupt. ! 275: */ ! 276: old_timer->tstamp = ts; ! 277: current_timer[mycpu] = old_timer; ! 278: } ! 279: ! 280: /* ! 281: * timer_switch switches to a new timer. The machine ! 282: * dependent routine/macro get_timestamp must return a timestamp. ! 283: * Caller must lock out interrupts. ! 284: */ ! 285: void ! 286: timer_switch(new_timer) ! 287: timer_t new_timer; ! 288: { ! 289: int elapsed; ! 290: int mycpu; ! 291: timer_t mytimer; ! 292: unsigned ts; ! 293: ! 294: /* ! 295: * Calculate elapsed time. ! 296: */ ! 297: mycpu = cpu_number(); ! 298: mytimer = current_timer[mycpu]; ! 299: ts = get_timestamp(); ! 300: elapsed = ts - mytimer->tstamp; ! 301: #ifdef TIMER_MAX ! 302: if (elapsed < 0) elapsed += TIMER_MAX; ! 303: #endif TIMER_MAX ! 304: ! 305: /* ! 306: * Update current timer. ! 307: */ ! 308: mytimer->low_bits += elapsed; ! 309: mytimer->tstamp = 0; ! 310: ! 311: /* ! 312: * Normalization check ! 313: */ ! 314: if (mytimer->low_bits & TIMER_LOW_FULL) { ! 315: timer_normalize(mytimer); ! 316: } ! 317: ! 318: /* ! 319: * Record new timer. ! 320: */ ! 321: current_timer[mycpu] = new_timer; ! 322: new_timer->tstamp = ts; ! 323: } ! 324: #endif STAT_TIME ! 325: ! 326: /* ! 327: * timer_normalize normalizes the value of a timer. It is ! 328: * called only rarely, to make sure low_bits never overflows. ! 329: */ ! 330: timer_normalize(timer) ! 331: register ! 332: timer_t timer; ! 333: { ! 334: unsigned int high_increment; ! 335: ! 336: /* ! 337: * Calculate high_increment, then write high check field first ! 338: * followed by low and high. timer_grab() reads these fields in ! 339: * reverse order so if high and high check match, we know ! 340: * that the values read are ok. ! 341: */ ! 342: ! 343: high_increment = timer->low_bits/TIMER_HIGH_UNIT; ! 344: timer->high_bits_check += high_increment; ! 345: timer->low_bits %= TIMER_HIGH_UNIT; ! 346: timer->high_bits += high_increment; ! 347: } ! 348: ! 349: /* ! 350: * timer_grab() is a macro to retrieve the value of a timer. ! 351: */ ! 352: ! 353: #define timer_grab(timer, save) \ ! 354: MACRO_BEGIN \ ! 355: do { \ ! 356: (save)->high = (timer)->high_bits; \ ! 357: (save)->low = (timer)->low_bits; \ ! 358: /* \ ! 359: * If the timer was normalized while we were doing this, \ ! 360: * the high_bits value read above and the high_bits check \ ! 361: * value won't match because high_bits_check is the first \ ! 362: * field touched by the normalization procedure, and \ ! 363: * high_bits is the last. \ ! 364: * ! 365: * Additions to timer only touch low bits and \ ! 366: * are therefore atomic with respect to this. \ ! 367: */ \ ! 368: } while ( (save)->high != (timer)->high_bits_check); \ ! 369: MACRO_END ! 370: ! 371: ! 372: /* ! 373: * timer_read reads the value of a timer into a time_value_t. If the ! 374: * timer was modified during the read, retry. The value returned ! 375: * is accurate to the last update; time accumulated by a running ! 376: * timer since its last timestamp is not included. ! 377: */ ! 378: ! 379: void ! 380: timer_read(timer, tv) ! 381: timer_t timer; ! 382: register ! 383: time_value_t *tv; ! 384: { ! 385: timer_save_data_t temp; ! 386: ! 387: timer_grab(timer,&temp); ! 388: /* ! 389: * Normalize the result ! 390: */ ! 391: #ifdef TIMER_ADJUST ! 392: TIMER_ADJUST(&temp); ! 393: #endif TIMER_ADJUST ! 394: tv->seconds = temp.high + temp.low/1000000; ! 395: tv->microseconds = temp.low%1000000; ! 396: ! 397: } ! 398: ! 399: /* ! 400: * thread_read_times reads the user and system times from a thread. ! 401: * Time accumulated since last timestamp is not included. Should ! 402: * be called at splsched() to avoid having user and system times ! 403: * be out of step. Doesn't care if caller locked thread. ! 404: */ ! 405: void thread_read_times(thread, user_time_p, system_time_p) ! 406: thread_t thread; ! 407: time_value_t *user_time_p; ! 408: time_value_t *system_time_p; ! 409: { ! 410: timer_save_data_t temp; ! 411: register timer_t timer; ! 412: ! 413: timer = &thread->user_timer; ! 414: timer_grab(timer, &temp); ! 415: ! 416: #ifdef TIMER_ADJUST ! 417: TIMER_ADJUST(&temp); ! 418: #endif TIMER_ADJUST ! 419: user_time_p->seconds = temp.high + temp.low/1000000; ! 420: user_time_p->microseconds = temp.low % 1000000; ! 421: ! 422: timer = &thread->system_timer; ! 423: timer_grab(timer, &temp); ! 424: ! 425: #ifdef TIMER_ADJUST ! 426: TIMER_ADJUST(&temp); ! 427: #endif TIMER_ADJUST ! 428: system_time_p->seconds = temp.high + temp.low/1000000; ! 429: system_time_p->microseconds = temp.low % 1000000; ! 430: } ! 431: ! 432: /* ! 433: * timer_delta takes the difference of a saved timer value ! 434: * and the current one, and updates the saved value to current. ! 435: * The difference is returned as a function value. See ! 436: * TIMER_DELTA macro (timer.h) for optimization to this. ! 437: */ ! 438: ! 439: unsigned ! 440: timer_delta(timer, save) ! 441: register ! 442: timer_t timer; ! 443: timer_save_t save; ! 444: { ! 445: timer_save_data_t new_save; ! 446: register unsigned result; ! 447: ! 448: timer_grab(timer,&new_save); ! 449: result = (new_save.high - save->high) * TIMER_HIGH_UNIT + ! 450: new_save.low - save->low; ! 451: save->high = new_save.high; ! 452: save->low = new_save.low; ! 453: return(result); ! 454: } ! 455:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.