Expose all EventLog events as DTrace probes
[ghc-hetmet.git] / rts / Trace.c
1 /* -----------------------------------------------------------------------------
2  *
3  * (c) The GHC Team 2006-2009
4  *
5  * Debug and performance tracing
6  *
7  * ---------------------------------------------------------------------------*/
8
9 // external headers
10 #include "Rts.h"
11
12 // internal headers
13 #include "Trace.h"
14
15 #ifdef TRACING
16
17 #include "GetTime.h"
18 #include "Stats.h"
19 #include "eventlog/EventLog.h"
20 #include "Threads.h"
21 #include "Printer.h"
22
23 #ifdef DEBUG
24 // debugging flags, set with +RTS -D<something>
25 int DEBUG_sched;
26 int DEBUG_interp;
27 int DEBUG_weak;
28 int DEBUG_gccafs;
29 int DEBUG_gc;
30 int DEBUG_block_alloc;
31 int DEBUG_sanity;
32 int DEBUG_stable;
33 int DEBUG_stm;
34 int DEBUG_prof;
35 int DEBUG_gran;
36 int DEBUG_par;
37 int DEBUG_linker;
38 int DEBUG_squeeze;
39 int DEBUG_hpc;
40 int DEBUG_sparks;
41 #endif
42
43 // events
44 int TRACE_sched;
45
46 #ifdef THREADED_RTS
47 static Mutex trace_utx;
48 #endif
49
50 static rtsBool eventlog_enabled;
51
52 /* ---------------------------------------------------------------------------
53    Starting up / shuttting down the tracing facilities
54  --------------------------------------------------------------------------- */
55
56 void initTracing (void)
57 {
58 #ifdef THREADED_RTS
59     initMutex(&trace_utx);
60 #endif
61
62 #ifdef DEBUG
63 #define DEBUG_FLAG(name, class) \
64     class = RtsFlags.DebugFlags.name ? 1 : 0;
65
66     DEBUG_FLAG(scheduler,    DEBUG_sched);
67
68     DEBUG_FLAG(interpreter,  DEBUG_interp);
69     DEBUG_FLAG(weak,         DEBUG_weak);
70     DEBUG_FLAG(gccafs,       DEBUG_gccafs);
71     DEBUG_FLAG(gc,           DEBUG_gc);
72     DEBUG_FLAG(block_alloc,  DEBUG_block_alloc);
73     DEBUG_FLAG(sanity,       DEBUG_sanity);
74     DEBUG_FLAG(stable,       DEBUG_stable);
75     DEBUG_FLAG(stm,          DEBUG_stm);
76     DEBUG_FLAG(prof,         DEBUG_prof);
77     DEBUG_FLAG(linker,       DEBUG_linker);
78     DEBUG_FLAG(squeeze,      DEBUG_squeeze);
79     DEBUG_FLAG(hpc,          DEBUG_hpc);
80     DEBUG_FLAG(sparks,       DEBUG_sparks);
81 #endif
82
83     // -Ds turns on scheduler tracing too
84     TRACE_sched =
85         RtsFlags.TraceFlags.scheduler ||
86         RtsFlags.DebugFlags.scheduler;
87
88     eventlog_enabled = RtsFlags.TraceFlags.tracing == TRACE_EVENTLOG;
89
90     if (eventlog_enabled) {
91         initEventLogging();
92     }
93 }
94
95 void endTracing (void)
96 {
97     if (eventlog_enabled) {
98         endEventLogging();
99     }
100 }
101
102 void freeTracing (void)
103 {
104     if (eventlog_enabled) {
105         freeEventLogging();
106     }
107 }
108
109 /* ---------------------------------------------------------------------------
110    Emitting trace messages/events
111  --------------------------------------------------------------------------- */
112
113 #ifdef DEBUG
114 static void tracePreface (void)
115 {
116 #ifdef THREADED_RTS
117     debugBelch("%12lx: ", (unsigned long)osThreadId());
118 #endif
119     if (RtsFlags.TraceFlags.timestamp) {
120         debugBelch("%9" FMT_Word64 ": ", stat_getElapsedTime());
121     }
122 }
123 #endif
124
125 #ifdef DEBUG
126 static char *thread_stop_reasons[] = {
127     [HeapOverflow] = "heap overflow",
128     [StackOverflow] = "stack overflow",
129     [ThreadYielding] = "yielding",
130     [ThreadBlocked] = "blocked",
131     [ThreadFinished] = "finished",
132     [THREAD_SUSPENDED_FOREIGN_CALL] = "suspended while making a foreign call"
133 };
134 #endif
135
136 #ifdef DEBUG
137 static void traceSchedEvent_stderr (Capability *cap, EventTypeNum tag, 
138                                     StgTSO *tso, 
139                                     StgWord64 other STG_UNUSED)
140 {
141     ACQUIRE_LOCK(&trace_utx);
142
143     tracePreface();
144     switch (tag) {
145     case EVENT_CREATE_THREAD:   // (cap, thread)
146         debugBelch("cap %d: created thread %lu\n", 
147                    cap->no, (lnat)tso->id);
148         break;
149     case EVENT_RUN_THREAD:      //  (cap, thread)
150         debugBelch("cap %d: running thread %lu (%s)\n", 
151                    cap->no, (lnat)tso->id, what_next_strs[tso->what_next]);
152         break;
153     case EVENT_THREAD_RUNNABLE: // (cap, thread)
154         debugBelch("cap %d: thread %lu appended to run queue\n", 
155                    cap->no, (lnat)tso->id);
156         break;
157     case EVENT_RUN_SPARK:       // (cap, thread)
158         debugBelch("cap %d: thread %lu running a spark\n", 
159                    cap->no, (lnat)tso->id);
160         break;
161     case EVENT_CREATE_SPARK_THREAD: // (cap, spark_thread)
162         debugBelch("cap %d: creating spark thread %lu\n", 
163                    cap->no, (long)other);
164         break;
165     case EVENT_MIGRATE_THREAD:  // (cap, thread, new_cap)
166         debugBelch("cap %d: thread %lu migrating to cap %d\n", 
167                    cap->no, (lnat)tso->id, (int)other);
168         break;
169     case EVENT_STEAL_SPARK:     // (cap, thread, victim_cap)
170         debugBelch("cap %d: thread %lu stealing a spark from cap %d\n", 
171                    cap->no, (lnat)tso->id, (int)other);
172         break;
173     case EVENT_THREAD_WAKEUP:   // (cap, thread, other_cap)
174         debugBelch("cap %d: waking up thread %lu on cap %d\n", 
175                    cap->no, (lnat)tso->id, (int)other);
176         break;
177         
178     case EVENT_STOP_THREAD:     // (cap, thread, status)
179         debugBelch("cap %d: thread %lu stopped (%s)\n", 
180                    cap->no, (lnat)tso->id, thread_stop_reasons[other]);
181         break;
182     case EVENT_SHUTDOWN:        // (cap)
183         debugBelch("cap %d: shutting down\n", cap->no);
184         break;
185     case EVENT_REQUEST_SEQ_GC:  // (cap)
186         debugBelch("cap %d: requesting sequential GC\n", cap->no);
187         break;
188     case EVENT_REQUEST_PAR_GC:  // (cap)
189         debugBelch("cap %d: requesting parallel GC\n", cap->no);
190         break;
191     case EVENT_GC_START:        // (cap)
192         debugBelch("cap %d: starting GC\n", cap->no);
193         break;
194     case EVENT_GC_END:          // (cap)
195         debugBelch("cap %d: finished GC\n", cap->no);
196         break;
197     case EVENT_GC_IDLE:        // (cap)
198         debugBelch("cap %d: GC idle\n", cap->no);
199         break;
200     case EVENT_GC_WORK:          // (cap)
201         debugBelch("cap %d: GC working\n", cap->no);
202         break;
203     case EVENT_GC_DONE:          // (cap)
204         debugBelch("cap %d: GC done\n", cap->no);
205         break;
206     default:
207         debugBelch("cap %2d: thread %lu: event %d\n\n", 
208                    cap->no, (lnat)tso->id, tag);
209         break;
210     }
211
212     RELEASE_LOCK(&trace_utx);
213 }
214 #endif
215
216 void traceSchedEvent_ (Capability *cap, EventTypeNum tag, 
217                       StgTSO *tso, StgWord64 other)
218 {
219 #ifdef DEBUG
220     if (RtsFlags.TraceFlags.tracing == TRACE_STDERR) {
221         traceSchedEvent_stderr(cap, tag, tso, other);
222     } else
223 #endif
224     {
225         postSchedEvent(cap,tag,tso ? tso->id : 0,other);
226     }
227 }
228
229 void traceEvent_ (Capability *cap, EventTypeNum tag)
230 {
231 #ifdef DEBUG
232     if (RtsFlags.TraceFlags.tracing == TRACE_STDERR) {
233         traceSchedEvent_stderr(cap, tag, 0, 0);
234     } else
235 #endif
236     {
237         postEvent(cap,tag);
238     }
239 }
240
241 #ifdef DEBUG
242 static void traceCap_stderr(Capability *cap, char *msg, va_list ap)
243 {
244     ACQUIRE_LOCK(&trace_utx);
245
246     tracePreface();
247     debugBelch("cap %2d: ", cap->no);
248     vdebugBelch(msg,ap);
249     debugBelch("\n");
250
251     RELEASE_LOCK(&trace_utx);
252 }
253 #endif
254
255 void traceCap_(Capability *cap, char *msg, ...)
256 {
257     va_list ap;
258     va_start(ap,msg);
259     
260 #ifdef DEBUG
261     if (RtsFlags.TraceFlags.tracing == TRACE_STDERR) {
262         traceCap_stderr(cap, msg, ap);
263     } else
264 #endif
265     {
266         postCapMsg(cap, msg, ap);
267     }
268
269     va_end(ap);
270 }
271
272 #ifdef DEBUG
273 static void trace_stderr(char *msg, va_list ap)
274 {
275     ACQUIRE_LOCK(&trace_utx);
276
277     tracePreface();
278     vdebugBelch(msg,ap);
279     debugBelch("\n");
280
281     RELEASE_LOCK(&trace_utx);
282 }
283 #endif
284
285 void trace_(char *msg, ...)
286 {
287     va_list ap;
288     va_start(ap,msg);
289
290 #ifdef DEBUG
291     if (RtsFlags.TraceFlags.tracing == TRACE_STDERR) {
292         trace_stderr(msg, ap);
293     } else
294 #endif
295     {
296         postMsg(msg, ap);
297     }
298
299     va_end(ap);
300 }
301
302 void traceUserMsg(Capability *cap, char *msg)
303 {
304 #ifdef DEBUG
305     if (RtsFlags.TraceFlags.tracing == TRACE_STDERR) {
306         traceCap_stderr(cap, msg, NULL);
307     } else
308 #endif
309     {
310         if (eventlog_enabled) {
311             postUserMsg(cap, msg);
312         }
313     }
314     dtraceUserMsg(cap->no, msg);
315 }
316
317 void traceThreadStatus_ (StgTSO *tso USED_IF_DEBUG)
318 {
319 #ifdef DEBUG
320     if (RtsFlags.TraceFlags.tracing == TRACE_STDERR) {
321         printThreadStatus(tso);
322     } else
323 #endif
324     {
325         /* nothing - no event for this one yet */
326     }
327 }
328
329
330 #ifdef DEBUG
331 void traceBegin (const char *str, ...)
332 {
333     va_list ap;
334     va_start(ap,str);
335
336     ACQUIRE_LOCK(&trace_utx);
337
338     tracePreface();
339     vdebugBelch(str,ap);
340 }
341
342 void traceEnd (void)
343 {
344     debugBelch("\n");
345     RELEASE_LOCK(&trace_utx);
346 }
347 #endif /* DEBUG */
348
349 #endif /* TRACING */
350
351 // If DTRACE is enabled, but neither DEBUG nor TRACING, we need a C land
352 // wrapper for the user-msg probe (as we can't expand that in PrimOps.cmm)
353 //
354 #if !defined(DEBUG) && !defined(TRACING) && defined(DTRACE)
355
356 void dtraceUserMsgWrapper(Capability *cap, char *msg)
357 {
358     dtraceUserMsg(cap->no, msg);
359 }
360
361 #endif /* !defined(DEBUG) && !defined(TRACING) && defined(DTRACE) */