Annotation of XNU/osfmk/kern/etap_macros.h, revision 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.