|
|
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: /* ! 27: * The Event Trace Analysis Package ! 28: * ================================ ! 29: * ! 30: * Function: Traces micro-kernel events. ! 31: * ! 32: * Macro Notes: Several macros are added throughout the lock code. ! 33: * These macros allow for convenient configuration ! 34: * and code readability. ! 35: * ! 36: * The macro prefixes determine a specific trace ! 37: * configuration operation: ! 38: * ! 39: * CUM - Cumulative trace specific operation. ! 40: * MON - Monitored trace specific operation. ! 41: * ETAP - Both a cumulative and monitored trace ! 42: * operation. ! 43: */ ! 44: ! 45: ! 46: #ifndef _KERN_ETAP_MACROS_H_ ! 47: #define _KERN_ETAP_MACROS_H_ ! 48: ! 49: #include <kern/etap_options.h> ! 50: #include <kern/lock.h> ! 51: #include <mach/etap.h> ! 52: #include <mach/etap_events.h> ! 53: #include <kern/etap_pool.h> ! 54: ! 55: ! 56: #if ETAP ! 57: ! 58: #include <kern/macro_help.h> ! 59: #include <mach/vm_param.h> ! 60: #include <ipc/ipc_types.h> ! 61: #include <mach/message.h> ! 62: ! 63: extern void etap_init_phase1(void); ! 64: extern void etap_init_phase2(void); ! 65: extern void etap_event_table_assign(struct event_table_chain *, etap_event_t); ! 66: extern unsigned int etap_get_pc(void); ! 67: extern event_table_t event_table; ! 68: extern subs_table_t subs_table; ! 69: ! 70: /* ! 71: * Time Macros ! 72: */ ! 73: ! 74: #define ETAP_TIMESTAMP(t) rtc_gettime_interrupts_disabled(&t) ! 75: #define ETAP_TIME_SUM(t,sum_me) t += sum_me ! 76: #define ETAP_TIME_SUB(t,stop,start) \ ! 77: MACRO_BEGIN \ ! 78: (t) = (stop); \ ! 79: SUB_MACH_TIMESPEC(&(t), &(start)); \ ! 80: MACRO_END ! 81: #define ETAP_TIME_SQR(t,sqr_me) t += sqr_me*sqr_me ! 82: #define ETAP_TIME_DIV(r,n,d) r = (u_short) n/d ! 83: #define ETAP_TIME_IS_ZERO(t) ((t).tv_sec == 0) ! 84: #define ETAP_TIME_CLEAR(t) ((t).tv_sec = 0) ! 85: #define ETAP_TIME_GREATER(t1,t2) ((t1) > (t2)) ! 86: ! 87: #else /* ETAP */ ! 88: ! 89: #define etap_init_phase1() ! 90: #define etap_init_phase2() ! 91: #define etap_event_table_assign(event) ! 92: #define ETAP_TIMESTAMP(t) ! 93: #define ETAP_TIME_SUB(t,start,stop) ! 94: #define ETAP_TIME_CLEAR(t) ! 95: ! 96: #endif /* ETAP */ ! 97: ! 98: ! 99: /* ! 100: * =================================================== ! 101: * ETAP: cumulative trace specific macros ! 102: * =================================================== ! 103: */ ! 104: ! 105: #if ETAP_LOCK_ACCUMULATE ! 106: ! 107: extern cbuff_entry_t etap_cbuff_reserve(event_table_t); ! 108: #if MACH_LDEBUG ! 109: extern simple_lock_t cbuff_locks; ! 110: #else ! 111: extern simple_lock_data_t cbuff_locks; ! 112: #endif ! 113: extern int cbuff_width; ! 114: ! 115: /* ! 116: * If cumulative hold tracing is enabled for the event (i.e., acquired lock), ! 117: * the CUM_HOLD_ACCUMULATE macro will update the appropriate cumulative buffer ! 118: * entry with the newly collected hold data. ! 119: */ ! 120: ! 121: #define CUM_HOLD_ACCUMULATE(cp,total_time,dynamic,trace) \ ! 122: MACRO_BEGIN \ ! 123: u_short _bucket; \ ! 124: if ((cp) != CBUFF_ENTRY_NULL && ((trace) & CUM_DURATION)) { \ ! 125: if (dynamic) \ ! 126: simple_lock_no_trace(&cbuff_locks[dynamic-1]); \ ! 127: (cp)->hold.triggered++; \ ! 128: ETAP_TIME_SUM((cp)->hold.time,(total_time)); \ ! 129: ETAP_TIME_SQR((cp)->hold.time_sq,(total_time)); \ ! 130: if (ETAP_TIME_IS_ZERO((cp)->hold.min_time) || \ ! 131: ETAP_TIME_GREATER((cp)->hold.min_time,(total_time))) \ ! 132: (cp)->hold.min_time = (total_time); \ ! 133: if (ETAP_TIME_GREATER((total_time),(cp)->hold.max_time)) \ ! 134: (cp)->hold.max_time = (total_time); \ ! 135: ETAP_TIME_DIV(_bucket,(total_time),cbuff_width); \ ! 136: if (_bucket >= ETAP_CBUFF_IBUCKETS) \ ! 137: (cp)->hold_interval[ETAP_CBUFF_IBUCKETS-1]++; \ ! 138: else \ ! 139: (cp)->hold_interval[_bucket]++; \ ! 140: if (dynamic) \ ! 141: simple_unlock_no_trace(&cbuff_locks[dynamic-1]); \ ! 142: } \ ! 143: MACRO_END ! 144: ! 145: /* ! 146: * If cumulative wait tracing is enabled for the event (i.e., acquired lock), ! 147: * the CUM_WAIT_ACCUMULATE macro will update the appropriate cumulative ! 148: * buffer entry with the newly collected wait data. ! 149: */ ! 150: ! 151: #define CUM_WAIT_ACCUMULATE(cp,total_time,dynamic,trace) \ ! 152: MACRO_BEGIN \ ! 153: u_short _bucket; \ ! 154: if ((cp) != CBUFF_ENTRY_NULL && ((trace) & CUM_CONTENTION)) { \ ! 155: if (dynamic) \ ! 156: simple_lock_no_trace(&cbuff_locks[dynamic-1]); \ ! 157: (cp)->wait.triggered++; \ ! 158: ETAP_TIME_SUM((cp)->wait.time,(total_time)); \ ! 159: ETAP_TIME_SQR((cp)->wait.time_sq,(total_time)); \ ! 160: if (ETAP_TIME_IS_ZERO((cp)->wait.min_time) || \ ! 161: ETAP_TIME_GREATER((cp)->wait.min_time,(total_time))) \ ! 162: (cp)->wait.min_time = (total_time); \ ! 163: if (ETAP_TIME_GREATER((total_time),(cp)->wait.max_time)) \ ! 164: (cp)->wait.max_time = (total_time); \ ! 165: ETAP_TIME_DIV(_bucket,(total_time),cbuff_width); \ ! 166: if (_bucket >= ETAP_CBUFF_IBUCKETS) \ ! 167: (cp)->wait_interval[ETAP_CBUFF_IBUCKETS-1]++; \ ! 168: else \ ! 169: (cp)->wait_interval[_bucket]++; \ ! 170: if (dynamic) \ ! 171: simple_unlock_no_trace(&cbuff_locks[dynamic-1]); \ ! 172: } \ ! 173: MACRO_END ! 174: ! 175: /* ! 176: * Initially a lock's cbuff_read pointer is set to CBUFF_ENTRY_NULL. This ! 177: * saves space in the cumulative buffer in the event that a read lock is ! 178: * not acquired. In the case that a read lock is acquired, the ! 179: * CUM_READ_ENTRY_RESERVE macro is called. Here a cumulative ! 180: * record is reserved and initialized. ! 181: */ ! 182: ! 183: #define CUM_READ_ENTRY_RESERVE(l,cp,trace) \ ! 184: MACRO_BEGIN \ ! 185: if ((cp) == CBUFF_ENTRY_NULL && (trace) & ETAP_CUMULATIVE) { \ ! 186: (cp) = etap_cbuff_reserve(lock_event_table(l)); \ ! 187: if ((cp) != CBUFF_ENTRY_NULL) { \ ! 188: (cp)->event = lock_event_table(l)->event; \ ! 189: (cp)->instance = (u_int) l; \ ! 190: (cp)->kind = READ_LOCK; \ ! 191: } \ ! 192: } \ ! 193: MACRO_END ! 194: ! 195: #else /* ETAP_LOCK_ACCUMULATE */ ! 196: #define etap_cbuff_reserve(et) ! 197: #define CUM_HOLD_ACCUMULATE(cp,t,d,tr) ! 198: #define CUM_WAIT_ACCUMULATE(cp,t,d,tr) ! 199: #define CUM_READ_ENTRY_RESERVE(l,rep,tr) ! 200: #endif /* ETAP_LOCK_ACCUMULATE */ ! 201: ! 202: /* ! 203: * =============================================== ! 204: * ETAP: monitor trace specific macros ! 205: * =============================================== ! 206: */ ! 207: ! 208: #if ETAP_MONITOR ! 209: extern int mbuff_entries; ! 210: extern monitor_buffer_t mbuff[]; ! 211: #endif /* ETAP_MONITOR */ ! 212: ! 213: ! 214: #if ETAP_LOCK_MONITOR ! 215: ! 216: /* ! 217: * If monitor tracing is enabled for the lock, the ! 218: * MON_DATA_COLLECT macro will write collected lock data to ! 219: * the next slot in a cpu specific monitor buffer. Circular ! 220: * buffer maintenance is also performed here. ! 221: */ ! 222: ! 223: #define MON_DATA_COLLECT(l,e,total_time,type,op,trace) \ ! 224: MACRO_BEGIN \ ! 225: mbuff_entry_t _mp; \ ! 226: int _cpu, _ent, _s; \ ! 227: if ((trace) & op) { \ ! 228: mp_disable_preemption(); \ ! 229: _cpu = cpu_number(); \ ! 230: _s = splhigh(); \ ! 231: _ent = mbuff[_cpu]->free; \ ! 232: _mp = &mbuff[_cpu]->entry[_ent]; \ ! 233: _mp->event = lock_event_table(l)->event; \ ! 234: _mp->flags = ((op) | (type)); \ ! 235: _mp->instance = (u_int) (l); \ ! 236: _mp->time = (total_time); \ ! 237: _mp->data[0] = (e)->start_pc; \ ! 238: _mp->data[1] = (e)->end_pc; \ ! 239: mbuff[_cpu]->free = (_ent+1) % mbuff_entries; \ ! 240: if (mbuff[_cpu]->free == 0) \ ! 241: mbuff[_cpu]->timestamp++; \ ! 242: splx(_s); \ ! 243: mp_enable_preemption(); \ ! 244: } \ ! 245: MACRO_END ! 246: ! 247: #define MON_CLEAR_PCS(l) \ ! 248: MACRO_BEGIN \ ! 249: (l)->start_pc = 0; \ ! 250: (l)->end_pc = 0; \ ! 251: MACRO_END ! 252: ! 253: #define MON_ASSIGN_PC(target,source,trace) \ ! 254: if ((trace) & ETAP_MONITORED) target = source ! 255: ! 256: #else /* ETAP_LOCK_MONITOR */ ! 257: #define MON_DATA_COLLECT(l,le,tt,t,o,tr) ! 258: #define MON_GET_PC(pc,tr) ! 259: #define MON_CLEAR_PCS(l) ! 260: #define MON_ASSIGN_PC(t,s,tr) ! 261: #endif /* ETAP_LOCK_MONITOR */ ! 262: ! 263: ! 264: #if ETAP_EVENT_MONITOR ! 265: ! 266: #define ETAP_PROBE_DATA_COND(_event, _flags, _thread, _data, _size, _cond) \ ! 267: MACRO_BEGIN \ ! 268: mbuff_entry_t _mp; \ ! 269: int _cpu, _ent, _s; \ ! 270: if (event_table[_event].status && (_cond)) { \ ! 271: mp_disable_preemption(); \ ! 272: _cpu = cpu_number(); \ ! 273: _s = splhigh(); \ ! 274: _ent = mbuff[_cpu]->free; \ ! 275: _mp = &mbuff[_cpu]->entry[_ent]; \ ! 276: ETAP_TIMESTAMP(_mp->time); \ ! 277: _mp->pc = etap_get_pc(); \ ! 278: _mp->event = _event; \ ! 279: _mp->flags = KERNEL_EVENT | _flags; \ ! 280: _mp->instance = (u_int) _thread; \ ! 281: bcopy((char *) _data, (char *) _mp->data, _size); \ ! 282: mbuff[_cpu]->free = (_ent+1) % mbuff_entries; \ ! 283: if (mbuff[_cpu]->free == 0) \ ! 284: mbuff[_cpu]->timestamp++; \ ! 285: splx(_s); \ ! 286: mp_enable_preemption(); \ ! 287: } \ ! 288: MACRO_END ! 289: ! 290: #define ETAP_PROBE(_event, _flags, _thread) \ ! 291: ETAP_PROBE_DATA_COND(_event, _flags, _thread, 0, 0, 1) ! 292: ! 293: #define ETAP_PROBE_DATA(_event, _flags, _thread, _data, _size) \ ! 294: ETAP_PROBE_DATA_COND(_event, _flags, _thread, _data, _size, \ ! 295: (_thread)->etap_trace) ! 296: ! 297: #define ETAP_DATA_LOAD(ed, x) ((ed) = (u_int) (x)) ! 298: #define ETAP_SET_REASON(_th, _reason) ((_th)->etap_reason = (_reason)) ! 299: ! 300: #else /* ETAP_EVENT_MONITOR */ ! 301: #define ETAP_PROBE(e,f,th) ! 302: #define ETAP_PROBE_DATA(e,f,th,d,s) ! 303: #define ETAP_PROBE_DATA_COND(e,f,th,d,s,c) ! 304: #define ETAP_DATA_LOAD(d,x); ! 305: #define ETAP_SET_REASON(t,r) ! 306: #endif /* ETAP_EVENT_MONITOR */ ! 307: ! 308: /* ! 309: * ================================= ! 310: * ETAP: general lock macros ! 311: * ================================= ! 312: */ ! 313: ! 314: #if ETAP_LOCK_TRACE ! 315: ! 316: #define ETAP_TOTAL_TIME(t,stop,start) \ ! 317: ETAP_TIME_SUB((t),(stop),(start)) ! 318: ! 319: #define ETAP_DURATION_TIMESTAMP(e,trace) \ ! 320: MACRO_BEGIN \ ! 321: if ((trace) & ETAP_DURATION) \ ! 322: ETAP_TIMESTAMP((e)->start_hold_time); \ ! 323: MACRO_END ! 324: ! 325: #define ETAP_COPY_START_HOLD_TIME(entry,time,trace) \ ! 326: MACRO_BEGIN \ ! 327: if ((trace) & ETAP_DURATION) \ ! 328: (entry)->start_hold_time = time; \ ! 329: MACRO_END ! 330: ! 331: #define ETAP_CONTENTION_TIMESTAMP(e,trace) \ ! 332: MACRO_BEGIN \ ! 333: if ((trace) & ETAP_CONTENTION) \ ! 334: ETAP_TIMESTAMP((e)->start_wait_time); \ ! 335: MACRO_END ! 336: ! 337: #define ETAP_STAMP(event_table,trace,dynamic) \ ! 338: MACRO_BEGIN \ ! 339: if ((event_table) != EVENT_TABLE_NULL) { \ ! 340: (dynamic) = (event_table)->dynamic; \ ! 341: (trace) = (event_table)->status; \ ! 342: } \ ! 343: MACRO_END ! 344: ! 345: #define ETAP_WHOLE_OP(l) \ ! 346: (!(ETAP_TIME_IS_ZERO((l)->u.s.start_hold_time))) ! 347: #define ETAP_DURATION_ENABLED(trace) ((trace) & ETAP_DURATION) ! 348: #define ETAP_CONTENTION_ENABLED(trace) ((trace) & ETAP_CONTENTION) ! 349: ! 350: /* ! 351: * The ETAP_CLEAR_TRACE_DATA macro sets the etap specific fields ! 352: * of the simple_lock_t structure to zero. ! 353: * ! 354: * This is always done just before a simple lock is released. ! 355: */ ! 356: ! 357: #define ETAP_CLEAR_TRACE_DATA(l) \ ! 358: MACRO_BEGIN \ ! 359: ETAP_TIME_CLEAR((l)->u.s.start_hold_time); \ ! 360: MON_CLEAR_PCS((l)); \ ! 361: MACRO_END ! 362: ! 363: ! 364: /* ================================================== ! 365: * The ETAP_XXX_ENTRY macros manipulate the locks ! 366: * start_list (a linked list of start data). ! 367: * ================================================== ! 368: */ ! 369: ! 370: #define ETAP_CREATE_ENTRY(entry,trace) \ ! 371: MACRO_BEGIN \ ! 372: if ((trace) & ETAP_TRACE_ON) \ ! 373: (entry) = get_start_data_node(); \ ! 374: MACRO_END ! 375: ! 376: #define ETAP_LINK_ENTRY(l,entry,trace) \ ! 377: MACRO_BEGIN \ ! 378: if ((trace) & ETAP_TRACE_ON) { \ ! 379: (entry)->next = (l)->u.s.start_list; \ ! 380: (l)->u.s.start_list = (entry); \ ! 381: (entry)->thread_id = (u_int) current_thread(); \ ! 382: ETAP_TIME_CLEAR((entry)->start_wait_time); \ ! 383: } \ ! 384: MACRO_END ! 385: ! 386: #define ETAP_FIND_ENTRY(l,entry,trace) \ ! 387: MACRO_BEGIN \ ! 388: u_int _ct; \ ! 389: _ct = (u_int) current_thread(); \ ! 390: (entry) = (l)->u.s.start_list; \ ! 391: while ((entry) != SD_ENTRY_NULL && (entry)->thread_id != _ct) \ ! 392: (entry) = (entry)->next; \ ! 393: if ((entry) == SD_ENTRY_NULL) \ ! 394: (trace) = 0; \ ! 395: MACRO_END ! 396: ! 397: #define ETAP_UNLINK_ENTRY(l,entry) \ ! 398: MACRO_BEGIN \ ! 399: boolean_t _first = TRUE; \ ! 400: start_data_node_t _prev; \ ! 401: u_int _ct; \ ! 402: _ct = (u_int) current_thread(); \ ! 403: (entry) = (l)->u.s.start_list; \ ! 404: while ((entry) != SD_ENTRY_NULL && (entry)->thread_id != _ct){ \ ! 405: _prev = (entry); \ ! 406: (entry) = (entry)->next; \ ! 407: _first = FALSE; \ ! 408: } \ ! 409: if (entry != SD_ENTRY_NULL) { \ ! 410: if (_first) \ ! 411: (l)->u.s.start_list = (entry)->next; \ ! 412: else \ ! 413: _prev->next = (entry)->next; \ ! 414: (entry)->next = SD_ENTRY_NULL; \ ! 415: } \ ! 416: MACRO_END ! 417: ! 418: #define ETAP_DESTROY_ENTRY(entry) \ ! 419: MACRO_BEGIN \ ! 420: if ((entry) != SD_ENTRY_NULL) \ ! 421: free_start_data_node ((entry)); \ ! 422: MACRO_END ! 423: ! 424: #else /* ETAP_LOCK_TRACE */ ! 425: #define ETAP_TOTAL_TIME(t,stop,start) ! 426: #define ETAP_DURATION_TIMESTAMP(le,tr) ! 427: #define ETAP_CONTENTION_TIMESTAMP(le,tr) ! 428: #define ETAP_COPY_START_HOLD_TIME(le,t,tr) ! 429: #define ETAP_STAMP(tt,tr,d) ! 430: #define ETAP_DURATION_ENABLED(tr) (0) /* always fails */ ! 431: #define ETAP_CONTENTION_ENABLED(tr) (0) /* always fails */ ! 432: #define ETAP_CLEAR_TRACE_DATA(l) ! 433: #define ETAP_CREATE_ENTRY(e,tr) ! 434: #define ETAP_LINK_ENTRY(l,e,tr) ! 435: #define ETAP_FIND_ENTRY(l,e,tr) ! 436: #define ETAP_UNLINK_ENTRY(l,e) ! 437: #define ETAP_DESTROY_ENTRY(e) ! 438: #endif /* ETAP_LOCK_TRACE */ ! 439: ! 440: #endif /* _KERN_ETAP_MACROS_H_ */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.