Merge branch 'master' of mac:ghc/git/val32/.
[ghc.git] / rts / Trace.h
1 /* -----------------------------------------------------------------------------
2 *
3 * (c) The GHC Team, 2008-2009
4 *
5 * Support for fast binary event logging and user-space dtrace probes.
6 *
7 * ---------------------------------------------------------------------------*/
8
9 #ifndef TRACE_H
10 #define TRACE_H
11
12 #include "rts/EventLogFormat.h"
13 #include "Capability.h"
14
15 #if defined(DTRACE)
16 #include "RtsProbes.h"
17 #endif /* defined(DTRACE) */
18
19 #include "BeginPrivate.h"
20
21 // -----------------------------------------------------------------------------
22 // EventLog API
23 // -----------------------------------------------------------------------------
24
25 #if defined(TRACING)
26
27 void initTracing (void);
28 void endTracing (void);
29 void freeTracing (void);
30 void resetTracing (void);
31
32 #endif /* TRACING */
33
34 typedef StgWord32 CapsetID;
35 typedef StgWord16 CapsetType;
36 enum CapsetType { CapsetTypeCustom = CAPSET_TYPE_CUSTOM,
37 CapsetTypeOsProcess = CAPSET_TYPE_OSPROCESS,
38 CapsetTypeClockdomain = CAPSET_TYPE_CLOCKDOMAIN };
39 #define CAPSET_OSPROCESS_DEFAULT 0
40 #define CAPSET_CLOCKDOMAIN_DEFAULT 1
41
42 // -----------------------------------------------------------------------------
43 // Message classes
44 // -----------------------------------------------------------------------------
45
46 // debugging flags, set with +RTS -D<something>
47 extern int DEBUG_sched;
48 extern int DEBUG_interp;
49 extern int DEBUG_weak;
50 extern int DEBUG_gccafs;
51 extern int DEBUG_gc;
52 extern int DEBUG_block_alloc;
53 extern int DEBUG_sanity;
54 extern int DEBUG_stable;
55 extern int DEBUG_stm;
56 extern int DEBUG_prof;
57 extern int DEBUG_gran;
58 extern int DEBUG_par;
59 extern int DEBUG_linker;
60 extern int DEBUG_squeeze;
61 extern int DEBUG_hpc;
62 extern int DEBUG_sparks;
63
64 // events
65 extern int TRACE_sched;
66 extern int TRACE_gc;
67 extern int TRACE_spark_sampled;
68 extern int TRACE_spark_full;
69
70 // -----------------------------------------------------------------------------
71 // Posting events
72 //
73 // We use macros rather than inline functions deliberately. We want
74 // the not-taken case to be as efficient as possible, a simple
75 // test-and-jump, and with inline functions gcc seemed to move some of
76 // the instructions from the branch up before the test.
77 //
78 // -----------------------------------------------------------------------------
79
80 #ifdef DEBUG
81 void traceBegin (const char *str, ...);
82 void traceEnd (void);
83 #endif
84
85 #ifdef TRACING
86
87 /*
88 * Record a scheduler event
89 */
90 #define traceSchedEvent(cap, tag, tso, other) \
91 if (RTS_UNLIKELY(TRACE_sched)) { \
92 traceSchedEvent_(cap, tag, tso, other, 0); \
93 }
94
95 #define traceSchedEvent2(cap, tag, tso, info1, info2) \
96 if (RTS_UNLIKELY(TRACE_sched)) { \
97 traceSchedEvent_(cap, tag, tso, info1, info2); \
98 }
99
100 void traceSchedEvent_ (Capability *cap, EventTypeNum tag,
101 StgTSO *tso, StgWord info1, StgWord info2);
102
103 /*
104 * Record a GC event
105 */
106 #define traceGcEvent(cap, tag) \
107 if (RTS_UNLIKELY(TRACE_gc)) { \
108 traceGcEvent_(cap, tag); \
109 }
110
111 void traceGcEvent_ (Capability *cap, EventTypeNum tag);
112
113 /*
114 * Record a spark event
115 */
116 #define traceSparkEvent(cap, tag) \
117 if (RTS_UNLIKELY(TRACE_spark_full)) { \
118 traceSparkEvent_(cap, tag, 0); \
119 }
120
121 #define traceSparkEvent2(cap, tag, other) \
122 if (RTS_UNLIKELY(TRACE_spark_full)) { \
123 traceSparkEvent_(cap, tag, other); \
124 }
125
126 void traceSparkEvent_ (Capability *cap, EventTypeNum tag, StgWord info1);
127
128 // variadic macros are C99, and supported by gcc. However, the
129 // ##__VA_ARGS syntax is a gcc extension, which allows the variable
130 // argument list to be empty (see gcc docs for details).
131
132 /*
133 * Emit a trace message on a particular Capability
134 */
135 #define traceCap(class, cap, msg, ...) \
136 if (RTS_UNLIKELY(class)) { \
137 traceCap_(cap, msg, ##__VA_ARGS__); \
138 }
139
140 void traceCap_(Capability *cap, char *msg, ...);
141
142 /*
143 * Emit a trace message
144 */
145 #define trace(class, msg, ...) \
146 if (RTS_UNLIKELY(class)) { \
147 trace_(msg, ##__VA_ARGS__); \
148 }
149
150 void trace_(char *msg, ...);
151
152 /*
153 * A message or event emitted by the program
154 */
155 void traceUserMsg(Capability *cap, char *msg);
156
157 /*
158 * Emit a debug message (only when DEBUG is defined)
159 */
160 #ifdef DEBUG
161 #define debugTrace(class, msg, ...) \
162 if (RTS_UNLIKELY(class)) { \
163 trace_(msg, ##__VA_ARGS__); \
164 }
165 #else
166 #define debugTrace(class, str, ...) /* nothing */
167 #endif
168
169 #ifdef DEBUG
170 #define debugTraceCap(class, cap, msg, ...) \
171 if (RTS_UNLIKELY(class)) { \
172 traceCap_(cap, msg, ##__VA_ARGS__); \
173 }
174 #else
175 #define debugTraceCap(class, cap, str, ...) /* nothing */
176 #endif
177
178 /*
179 * Emit a message/event describing the state of a thread
180 */
181 #define traceThreadStatus(class, tso) \
182 if (RTS_UNLIKELY(class)) { \
183 traceThreadStatus_(tso); \
184 }
185
186 void traceThreadStatus_ (StgTSO *tso);
187
188 void traceEventStartup_ (int n_caps);
189
190 /*
191 * Events for describing capability sets in the eventlog
192 *
193 * Note: unlike other events, these are not conditional on TRACE_sched or
194 * similar because they are not "real" events themselves but provide
195 * information and context for other "real" events. Other events depend on
196 * the capset info events so for simplicity, rather than working out if
197 * they're necessary we always emit them. They should be very low volume.
198 */
199 void traceCapsetEvent_ (EventTypeNum tag,
200 CapsetID capset,
201 StgWord info);
202
203 void traceWallClockTime_(void);
204
205 void traceOSProcessInfo_ (void);
206
207 void traceSparkCounters_ (Capability *cap,
208 SparkCounters counters,
209 StgWord remaining);
210
211 #else /* !TRACING */
212
213 #define traceSchedEvent(cap, tag, tso, other) /* nothing */
214 #define traceSchedEvent2(cap, tag, tso, other, info) /* nothing */
215 #define traceGcEvent(cap, tag) /* nothing */
216 #define traceSparkEvent(cap, tag) /* nothing */
217 #define traceSparkEvent2(cap, tag, other) /* nothing */
218 #define traceCap(class, cap, msg, ...) /* nothing */
219 #define trace(class, msg, ...) /* nothing */
220 #define debugTrace(class, str, ...) /* nothing */
221 #define debugTraceCap(class, cap, str, ...) /* nothing */
222 #define traceThreadStatus(class, tso) /* nothing */
223 INLINE_HEADER void traceEventStartup_ (int n_caps STG_UNUSED) {};
224 #define traceCapsetEvent_(tag, capset, info) /* nothing */
225 #define traceWallClockTime_() /* nothing */
226 #define traceOSProcessInfo_() /* nothing */
227 #define traceSparkCounters_(cap, counters, remaining) /* nothing */
228
229 #endif /* TRACING */
230
231 // If DTRACE is enabled, but neither DEBUG nor TRACING, we need a C land
232 // wrapper for the user-msg probe (as we can't expand that in PrimOps.cmm)
233 //
234 #if !defined(DEBUG) && !defined(TRACING) && defined(DTRACE)
235
236 void dtraceUserMsgWrapper(Capability *cap, char *msg);
237
238 #endif /* !defined(DEBUG) && !defined(TRACING) && defined(DTRACE) */
239
240 // -----------------------------------------------------------------------------
241 // Aliases for static dtrace probes if dtrace is available
242 // -----------------------------------------------------------------------------
243
244 #if defined(DTRACE)
245
246 #define dtraceCreateThread(cap, tid) \
247 HASKELLEVENT_CREATE_THREAD(cap, tid)
248 #define dtraceRunThread(cap, tid) \
249 HASKELLEVENT_RUN_THREAD(cap, tid)
250 #define dtraceStopThread(cap, tid, status, info) \
251 HASKELLEVENT_STOP_THREAD(cap, tid, status, info)
252 #define dtraceThreadRunnable(cap, tid) \
253 HASKELLEVENT_THREAD_RUNNABLE(cap, tid)
254 #define dtraceMigrateThread(cap, tid, new_cap) \
255 HASKELLEVENT_MIGRATE_THREAD(cap, tid, new_cap)
256 #define dtraceShutdown(cap) \
257 HASKELLEVENT_SHUTDOWN(cap)
258 #define dtraceThreadWakeup(cap, tid, other_cap) \
259 HASKELLEVENT_THREAD_WAKEUP(cap, tid, other_cap)
260 #define dtraceGcStart(cap) \
261 HASKELLEVENT_GC_START(cap)
262 #define dtraceGcEnd(cap) \
263 HASKELLEVENT_GC_END(cap)
264 #define dtraceRequestSeqGc(cap) \
265 HASKELLEVENT_REQUEST_SEQ_GC(cap)
266 #define dtraceRequestParGc(cap) \
267 HASKELLEVENT_REQUEST_PAR_GC(cap)
268 #define dtraceCreateSparkThread(cap, spark_tid) \
269 HASKELLEVENT_CREATE_SPARK_THREAD(cap, spark_tid)
270 INLINE_HEADER void dtraceStartup (int num_caps) {
271 HASKELLEVENT_STARTUP(num_caps);
272 }
273 #define dtraceUserMsg(cap, msg) \
274 HASKELLEVENT_USER_MSG(cap, msg)
275 #define dtraceGcIdle(cap) \
276 HASKELLEVENT_GC_IDLE(cap)
277 #define dtraceGcWork(cap) \
278 HASKELLEVENT_GC_WORK(cap)
279 #define dtraceGcDone(cap) \
280 HASKELLEVENT_GC_DONE(cap)
281 #define dtraceCapsetCreate(capset, capset_type) \
282 HASKELLEVENT_CAPSET_CREATE(capset, capset_type)
283 #define dtraceCapsetDelete(capset) \
284 HASKELLEVENT_CAPSET_DELETE(capset)
285 #define dtraceCapsetAssignCap(capset, capno) \
286 HASKELLEVENT_CAPSET_ASSIGN_CAP(capset, capno)
287 #define dtraceCapsetRemoveCap(capset, capno) \
288 HASKELLEVENT_CAPSET_REMOVE_CAP(capset, capno)
289 #define dtraceSparkCounters(cap, a, b, c, d, e, f, g) \
290 HASKELLEVENT_SPARK_COUNTERS(cap, a, b, c, d, e, f, g)
291 #define dtraceSparkCreate(cap) \
292 HASKELLEVENT_SPARK_CREATE(cap)
293 #define dtraceSparkDud(cap) \
294 HASKELLEVENT_SPARK_DUD(cap)
295 #define dtraceSparkOverflow(cap) \
296 HASKELLEVENT_SPARK_OVERFLOW(cap)
297 #define dtraceSparkRun(cap) \
298 HASKELLEVENT_SPARK_RUN(cap)
299 #define dtraceSparkSteal(cap, victim_cap) \
300 HASKELLEVENT_SPARK_STEAL(cap, victim_cap)
301 #define dtraceSparkFizzle(cap) \
302 HASKELLEVENT_SPARK_FIZZLE(cap)
303 #define dtraceSparkGc(cap) \
304 HASKELLEVENT_SPARK_GC(cap)
305
306 #else /* !defined(DTRACE) */
307
308 #define dtraceCreateThread(cap, tid) /* nothing */
309 #define dtraceRunThread(cap, tid) /* nothing */
310 #define dtraceStopThread(cap, tid, status, info) /* nothing */
311 #define dtraceThreadRunnable(cap, tid) /* nothing */
312 #define dtraceMigrateThread(cap, tid, new_cap) /* nothing */
313 #define dtraceShutdown(cap) /* nothing */
314 #define dtraceThreadWakeup(cap, tid, other_cap) /* nothing */
315 #define dtraceGcStart(cap) /* nothing */
316 #define dtraceGcEnd(cap) /* nothing */
317 #define dtraceRequestSeqGc(cap) /* nothing */
318 #define dtraceRequestParGc(cap) /* nothing */
319 #define dtraceCreateSparkThread(cap, spark_tid) /* nothing */
320 INLINE_HEADER void dtraceStartup (int num_caps STG_UNUSED) {};
321 #define dtraceUserMsg(cap, msg) /* nothing */
322 #define dtraceGcIdle(cap) /* nothing */
323 #define dtraceGcWork(cap) /* nothing */
324 #define dtraceGcDone(cap) /* nothing */
325 #define dtraceCapsetCreate(capset, capset_type) /* nothing */
326 #define dtraceCapsetDelete(capset) /* nothing */
327 #define dtraceCapsetAssignCap(capset, capno) /* nothing */
328 #define dtraceCapsetRemoveCap(capset, capno) /* nothing */
329 #define dtraceSparkCounters(cap, a, b, c, d, e, f, g) /* nothing */
330 #define dtraceSparkCreate(cap) /* nothing */
331 #define dtraceSparkDud(cap) /* nothing */
332 #define dtraceSparkOverflow(cap) /* nothing */
333 #define dtraceSparkRun(cap) /* nothing */
334 #define dtraceSparkSteal(cap, victim_cap) /* nothing */
335 #define dtraceSparkFizzle(cap) /* nothing */
336 #define dtraceSparkGc(cap) /* nothing */
337
338 #endif
339
340 // -----------------------------------------------------------------------------
341 // Trace probes dispatching to various tracing frameworks
342 //
343 // In order to avoid accumulating multiple calls to tracing calls at trace
344 // points, we define inline probe functions that contain the various
345 // invocations.
346 //
347 // Dtrace - dtrace probes are unconditionally added as probe activation is
348 // handled by the dtrace component of the kernel, and inactive probes are
349 // very cheap — usually, one no-op. Consequently, dtrace can be used with
350 // all flavours of the RTS. In addition, we still support logging events to
351 // a file, even in the presence of dtrace. This is, eg, useful when tracing
352 // on a server, but browsing trace information with ThreadScope on a local
353 // client.
354 //
355 // -----------------------------------------------------------------------------
356
357 INLINE_HEADER void traceEventCreateThread(Capability *cap STG_UNUSED,
358 StgTSO *tso STG_UNUSED)
359 {
360 traceSchedEvent(cap, EVENT_CREATE_THREAD, tso, tso->stackobj->stack_size);
361 dtraceCreateThread((EventCapNo)cap->no, (EventThreadID)tso->id);
362 }
363
364 INLINE_HEADER void traceEventRunThread(Capability *cap STG_UNUSED,
365 StgTSO *tso STG_UNUSED)
366 {
367 traceSchedEvent(cap, EVENT_RUN_THREAD, tso, tso->what_next);
368 dtraceRunThread((EventCapNo)cap->no, (EventThreadID)tso->id);
369 }
370
371 INLINE_HEADER void traceEventStopThread(Capability *cap STG_UNUSED,
372 StgTSO *tso STG_UNUSED,
373 StgThreadReturnCode status STG_UNUSED,
374 StgWord32 info STG_UNUSED)
375 {
376 traceSchedEvent2(cap, EVENT_STOP_THREAD, tso, status, info);
377 dtraceStopThread((EventCapNo)cap->no, (EventThreadID)tso->id,
378 (EventThreadStatus)status, (EventThreadID)info);
379 }
380
381 // needs to be EXTERN_INLINE as it is used in another EXTERN_INLINE function
382 EXTERN_INLINE void traceEventThreadRunnable(Capability *cap STG_UNUSED,
383 StgTSO *tso STG_UNUSED);
384
385 EXTERN_INLINE void traceEventThreadRunnable(Capability *cap STG_UNUSED,
386 StgTSO *tso STG_UNUSED)
387 {
388 traceSchedEvent(cap, EVENT_THREAD_RUNNABLE, tso, 0);
389 dtraceThreadRunnable((EventCapNo)cap->no, (EventThreadID)tso->id);
390 }
391
392 INLINE_HEADER void traceEventMigrateThread(Capability *cap STG_UNUSED,
393 StgTSO *tso STG_UNUSED,
394 nat new_cap STG_UNUSED)
395 {
396 traceSchedEvent(cap, EVENT_MIGRATE_THREAD, tso, new_cap);
397 dtraceMigrateThread((EventCapNo)cap->no, (EventThreadID)tso->id,
398 (EventCapNo)new_cap);
399 }
400
401 INLINE_HEADER void traceEventShutdown(Capability *cap STG_UNUSED)
402 {
403 traceSchedEvent(cap, EVENT_SHUTDOWN, 0, 0);
404 dtraceShutdown((EventCapNo)cap->no);
405 }
406
407 INLINE_HEADER void traceEventThreadWakeup(Capability *cap STG_UNUSED,
408 StgTSO *tso STG_UNUSED,
409 nat other_cap STG_UNUSED)
410 {
411 traceSchedEvent(cap, EVENT_THREAD_WAKEUP, tso, other_cap);
412 dtraceThreadWakeup((EventCapNo)cap->no, (EventThreadID)tso->id,
413 (EventCapNo)other_cap);
414 }
415
416 INLINE_HEADER void traceEventGcStart(Capability *cap STG_UNUSED)
417 {
418 traceGcEvent(cap, EVENT_GC_START);
419 dtraceGcStart((EventCapNo)cap->no);
420 }
421
422 INLINE_HEADER void traceEventGcEnd(Capability *cap STG_UNUSED)
423 {
424 traceGcEvent(cap, EVENT_GC_END);
425 dtraceGcEnd((EventCapNo)cap->no);
426 }
427
428 INLINE_HEADER void traceEventRequestSeqGc(Capability *cap STG_UNUSED)
429 {
430 traceGcEvent(cap, EVENT_REQUEST_SEQ_GC);
431 dtraceRequestSeqGc((EventCapNo)cap->no);
432 }
433
434 INLINE_HEADER void traceEventRequestParGc(Capability *cap STG_UNUSED)
435 {
436 traceGcEvent(cap, EVENT_REQUEST_PAR_GC);
437 dtraceRequestParGc((EventCapNo)cap->no);
438 }
439
440 INLINE_HEADER void traceEventGcIdle(Capability *cap STG_UNUSED)
441 {
442 traceGcEvent(cap, EVENT_GC_IDLE);
443 dtraceGcIdle((EventCapNo)cap->no);
444 }
445
446 INLINE_HEADER void traceEventGcWork(Capability *cap STG_UNUSED)
447 {
448 traceGcEvent(cap, EVENT_GC_WORK);
449 dtraceGcWork((EventCapNo)cap->no);
450 }
451
452 INLINE_HEADER void traceEventGcDone(Capability *cap STG_UNUSED)
453 {
454 traceGcEvent(cap, EVENT_GC_DONE);
455 dtraceGcDone((EventCapNo)cap->no);
456 }
457
458 INLINE_HEADER void traceEventStartup(void)
459 {
460 int n_caps;
461 #ifdef THREADED_RTS
462 // XXX n_capabilities hasn't been initialised yet
463 n_caps = RtsFlags.ParFlags.nNodes;
464 #else
465 n_caps = 1;
466 #endif
467
468 traceEventStartup_(n_caps);
469 dtraceStartup(n_caps);
470 }
471
472 INLINE_HEADER void traceCapsetCreate(CapsetID capset STG_UNUSED,
473 CapsetType capset_type STG_UNUSED)
474 {
475 traceCapsetEvent_(EVENT_CAPSET_CREATE, capset, capset_type);
476 dtraceCapsetCreate(capset, capset_type);
477 }
478
479 INLINE_HEADER void traceCapsetDelete(CapsetID capset STG_UNUSED)
480 {
481 traceCapsetEvent_(EVENT_CAPSET_DELETE, capset, 0);
482 dtraceCapsetDelete(capset);
483 }
484
485 INLINE_HEADER void traceCapsetAssignCap(CapsetID capset STG_UNUSED,
486 nat capno STG_UNUSED)
487 {
488 traceCapsetEvent_(EVENT_CAPSET_ASSIGN_CAP, capset, capno);
489 dtraceCapsetAssignCap(capset, capno);
490 }
491
492 INLINE_HEADER void traceCapsetRemoveCap(CapsetID capset STG_UNUSED,
493 nat capno STG_UNUSED)
494 {
495 traceCapsetEvent_(EVENT_CAPSET_REMOVE_CAP, capset, capno);
496 dtraceCapsetRemoveCap(capset, capno);
497 }
498
499 INLINE_HEADER void traceWallClockTime(void)
500 {
501 traceWallClockTime_();
502 /* Note: no DTrace equivalent because it is available to DTrace directly */
503 }
504
505 INLINE_HEADER void traceOSProcessInfo(void)
506 {
507 traceOSProcessInfo_();
508 /* Note: no DTrace equivalent because all this OS process info
509 * is available to DTrace directly */
510 }
511
512 INLINE_HEADER void traceEventCreateSparkThread(Capability *cap STG_UNUSED,
513 StgThreadID spark_tid STG_UNUSED)
514 {
515 traceSparkEvent2(cap, EVENT_CREATE_SPARK_THREAD, spark_tid);
516 dtraceCreateSparkThread((EventCapNo)cap->no, (EventThreadID)spark_tid);
517 }
518
519 INLINE_HEADER void traceSparkCounters(Capability *cap STG_UNUSED)
520 {
521 #ifdef THREADED_RTS
522 if (RTS_UNLIKELY(TRACE_spark_sampled)) {
523 traceSparkCounters_(cap, cap->spark_stats, sparkPoolSize(cap->sparks));
524 }
525 dtraceSparkCounters((EventCapNo)cap->no,
526 cap->spark_stats.created,
527 cap->spark_stats.dud,
528 cap->spark_stats.overflowed,
529 cap->spark_stats.converted,
530 cap->spark_stats.gcd,
531 cap->spark_stats.fizzled,
532 sparkPoolSize(cap->sparks));
533 #endif
534 }
535
536 INLINE_HEADER void traceEventSparkCreate(Capability *cap STG_UNUSED)
537 {
538 traceSparkEvent(cap, EVENT_SPARK_CREATE);
539 dtraceSparkCreate((EventCapNo)cap->no);
540 }
541
542 INLINE_HEADER void traceEventSparkDud(Capability *cap STG_UNUSED)
543 {
544 traceSparkEvent(cap, EVENT_SPARK_DUD);
545 dtraceSparkDud((EventCapNo)cap->no);
546 }
547
548 INLINE_HEADER void traceEventSparkOverflow(Capability *cap STG_UNUSED)
549 {
550 traceSparkEvent(cap, EVENT_SPARK_OVERFLOW);
551 dtraceSparkOverflow((EventCapNo)cap->no);
552 }
553
554 INLINE_HEADER void traceEventSparkRun(Capability *cap STG_UNUSED)
555 {
556 traceSparkEvent(cap, EVENT_SPARK_RUN);
557 dtraceSparkRun((EventCapNo)cap->no);
558 }
559
560 INLINE_HEADER void traceEventSparkSteal(Capability *cap STG_UNUSED,
561 nat victim_cap STG_UNUSED)
562 {
563 traceSparkEvent2(cap, EVENT_SPARK_STEAL, victim_cap);
564 dtraceSparkSteal((EventCapNo)cap->no, (EventCapNo)victim_cap);
565 }
566
567 INLINE_HEADER void traceEventSparkFizzle(Capability *cap STG_UNUSED)
568 {
569 traceSparkEvent(cap, EVENT_SPARK_FIZZLE);
570 dtraceSparkFizzle((EventCapNo)cap->no);
571 }
572
573 INLINE_HEADER void traceEventSparkGC(Capability *cap STG_UNUSED)
574 {
575 traceSparkEvent(cap, EVENT_SPARK_GC);
576 dtraceSparkGc((EventCapNo)cap->no);
577 }
578
579 #include "EndPrivate.h"
580
581 #endif /* TRACE_H */