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