Annotation of XNU/osfmk/kern/etap_macros.h, revision 1.1.1.1

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_ */

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.