|
|
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.