|
|
1.1 ! root 1: /* ! 2: * Mach Operating System ! 3: * Copyright (c) 1991,1990,1989,1988,1987 Carnegie Mellon University ! 4: * All Rights Reserved. ! 5: * ! 6: * Permission to use, copy, modify and distribute this software and its ! 7: * documentation is hereby granted, provided that both the copyright ! 8: * notice and this permission notice appear in all copies of the ! 9: * software, derivative works or modified versions, and any portions ! 10: * thereof, and that both notices appear in supporting documentation. ! 11: * ! 12: * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" ! 13: * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR ! 14: * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. ! 15: * ! 16: * Carnegie Mellon requests users of this software to return to ! 17: * ! 18: * Software Distribution Coordinator or [email protected] ! 19: * School of Computer Science ! 20: * Carnegie Mellon University ! 21: * Pittsburgh PA 15213-3890 ! 22: * ! 23: * any improvements or extensions that they make and grant Carnegie Mellon ! 24: * the rights to redistribute these changes. ! 25: */ ! 26: ! 27: #include <cpus.h> ! 28: #include <stat_time.h> ! 29: ! 30: #include <mach/kern_return.h> ! 31: #include <mach/port.h> ! 32: #include <kern/queue.h> ! 33: #include <kern/thread.h> ! 34: #include <mach/time_value.h> ! 35: #include <kern/timer.h> ! 36: #include <kern/cpu_number.h> ! 37: ! 38: #include <kern/assert.h> ! 39: #include <kern/macro_help.h> ! 40: ! 41: ! 42: ! 43: timer_t current_timer[NCPUS]; ! 44: timer_data_t kernel_timer[NCPUS]; ! 45: ! 46: void timer_init(); /* forward */ ! 47: ! 48: /* ! 49: * init_timers initializes all non-thread timers and puts the ! 50: * service routine on the callout queue. All timers must be ! 51: * serviced by the callout routine once an hour. ! 52: */ ! 53: void init_timers() ! 54: { ! 55: register int i; ! 56: register timer_t this_timer; ! 57: ! 58: /* ! 59: * Initialize all the kernel timers and start the one ! 60: * for this cpu (master) slaves start theirs later. ! 61: */ ! 62: this_timer = &kernel_timer[0]; ! 63: for ( i=0 ; i<NCPUS ; i++, this_timer++) { ! 64: timer_init(this_timer); ! 65: current_timer[i] = (timer_t) 0; ! 66: } ! 67: ! 68: start_timer(&kernel_timer[cpu_number()]); ! 69: } ! 70: ! 71: /* ! 72: * timer_init initializes a single timer. ! 73: */ ! 74: void timer_init(this_timer) ! 75: register ! 76: timer_t this_timer; ! 77: { ! 78: this_timer->low_bits = 0; ! 79: this_timer->high_bits = 0; ! 80: this_timer->tstamp = 0; ! 81: this_timer->high_bits_check = 0; ! 82: } ! 83: ! 84: #if STAT_TIME ! 85: #else /* STAT_TIME */ ! 86: ! 87: #ifdef MACHINE_TIMER_ROUTINES ! 88: ! 89: /* ! 90: * Machine-dependent code implements the timer routines. ! 91: */ ! 92: ! 93: #else /* MACHINE_TIMER_ROUTINES */ ! 94: ! 95: /* ! 96: * start_timer starts the given timer for this cpu. It is called ! 97: * exactly once for each cpu during the boot sequence. ! 98: */ ! 99: void ! 100: start_timer(timer) ! 101: timer_t timer; ! 102: { ! 103: timer->tstamp = get_timestamp(); ! 104: current_timer[cpu_number()] = timer; ! 105: } ! 106: ! 107: /* ! 108: * time_trap_uentry does trap entry timing. Caller must lock out ! 109: * interrupts and take a timestamp. ts is a timestamp taken after ! 110: * interrupts were locked out. Must only be called if trap was ! 111: * from user mode. ! 112: */ ! 113: void ! 114: time_trap_uentry(ts) ! 115: unsigned ts; ! 116: { ! 117: int elapsed; ! 118: int mycpu; ! 119: timer_t mytimer; ! 120: ! 121: /* ! 122: * Calculate elapsed time. ! 123: */ ! 124: mycpu = cpu_number(); ! 125: mytimer = current_timer[mycpu]; ! 126: elapsed = ts - mytimer->tstamp; ! 127: #ifdef TIMER_MAX ! 128: if (elapsed < 0) elapsed += TIMER_MAX; ! 129: #endif /* TIMER_MAX */ ! 130: ! 131: /* ! 132: * Update current timer. ! 133: */ ! 134: mytimer->low_bits += elapsed; ! 135: mytimer->tstamp = 0; ! 136: ! 137: if (mytimer->low_bits & TIMER_LOW_FULL) { ! 138: timer_normalize(mytimer); ! 139: } ! 140: ! 141: /* ! 142: * Record new timer. ! 143: */ ! 144: mytimer = &(active_threads[mycpu]->system_timer); ! 145: current_timer[mycpu] = mytimer; ! 146: mytimer->tstamp = ts; ! 147: } ! 148: ! 149: /* ! 150: * time_trap_uexit does trap exit timing. Caller must lock out ! 151: * interrupts and take a timestamp. ts is a timestamp taken after ! 152: * interrupts were locked out. Must only be called if returning to ! 153: * user mode. ! 154: */ ! 155: void ! 156: time_trap_uexit(ts) ! 157: { ! 158: int elapsed; ! 159: int mycpu; ! 160: timer_t mytimer; ! 161: ! 162: /* ! 163: * Calculate elapsed time. ! 164: */ ! 165: mycpu = cpu_number(); ! 166: mytimer = current_timer[mycpu]; ! 167: elapsed = ts - mytimer->tstamp; ! 168: #ifdef TIMER_MAX ! 169: if (elapsed < 0) elapsed += TIMER_MAX; ! 170: #endif /* TIMER_MAX */ ! 171: ! 172: /* ! 173: * Update current timer. ! 174: */ ! 175: mytimer->low_bits += elapsed; ! 176: mytimer->tstamp = 0; ! 177: ! 178: if (mytimer->low_bits & TIMER_LOW_FULL) { ! 179: timer_normalize(mytimer); /* SYSTEMMODE */ ! 180: } ! 181: ! 182: mytimer = &(active_threads[mycpu]->user_timer); ! 183: ! 184: /* ! 185: * Record new timer. ! 186: */ ! 187: current_timer[mycpu] = mytimer; ! 188: mytimer->tstamp = ts; ! 189: } ! 190: ! 191: /* ! 192: * time_int_entry does interrupt entry timing. Caller must lock out ! 193: * interrupts and take a timestamp. ts is a timestamp taken after ! 194: * interrupts were locked out. new_timer is the new timer to ! 195: * switch to. This routine returns the currently running timer, ! 196: * which MUST be pushed onto the stack by the caller, or otherwise ! 197: * saved for time_int_exit. ! 198: */ ! 199: timer_t ! 200: time_int_entry(ts,new_timer) ! 201: unsigned ts; ! 202: timer_t new_timer; ! 203: { ! 204: int elapsed; ! 205: int mycpu; ! 206: timer_t mytimer; ! 207: ! 208: /* ! 209: * Calculate elapsed time. ! 210: */ ! 211: mycpu = cpu_number(); ! 212: mytimer = current_timer[mycpu]; ! 213: ! 214: elapsed = ts - mytimer->tstamp; ! 215: #ifdef TIMER_MAX ! 216: if (elapsed < 0) elapsed += TIMER_MAX; ! 217: #endif /* TIMER_MAX */ ! 218: ! 219: /* ! 220: * Update current timer. ! 221: */ ! 222: mytimer->low_bits += elapsed; ! 223: mytimer->tstamp = 0; ! 224: ! 225: /* ! 226: * Switch to new timer, and save old one on stack. ! 227: */ ! 228: new_timer->tstamp = ts; ! 229: current_timer[mycpu] = new_timer; ! 230: return(mytimer); ! 231: } ! 232: ! 233: /* ! 234: * time_int_exit does interrupt exit timing. Caller must lock out ! 235: * interrupts and take a timestamp. ts is a timestamp taken after ! 236: * interrupts were locked out. old_timer is the timer value pushed ! 237: * onto the stack or otherwise saved after time_int_entry returned ! 238: * it. ! 239: */ ! 240: void ! 241: time_int_exit(ts, old_timer) ! 242: unsigned ts; ! 243: timer_t old_timer; ! 244: { ! 245: int elapsed; ! 246: int mycpu; ! 247: timer_t mytimer; ! 248: ! 249: /* ! 250: * Calculate elapsed time. ! 251: */ ! 252: mycpu = cpu_number(); ! 253: mytimer = current_timer[mycpu]; ! 254: elapsed = ts - mytimer->tstamp; ! 255: #ifdef TIMER_MAX ! 256: if (elapsed < 0) elapsed += TIMER_MAX; ! 257: #endif /* TIMER_MAX */ ! 258: ! 259: /* ! 260: * Update current timer. ! 261: */ ! 262: mytimer->low_bits += elapsed; ! 263: mytimer->tstamp = 0; ! 264: ! 265: /* ! 266: * If normalization requested, do it. ! 267: */ ! 268: if (mytimer->low_bits & TIMER_LOW_FULL) { ! 269: timer_normalize(mytimer); ! 270: } ! 271: if (old_timer->low_bits & TIMER_LOW_FULL) { ! 272: timer_normalize(old_timer); ! 273: } ! 274: ! 275: /* ! 276: * Start timer that was running before interrupt. ! 277: */ ! 278: old_timer->tstamp = ts; ! 279: current_timer[mycpu] = old_timer; ! 280: } ! 281: ! 282: /* ! 283: * timer_switch switches to a new timer. The machine ! 284: * dependent routine/macro get_timestamp must return a timestamp. ! 285: * Caller must lock out interrupts. ! 286: */ ! 287: void ! 288: timer_switch(new_timer) ! 289: timer_t new_timer; ! 290: { ! 291: int elapsed; ! 292: int mycpu; ! 293: timer_t mytimer; ! 294: unsigned ts; ! 295: ! 296: /* ! 297: * Calculate elapsed time. ! 298: */ ! 299: mycpu = cpu_number(); ! 300: mytimer = current_timer[mycpu]; ! 301: ts = get_timestamp(); ! 302: elapsed = ts - mytimer->tstamp; ! 303: #ifdef TIMER_MAX ! 304: if (elapsed < 0) elapsed += TIMER_MAX; ! 305: #endif /* TIMER_MAX */ ! 306: ! 307: /* ! 308: * Update current timer. ! 309: */ ! 310: mytimer->low_bits += elapsed; ! 311: mytimer->tstamp = 0; ! 312: ! 313: /* ! 314: * Normalization check ! 315: */ ! 316: if (mytimer->low_bits & TIMER_LOW_FULL) { ! 317: timer_normalize(mytimer); ! 318: } ! 319: ! 320: /* ! 321: * Record new timer. ! 322: */ ! 323: current_timer[mycpu] = new_timer; ! 324: new_timer->tstamp = ts; ! 325: } ! 326: ! 327: #endif /* MACHINE_TIMER_ROUTINES */ ! 328: #endif /* STAT_TIME */ ! 329: ! 330: /* ! 331: * timer_normalize normalizes the value of a timer. It is ! 332: * called only rarely, to make sure low_bits never overflows. ! 333: */ ! 334: void timer_normalize(timer) ! 335: register ! 336: timer_t timer; ! 337: { ! 338: unsigned int high_increment; ! 339: ! 340: /* ! 341: * Calculate high_increment, then write high check field first ! 342: * followed by low and high. timer_grab() reads these fields in ! 343: * reverse order so if high and high check match, we know ! 344: * that the values read are ok. ! 345: */ ! 346: ! 347: high_increment = timer->low_bits/TIMER_HIGH_UNIT; ! 348: timer->high_bits_check += high_increment; ! 349: timer->low_bits %= TIMER_HIGH_UNIT; ! 350: timer->high_bits += high_increment; ! 351: } ! 352: ! 353: /* ! 354: * timer_grab() retrieves the value of a timer. ! 355: * ! 356: * Critical scheduling code uses TIMER_DELTA macro in timer.h ! 357: * (called from thread_timer_delta in sched.h). ! 358: * ! 359: * Keep coherent with db_time_grab below. ! 360: */ ! 361: ! 362: static void timer_grab(timer, save) ! 363: timer_t timer; ! 364: timer_save_t save; ! 365: { ! 366: #if MACH_ASSERT ! 367: unsigned int passes=0; ! 368: #endif ! 369: do { ! 370: (save)->high = (timer)->high_bits; ! 371: (save)->low = (timer)->low_bits; ! 372: /* ! 373: * If the timer was normalized while we were doing this, ! 374: * the high_bits value read above and the high_bits check ! 375: * value will not match because high_bits_check is the first ! 376: * field touched by the normalization procedure, and ! 377: * high_bits is the last. ! 378: * ! 379: * Additions to timer only touch low bits and ! 380: * are therefore atomic with respect to this. ! 381: */ ! 382: #if MACH_ASSERT ! 383: passes++; ! 384: assert((passes < 10000) ? (1) : ((timer->high_bits_check = save->high), 0)); ! 385: #endif ! 386: } while ( (save)->high != (timer)->high_bits_check); ! 387: } ! 388: ! 389: /* ! 390: * ! 391: * Db_timer_grab(): used by db_thread_read_times. An nonblocking ! 392: * version of db_thread_get_times. Keep coherent with timer_grab ! 393: * above. ! 394: * ! 395: */ ! 396: void db_timer_grab(timer, save) ! 397: timer_t timer; ! 398: timer_save_t save; ! 399: { ! 400: /* Don't worry about coherency */ ! 401: ! 402: (save)->high = (timer)->high_bits; ! 403: (save)->low = (timer)->low_bits; ! 404: } ! 405: ! 406: ! 407: /* ! 408: * timer_read reads the value of a timer into a time_value_t. If the ! 409: * timer was modified during the read, retry. The value returned ! 410: * is accurate to the last update; time accumulated by a running ! 411: * timer since its last timestamp is not included. ! 412: */ ! 413: ! 414: void ! 415: timer_read(timer, tv) ! 416: timer_t timer; ! 417: register ! 418: time_value_t *tv; ! 419: { ! 420: timer_save_data_t temp; ! 421: ! 422: timer_grab(timer,&temp); ! 423: /* ! 424: * Normalize the result ! 425: */ ! 426: #ifdef TIMER_ADJUST ! 427: TIMER_ADJUST(&temp); ! 428: #endif /* TIMER_ADJUST */ ! 429: tv->seconds = temp.high + temp.low/1000000; ! 430: tv->microseconds = temp.low%1000000; ! 431: ! 432: } ! 433: ! 434: /* ! 435: * thread_read_times reads the user and system times from a thread. ! 436: * Time accumulated since last timestamp is not included. Should ! 437: * be called at splsched() to avoid having user and system times ! 438: * be out of step. Doesn't care if caller locked thread. ! 439: * ! 440: * Needs to be kept coherent with thread_read_times ahead. ! 441: */ ! 442: void thread_read_times(thread, user_time_p, system_time_p) ! 443: thread_t thread; ! 444: time_value_t *user_time_p; ! 445: time_value_t *system_time_p; ! 446: { ! 447: timer_save_data_t temp; ! 448: register timer_t timer; ! 449: ! 450: timer = &thread->user_timer; ! 451: timer_grab(timer, &temp); ! 452: ! 453: #ifdef TIMER_ADJUST ! 454: TIMER_ADJUST(&temp); ! 455: #endif /* TIMER_ADJUST */ ! 456: user_time_p->seconds = temp.high + temp.low/1000000; ! 457: user_time_p->microseconds = temp.low % 1000000; ! 458: ! 459: timer = &thread->system_timer; ! 460: timer_grab(timer, &temp); ! 461: ! 462: #ifdef TIMER_ADJUST ! 463: TIMER_ADJUST(&temp); ! 464: #endif /* TIMER_ADJUST */ ! 465: system_time_p->seconds = temp.high + temp.low/1000000; ! 466: system_time_p->microseconds = temp.low % 1000000; ! 467: } ! 468: ! 469: /* ! 470: * Db_thread_read_times: A version of thread_read_times that ! 471: * can be called by the debugger. This version does not call ! 472: * timer_grab, which can block. Please keep it up to date with ! 473: * thread_read_times above. ! 474: * ! 475: */ ! 476: void db_thread_read_times(thread, user_time_p, system_time_p) ! 477: thread_t thread; ! 478: time_value_t *user_time_p; ! 479: time_value_t *system_time_p; ! 480: { ! 481: timer_save_data_t temp; ! 482: register timer_t timer; ! 483: ! 484: timer = &thread->user_timer; ! 485: db_timer_grab(timer, &temp); ! 486: ! 487: #ifdef TIMER_ADJUST ! 488: TIMER_ADJUST(&temp); ! 489: #endif /* TIMER_ADJUST */ ! 490: user_time_p->seconds = temp.high + temp.low/1000000; ! 491: user_time_p->microseconds = temp.low % 1000000; ! 492: ! 493: timer = &thread->system_timer; ! 494: timer_grab(timer, &temp); ! 495: ! 496: #ifdef TIMER_ADJUST ! 497: TIMER_ADJUST(&temp); ! 498: #endif /* TIMER_ADJUST */ ! 499: system_time_p->seconds = temp.high + temp.low/1000000; ! 500: system_time_p->microseconds = temp.low % 1000000; ! 501: } ! 502: ! 503: /* ! 504: * timer_delta takes the difference of a saved timer value ! 505: * and the current one, and updates the saved value to current. ! 506: * The difference is returned as a function value. See ! 507: * TIMER_DELTA macro (timer.h) for optimization to this. ! 508: */ ! 509: ! 510: unsigned ! 511: timer_delta(timer, save) ! 512: register ! 513: timer_t timer; ! 514: timer_save_t save; ! 515: { ! 516: timer_save_data_t new_save; ! 517: register unsigned result; ! 518: ! 519: timer_grab(timer,&new_save); ! 520: result = (new_save.high - save->high) * TIMER_HIGH_UNIT + ! 521: new_save.low - save->low; ! 522: save->high = new_save.high; ! 523: save->low = new_save.low; ! 524: return(result); ! 525: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.