1 /* -----------------------------------------------------------------------------
3 * (c) The GHC Team 2006-2009
5 * Debug and performance tracing
7 * ---------------------------------------------------------------------------*/
20 #include "eventlog/EventLog.h"
29 // debugging flags, set with +RTS -D<something>
35 int DEBUG_block_alloc
;
53 static Mutex trace_utx
;
56 static rtsBool eventlog_enabled
;
58 /* ---------------------------------------------------------------------------
59 Starting up / shuttting down the tracing facilities
60 --------------------------------------------------------------------------- */
62 void initTracing (void)
65 initMutex(&trace_utx
);
69 #define DEBUG_FLAG(name, class) \
70 class = RtsFlags.DebugFlags.name ? 1 : 0;
72 DEBUG_FLAG(scheduler
, DEBUG_sched
);
74 DEBUG_FLAG(interpreter
, DEBUG_interp
);
75 DEBUG_FLAG(weak
, DEBUG_weak
);
76 DEBUG_FLAG(gccafs
, DEBUG_gccafs
);
77 DEBUG_FLAG(gc
, DEBUG_gc
);
78 DEBUG_FLAG(block_alloc
, DEBUG_block_alloc
);
79 DEBUG_FLAG(sanity
, DEBUG_sanity
);
80 DEBUG_FLAG(stable
, DEBUG_stable
);
81 DEBUG_FLAG(stm
, DEBUG_stm
);
82 DEBUG_FLAG(prof
, DEBUG_prof
);
83 DEBUG_FLAG(linker
, DEBUG_linker
);
84 DEBUG_FLAG(squeeze
, DEBUG_squeeze
);
85 DEBUG_FLAG(hpc
, DEBUG_hpc
);
86 DEBUG_FLAG(sparks
, DEBUG_sparks
);
89 // -Ds turns on scheduler tracing too
91 RtsFlags
.TraceFlags
.scheduler
||
92 RtsFlags
.DebugFlags
.scheduler
;
94 // -Dr turns on spark tracing
96 RtsFlags
.TraceFlags
.sparks
||
97 RtsFlags
.DebugFlags
.sparks
;
99 eventlog_enabled
= RtsFlags
.TraceFlags
.tracing
== TRACE_EVENTLOG
;
101 /* Note: we can have TRACE_sched or TRACE_spark turned on even when
102 eventlog_enabled is off. In the DEBUG way we may be tracing to stderr.
105 if (eventlog_enabled
) {
110 void endTracing (void)
112 if (eventlog_enabled
) {
117 void freeTracing (void)
119 if (eventlog_enabled
) {
124 void resetTracing (void)
126 if (eventlog_enabled
) {
127 abortEventLogging(); // abort eventlog inherited from parent
128 initEventLogging(); // child starts its own eventlog
132 /* ---------------------------------------------------------------------------
133 Emitting trace messages/events
134 --------------------------------------------------------------------------- */
137 static void tracePreface (void)
140 debugBelch("%12lx: ", (unsigned long)osThreadId());
142 if (RtsFlags
.TraceFlags
.timestamp
) {
143 debugBelch("%9" FMT_Word64
": ", stat_getElapsedTime());
149 static char *thread_stop_reasons
[] = {
150 [HeapOverflow
] = "heap overflow",
151 [StackOverflow
] = "stack overflow",
152 [ThreadYielding
] = "yielding",
153 [ThreadBlocked
] = "blocked",
154 [ThreadFinished
] = "finished",
155 [THREAD_SUSPENDED_FOREIGN_CALL
] = "suspended while making a foreign call",
156 [6 + BlockedOnMVar
] = "blocked on an MVar",
157 [6 + BlockedOnBlackHole
] = "blocked on a black hole",
158 [6 + BlockedOnRead
] = "blocked on a read operation",
159 [6 + BlockedOnWrite
] = "blocked on a write operation",
160 [6 + BlockedOnDelay
] = "blocked on a delay operation",
161 [6 + BlockedOnSTM
] = "blocked on STM",
162 [6 + BlockedOnDoProc
] = "blocked on asyncDoProc",
163 [6 + BlockedOnCCall
] = "blocked on a foreign call",
164 [6 + BlockedOnCCall_Interruptible
] = "blocked on a foreign call (interruptible)",
165 [6 + BlockedOnMsgThrowTo
] = "blocked on throwTo",
166 [6 + ThreadMigrating
] = "migrating"
171 static void traceSchedEvent_stderr (Capability
*cap
, EventTypeNum tag
,
173 StgWord info1 STG_UNUSED
,
174 StgWord info2 STG_UNUSED
)
176 ACQUIRE_LOCK(&trace_utx
);
180 case EVENT_CREATE_THREAD
: // (cap, thread)
181 debugBelch("cap %d: created thread %lu\n",
182 cap
->no
, (lnat
)tso
->id
);
184 case EVENT_RUN_THREAD
: // (cap, thread)
185 debugBelch("cap %d: running thread %lu (%s)\n",
186 cap
->no
, (lnat
)tso
->id
, what_next_strs
[tso
->what_next
]);
188 case EVENT_THREAD_RUNNABLE
: // (cap, thread)
189 debugBelch("cap %d: thread %lu appended to run queue\n",
190 cap
->no
, (lnat
)tso
->id
);
192 case EVENT_RUN_SPARK
: // (cap, thread)
193 debugBelch("cap %d: thread %lu running a spark\n",
194 cap
->no
, (lnat
)tso
->id
);
196 case EVENT_CREATE_SPARK_THREAD
: // (cap, spark_thread)
197 debugBelch("cap %d: creating spark thread %lu\n",
198 cap
->no
, (long)info1
);
200 case EVENT_MIGRATE_THREAD
: // (cap, thread, new_cap)
201 debugBelch("cap %d: thread %lu migrating to cap %d\n",
202 cap
->no
, (lnat
)tso
->id
, (int)info1
);
204 case EVENT_STEAL_SPARK
: // (cap, thread, victim_cap)
205 debugBelch("cap %d: thread %lu stealing a spark from cap %d\n",
206 cap
->no
, (lnat
)tso
->id
, (int)info1
);
208 case EVENT_THREAD_WAKEUP
: // (cap, thread, info1_cap)
209 debugBelch("cap %d: waking up thread %lu on cap %d\n",
210 cap
->no
, (lnat
)tso
->id
, (int)info1
);
213 case EVENT_STOP_THREAD
: // (cap, thread, status)
214 if (info1
== 6 + BlockedOnBlackHole
) {
215 debugBelch("cap %d: thread %lu stopped (blocked on black hole owned by thread %lu)\n",
216 cap
->no
, (lnat
)tso
->id
, (long)info2
);
218 debugBelch("cap %d: thread %lu stopped (%s)\n",
219 cap
->no
, (lnat
)tso
->id
, thread_stop_reasons
[info1
]);
222 case EVENT_SHUTDOWN
: // (cap)
223 debugBelch("cap %d: shutting down\n", cap
->no
);
225 case EVENT_REQUEST_SEQ_GC
: // (cap)
226 debugBelch("cap %d: requesting sequential GC\n", cap
->no
);
228 case EVENT_REQUEST_PAR_GC
: // (cap)
229 debugBelch("cap %d: requesting parallel GC\n", cap
->no
);
231 case EVENT_GC_START
: // (cap)
232 debugBelch("cap %d: starting GC\n", cap
->no
);
234 case EVENT_GC_END
: // (cap)
235 debugBelch("cap %d: finished GC\n", cap
->no
);
237 case EVENT_GC_IDLE
: // (cap)
238 debugBelch("cap %d: GC idle\n", cap
->no
);
240 case EVENT_GC_WORK
: // (cap)
241 debugBelch("cap %d: GC working\n", cap
->no
);
243 case EVENT_GC_DONE
: // (cap)
244 debugBelch("cap %d: GC done\n", cap
->no
);
247 debugBelch("cap %d: thread %lu: event %d\n\n",
248 cap
->no
, (lnat
)tso
->id
, tag
);
252 RELEASE_LOCK(&trace_utx
);
256 void traceSchedEvent_ (Capability
*cap
, EventTypeNum tag
,
257 StgTSO
*tso
, StgWord info1
, StgWord info2
)
260 if (RtsFlags
.TraceFlags
.tracing
== TRACE_STDERR
) {
261 traceSchedEvent_stderr(cap
, tag
, tso
, info1
, info2
);
265 postSchedEvent(cap
,tag
,tso ? tso
->id
: 0, info1
, info2
);
269 void traceCapsetModify_ (EventTypeNum tag
,
274 if (RtsFlags
.TraceFlags
.tracing
== TRACE_STDERR
) {
275 ACQUIRE_LOCK(&trace_utx
);
279 case EVENT_CAPSET_CREATE
: // (capset, capset_type)
280 debugBelch("created capset %lu of type %d\n", (lnat
)capset
, (int)other
);
282 case EVENT_CAPSET_DELETE
: // (capset)
283 debugBelch("deleted capset %lu\n", (lnat
)capset
);
285 case EVENT_CAPSET_ASSIGN_CAP
: // (capset, capno)
286 debugBelch("assigned cap %lu to capset %lu\n",
287 (lnat
)other
, (lnat
)capset
);
289 case EVENT_CAPSET_REMOVE_CAP
: // (capset, capno)
290 debugBelch("removed cap %lu from capset %lu\n",
291 (lnat
)other
, (lnat
)capset
);
294 RELEASE_LOCK(&trace_utx
);
298 if (eventlog_enabled
) {
299 postCapsetModifyEvent(tag
, capset
, other
);
304 void traceOSProcessInfo_(void) {
305 if (eventlog_enabled
) {
306 postCapsetModifyEvent(EVENT_OSPROCESS_PID
,
307 CAPSET_OSPROCESS_DEFAULT
,
310 #if !defined(cygwin32_HOST_OS) && !defined (mingw32_HOST_OS)
311 /* Windows has no strong concept of process heirarchy, so no getppid().
312 * In any case, this trace event is mainly useful for tracing programs
313 * that use 'forkProcess' which Windows doesn't support anyway.
315 postCapsetModifyEvent(EVENT_OSPROCESS_PPID
,
316 CAPSET_OSPROCESS_DEFAULT
,
321 snprintf(buf
, sizeof(buf
), "GHC-%s %s", ProjectVersion
, RtsWay
);
322 postCapsetStrEvent(EVENT_RTS_IDENTIFIER
,
323 CAPSET_OSPROCESS_DEFAULT
,
327 int argc
= 0; char **argv
;
328 getFullProgArgv(&argc
, &argv
);
330 postCapsetVecEvent(EVENT_PROGRAM_ARGS
,
331 CAPSET_OSPROCESS_DEFAULT
,
336 int envc
= 0; char **envv
;
337 getProgEnvv(&envc
, &envv
);
339 postCapsetVecEvent(EVENT_PROGRAM_ENV
,
340 CAPSET_OSPROCESS_DEFAULT
,
343 freeProgEnvv(envc
, envv
);
348 void traceSparkCounters_ (Capability
*cap
,
349 SparkCounters counters
,
353 if (RtsFlags
.TraceFlags
.tracing
== TRACE_STDERR
) {
354 /* we currently don't do debug tracing of spark stats but we must
355 test for TRACE_STDERR because of the !eventlog_enabled case. */
359 postSparkCountersEvent(cap
, counters
, remaining
);
364 void traceEvent_ (Capability
*cap
, EventTypeNum tag
)
367 if (RtsFlags
.TraceFlags
.tracing
== TRACE_STDERR
) {
368 traceSchedEvent_stderr(cap
, tag
, 0, 0, 0);
377 static void traceCap_stderr(Capability
*cap
, char *msg
, va_list ap
)
379 ACQUIRE_LOCK(&trace_utx
);
382 debugBelch("cap %d: ", cap
->no
);
386 RELEASE_LOCK(&trace_utx
);
390 void traceCap_(Capability
*cap
, char *msg
, ...)
396 if (RtsFlags
.TraceFlags
.tracing
== TRACE_STDERR
) {
397 traceCap_stderr(cap
, msg
, ap
);
401 postCapMsg(cap
, msg
, ap
);
408 static void trace_stderr(char *msg
, va_list ap
)
410 ACQUIRE_LOCK(&trace_utx
);
416 RELEASE_LOCK(&trace_utx
);
420 void trace_(char *msg
, ...)
426 if (RtsFlags
.TraceFlags
.tracing
== TRACE_STDERR
) {
427 trace_stderr(msg
, ap
);
437 static void traceFormatUserMsg(Capability
*cap
, char *msg
, ...)
443 if (RtsFlags
.TraceFlags
.tracing
== TRACE_STDERR
) {
444 traceCap_stderr(cap
, msg
, ap
);
448 if (eventlog_enabled
) {
449 postUserMsg(cap
, msg
, ap
);
452 dtraceUserMsg(cap
->no
, msg
);
455 void traceUserMsg(Capability
*cap
, char *msg
)
457 traceFormatUserMsg(cap
, "%s", msg
);
460 void traceThreadStatus_ (StgTSO
*tso USED_IF_DEBUG
)
463 if (RtsFlags
.TraceFlags
.tracing
== TRACE_STDERR
) {
464 printThreadStatus(tso
);
468 /* nothing - no event for this one yet */
472 void traceEventStartup_(int nocaps
)
474 if (eventlog_enabled
) {
475 postEventStartup(nocaps
);
480 void traceBegin (const char *str
, ...)
485 ACQUIRE_LOCK(&trace_utx
);
494 RELEASE_LOCK(&trace_utx
);
500 // If DTRACE is enabled, but neither DEBUG nor TRACING, we need a C land
501 // wrapper for the user-msg probe (as we can't expand that in PrimOps.cmm)
503 #if !defined(DEBUG) && !defined(TRACING) && defined(DTRACE)
505 void dtraceUserMsgWrapper(Capability
*cap
, char *msg
)
507 dtraceUserMsg(cap
->no
, msg
);
510 #endif /* !defined(DEBUG) && !defined(TRACING) && defined(DTRACE) */