Another improvement to SetLevels
[ghc.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 "GetEnv.h"
19 #include "Stats.h"
20 #include "eventlog/EventLog.h"
21 #include "rts/EventLogWriter.h"
22 #include "Threads.h"
23 #include "Printer.h"
24 #include "RtsFlags.h"
25
26 #ifdef HAVE_UNISTD_H
27 #include <unistd.h>
28 #endif
29
30 // events
31 int TRACE_sched;
32 int TRACE_gc;
33 int TRACE_spark_sampled;
34 int TRACE_spark_full;
35 int TRACE_user;
36 int TRACE_cap;
37
38 #ifdef THREADED_RTS
39 static Mutex trace_utx;
40 #endif
41
42 static bool eventlog_enabled;
43
44 /* ---------------------------------------------------------------------------
45 Starting up / shuttting down the tracing facilities
46 --------------------------------------------------------------------------- */
47
48 static const EventLogWriter *getEventLogWriter(void)
49 {
50 return rtsConfig.eventlog_writer;
51 }
52
53 void initTracing (void)
54 {
55 const EventLogWriter *eventlog_writer = getEventLogWriter();
56
57 #ifdef THREADED_RTS
58 initMutex(&trace_utx);
59 #endif
60
61 // -Ds turns on scheduler tracing too
62 TRACE_sched =
63 RtsFlags.TraceFlags.scheduler ||
64 RtsFlags.DebugFlags.scheduler;
65
66 // -Dg turns on gc tracing too
67 TRACE_gc =
68 RtsFlags.TraceFlags.gc ||
69 RtsFlags.DebugFlags.gc ||
70 RtsFlags.DebugFlags.scheduler;
71 if (TRACE_gc && RtsFlags.GcFlags.giveStats == NO_GC_STATS) {
72 RtsFlags.GcFlags.giveStats = COLLECT_GC_STATS;
73 }
74
75 TRACE_spark_sampled =
76 RtsFlags.TraceFlags.sparks_sampled;
77
78 // -Dr turns on full spark tracing
79 TRACE_spark_full =
80 RtsFlags.TraceFlags.sparks_full ||
81 RtsFlags.DebugFlags.sparks;
82
83 TRACE_user =
84 RtsFlags.TraceFlags.user;
85
86 // We trace cap events if we're tracing anything else
87 TRACE_cap =
88 TRACE_sched ||
89 TRACE_gc ||
90 TRACE_spark_sampled ||
91 TRACE_spark_full ||
92 TRACE_user;
93
94 eventlog_enabled = RtsFlags.TraceFlags.tracing == TRACE_EVENTLOG &&
95 eventlog_writer != NULL;
96
97 /* Note: we can have any of the TRACE_* flags turned on even when
98 eventlog_enabled is off. In the DEBUG way we may be tracing to stderr.
99 */
100
101 if (eventlog_enabled) {
102 initEventLogging(eventlog_writer);
103 }
104 }
105
106 void endTracing (void)
107 {
108 if (eventlog_enabled) {
109 endEventLogging();
110 }
111 }
112
113 void freeTracing (void)
114 {
115 if (eventlog_enabled) {
116 freeEventLogging();
117 }
118 }
119
120 void resetTracing (void)
121 {
122 const EventLogWriter *eventlog_writer;
123 eventlog_writer = getEventLogWriter();
124
125 if (eventlog_enabled) {
126 abortEventLogging(); // abort eventlog inherited from parent
127 if (eventlog_writer != NULL) {
128 initEventLogging(eventlog_writer); // child starts its own eventlog
129 }
130 }
131 }
132
133 void tracingAddCapapilities (uint32_t from, uint32_t to)
134 {
135 if (eventlog_enabled) {
136 moreCapEventBufs(from,to);
137 }
138 }
139
140 /* ---------------------------------------------------------------------------
141 Emitting trace messages/events
142 --------------------------------------------------------------------------- */
143
144 #ifdef DEBUG
145 static void tracePreface (void)
146 {
147 #ifdef THREADED_RTS
148 debugBelch("%12lx: ", (unsigned long)osThreadId());
149 #endif
150 if (RtsFlags.TraceFlags.timestamp) {
151 debugBelch("%9" FMT_Word64 ": ", stat_getElapsedTime());
152 }
153 }
154 #endif
155
156 #ifdef DEBUG
157 static char *thread_stop_reasons[] = {
158 [HeapOverflow] = "heap overflow",
159 [StackOverflow] = "stack overflow",
160 [ThreadYielding] = "yielding",
161 [ThreadBlocked] = "blocked",
162 [ThreadFinished] = "finished",
163 [THREAD_SUSPENDED_FOREIGN_CALL] = "suspended while making a foreign call",
164 [6 + BlockedOnMVar] = "blocked on an MVar",
165 [6 + BlockedOnMVarRead] = "blocked on an atomic MVar read",
166 [6 + BlockedOnBlackHole] = "blocked on a black hole",
167 [6 + BlockedOnRead] = "blocked on a read operation",
168 [6 + BlockedOnWrite] = "blocked on a write operation",
169 [6 + BlockedOnDelay] = "blocked on a delay operation",
170 [6 + BlockedOnSTM] = "blocked on STM",
171 [6 + BlockedOnDoProc] = "blocked on asyncDoProc",
172 [6 + BlockedOnCCall] = "blocked on a foreign call",
173 [6 + BlockedOnCCall_Interruptible] = "blocked on a foreign call (interruptible)",
174 [6 + BlockedOnMsgThrowTo] = "blocked on throwTo",
175 [6 + ThreadMigrating] = "migrating"
176 };
177 #endif
178
179 #ifdef DEBUG
180 static void traceSchedEvent_stderr (Capability *cap, EventTypeNum tag,
181 StgTSO *tso,
182 StgWord info1 STG_UNUSED,
183 StgWord info2 STG_UNUSED)
184 {
185 ACQUIRE_LOCK(&trace_utx);
186
187 tracePreface();
188 switch (tag) {
189 case EVENT_CREATE_THREAD: // (cap, thread)
190 debugBelch("cap %d: created thread %" FMT_Word "\n",
191 cap->no, (W_)tso->id);
192 break;
193 case EVENT_RUN_THREAD: // (cap, thread)
194 debugBelch("cap %d: running thread %" FMT_Word " (%s)\n",
195 cap->no, (W_)tso->id, what_next_strs[tso->what_next]);
196 break;
197 case EVENT_THREAD_RUNNABLE: // (cap, thread)
198 debugBelch("cap %d: thread %" FMT_Word " appended to run queue\n",
199 cap->no, (W_)tso->id);
200 break;
201 case EVENT_MIGRATE_THREAD: // (cap, thread, new_cap)
202 debugBelch("cap %d: thread %" FMT_Word " migrating to cap %d\n",
203 cap->no, (W_)tso->id, (int)info1);
204 break;
205 case EVENT_THREAD_WAKEUP: // (cap, thread, info1_cap)
206 debugBelch("cap %d: waking up thread %" FMT_Word " on cap %d\n",
207 cap->no, (W_)tso->id, (int)info1);
208 break;
209
210 case EVENT_STOP_THREAD: // (cap, thread, status)
211 if (info1 == 6 + BlockedOnBlackHole) {
212 debugBelch("cap %d: thread %" FMT_Word " stopped (blocked on black hole owned by thread %lu)\n",
213 cap->no, (W_)tso->id, (long)info2);
214 } else {
215 debugBelch("cap %d: thread %" FMT_Word " stopped (%s)\n",
216 cap->no, (W_)tso->id, thread_stop_reasons[info1]);
217 }
218 break;
219 default:
220 debugBelch("cap %d: thread %" FMT_Word ": event %d\n\n",
221 cap->no, (W_)tso->id, tag);
222 break;
223 }
224
225 RELEASE_LOCK(&trace_utx);
226 }
227 #endif
228
229 void traceSchedEvent_ (Capability *cap, EventTypeNum tag,
230 StgTSO *tso, StgWord info1, StgWord info2)
231 {
232 #ifdef DEBUG
233 if (RtsFlags.TraceFlags.tracing == TRACE_STDERR) {
234 traceSchedEvent_stderr(cap, tag, tso, info1, info2);
235 } else
236 #endif
237 {
238 postSchedEvent(cap,tag,tso ? tso->id : 0, info1, info2);
239 }
240 }
241
242 #ifdef DEBUG
243 static void traceGcEvent_stderr (Capability *cap, EventTypeNum tag)
244 {
245 ACQUIRE_LOCK(&trace_utx);
246
247 tracePreface();
248 switch (tag) {
249 case EVENT_REQUEST_SEQ_GC: // (cap)
250 debugBelch("cap %d: requesting sequential GC\n", cap->no);
251 break;
252 case EVENT_REQUEST_PAR_GC: // (cap)
253 debugBelch("cap %d: requesting parallel GC\n", cap->no);
254 break;
255 case EVENT_GC_START: // (cap)
256 debugBelch("cap %d: starting GC\n", cap->no);
257 break;
258 case EVENT_GC_END: // (cap)
259 debugBelch("cap %d: finished GC\n", cap->no);
260 break;
261 case EVENT_GC_IDLE: // (cap)
262 debugBelch("cap %d: GC idle\n", cap->no);
263 break;
264 case EVENT_GC_WORK: // (cap)
265 debugBelch("cap %d: GC working\n", cap->no);
266 break;
267 case EVENT_GC_DONE: // (cap)
268 debugBelch("cap %d: GC done\n", cap->no);
269 break;
270 case EVENT_GC_GLOBAL_SYNC: // (cap)
271 debugBelch("cap %d: all caps stopped for GC\n", cap->no);
272 break;
273 default:
274 barf("traceGcEvent: unknown event tag %d", tag);
275 break;
276 }
277
278 RELEASE_LOCK(&trace_utx);
279 }
280 #endif
281
282 void traceGcEvent_ (Capability *cap, EventTypeNum tag)
283 {
284 #ifdef DEBUG
285 if (RtsFlags.TraceFlags.tracing == TRACE_STDERR) {
286 traceGcEvent_stderr(cap, tag);
287 } else
288 #endif
289 {
290 /* currently all GC events are nullary events */
291 postEvent(cap, tag);
292 }
293 }
294
295 void traceGcEventAtT_ (Capability *cap, StgWord64 ts, EventTypeNum tag)
296 {
297 #ifdef DEBUG
298 if (RtsFlags.TraceFlags.tracing == TRACE_STDERR) {
299 traceGcEvent_stderr(cap, tag);
300 } else
301 #endif
302 {
303 /* assuming nullary events and explicitly inserting a timestamp */
304 postEventAtTimestamp(cap, ts, tag);
305 }
306 }
307
308 void traceHeapEvent_ (Capability *cap,
309 EventTypeNum tag,
310 CapsetID heap_capset,
311 W_ info1)
312 {
313 #ifdef DEBUG
314 if (RtsFlags.TraceFlags.tracing == TRACE_STDERR) {
315 /* no stderr equivalent for these ones */
316 } else
317 #endif
318 {
319 postHeapEvent(cap, tag, heap_capset, info1);
320 }
321 }
322
323 void traceEventHeapInfo_ (CapsetID heap_capset,
324 uint32_t gens,
325 W_ maxHeapSize,
326 W_ allocAreaSize,
327 W_ mblockSize,
328 W_ blockSize)
329 {
330 #ifdef DEBUG
331 if (RtsFlags.TraceFlags.tracing == TRACE_STDERR) {
332 /* no stderr equivalent for these ones */
333 } else
334 #endif
335 {
336 postEventHeapInfo(heap_capset, gens,
337 maxHeapSize, allocAreaSize,
338 mblockSize, blockSize);
339 }
340 }
341
342 void traceEventGcStats_ (Capability *cap,
343 CapsetID heap_capset,
344 uint32_t gen,
345 W_ copied,
346 W_ slop,
347 W_ fragmentation,
348 uint32_t par_n_threads,
349 W_ par_max_copied,
350 W_ par_tot_copied)
351 {
352 #ifdef DEBUG
353 if (RtsFlags.TraceFlags.tracing == TRACE_STDERR) {
354 /* no stderr equivalent for these ones */
355 } else
356 #endif
357 {
358 postEventGcStats(cap, heap_capset, gen,
359 copied, slop, fragmentation,
360 par_n_threads, par_max_copied, par_tot_copied);
361 }
362 }
363
364 void traceCapEvent_ (Capability *cap,
365 EventTypeNum tag)
366 {
367 #ifdef DEBUG
368 if (RtsFlags.TraceFlags.tracing == TRACE_STDERR) {
369 ACQUIRE_LOCK(&trace_utx);
370
371 tracePreface();
372 switch (tag) {
373 case EVENT_CAP_CREATE: // (cap)
374 debugBelch("cap %d: initialised\n", cap->no);
375 break;
376 case EVENT_CAP_DELETE: // (cap)
377 debugBelch("cap %d: shutting down\n", cap->no);
378 break;
379 case EVENT_CAP_ENABLE: // (cap)
380 debugBelch("cap %d: enabling capability\n", cap->no);
381 break;
382 case EVENT_CAP_DISABLE: // (cap)
383 debugBelch("cap %d: disabling capability\n", cap->no);
384 break;
385 }
386 RELEASE_LOCK(&trace_utx);
387 } else
388 #endif
389 {
390 if (eventlog_enabled) {
391 postCapEvent(tag, (EventCapNo)cap->no);
392 }
393 }
394 }
395
396 void traceCapsetEvent_ (EventTypeNum tag,
397 CapsetID capset,
398 StgWord info)
399 {
400 #ifdef DEBUG
401 if (RtsFlags.TraceFlags.tracing == TRACE_STDERR && TRACE_sched)
402 // When events go to stderr, it is annoying to see the capset
403 // events every time, so we only emit them with -Ds.
404 {
405 ACQUIRE_LOCK(&trace_utx);
406
407 tracePreface();
408 switch (tag) {
409 case EVENT_CAPSET_CREATE: // (capset, capset_type)
410 debugBelch("created capset %" FMT_Word32 " of type %d\n", capset,
411 (int)info);
412 break;
413 case EVENT_CAPSET_DELETE: // (capset)
414 debugBelch("deleted capset %" FMT_Word32 "\n", capset);
415 break;
416 case EVENT_CAPSET_ASSIGN_CAP: // (capset, capno)
417 debugBelch("assigned cap %" FMT_Word " to capset %" FMT_Word32 "\n",
418 info, capset);
419 break;
420 case EVENT_CAPSET_REMOVE_CAP: // (capset, capno)
421 debugBelch("removed cap %" FMT_Word " from capset %" FMT_Word32
422 "\n", info, capset);
423 break;
424 }
425 RELEASE_LOCK(&trace_utx);
426 } else
427 #endif
428 {
429 if (eventlog_enabled) {
430 postCapsetEvent(tag, capset, info);
431 }
432 }
433 }
434
435 void traceWallClockTime_(void) {
436 if (eventlog_enabled) {
437 postWallClockTime(CAPSET_CLOCKDOMAIN_DEFAULT);
438 }
439 }
440
441 void traceOSProcessInfo_(void) {
442 if (eventlog_enabled) {
443 postCapsetEvent(EVENT_OSPROCESS_PID,
444 CAPSET_OSPROCESS_DEFAULT,
445 getpid());
446
447 #if !defined (mingw32_HOST_OS)
448 /* Windows has no strong concept of process hierarchy, so no getppid().
449 * In any case, this trace event is mainly useful for tracing programs
450 * that use 'forkProcess' which Windows doesn't support anyway.
451 */
452 postCapsetEvent(EVENT_OSPROCESS_PPID,
453 CAPSET_OSPROCESS_DEFAULT,
454 getppid());
455 #endif
456 {
457 char buf[256];
458 snprintf(buf, sizeof(buf), "GHC-%s %s", ProjectVersion, RtsWay);
459 postCapsetStrEvent(EVENT_RTS_IDENTIFIER,
460 CAPSET_OSPROCESS_DEFAULT,
461 buf);
462 }
463 {
464 int argc = 0; char **argv;
465 getFullProgArgv(&argc, &argv);
466 if (argc != 0) {
467 postCapsetVecEvent(EVENT_PROGRAM_ARGS,
468 CAPSET_OSPROCESS_DEFAULT,
469 argc, argv);
470 }
471 }
472 {
473 int envc = 0; char **envv;
474 getProgEnvv(&envc, &envv);
475 if (envc != 0) {
476 postCapsetVecEvent(EVENT_PROGRAM_ENV,
477 CAPSET_OSPROCESS_DEFAULT,
478 envc, envv);
479 }
480 freeProgEnvv(envc, envv);
481 }
482 }
483 }
484
485 #ifdef DEBUG
486 static void traceSparkEvent_stderr (Capability *cap, EventTypeNum tag,
487 StgWord info1)
488 {
489 ACQUIRE_LOCK(&trace_utx);
490
491 tracePreface();
492 switch (tag) {
493
494 case EVENT_CREATE_SPARK_THREAD: // (cap, spark_thread)
495 debugBelch("cap %d: creating spark thread %lu\n",
496 cap->no, (long)info1);
497 break;
498 case EVENT_SPARK_CREATE: // (cap)
499 debugBelch("cap %d: added spark to pool\n",
500 cap->no);
501 break;
502 case EVENT_SPARK_DUD: // (cap)
503 debugBelch("cap %d: discarded dud spark\n",
504 cap->no);
505 break;
506 case EVENT_SPARK_OVERFLOW: // (cap)
507 debugBelch("cap %d: discarded overflowed spark\n",
508 cap->no);
509 break;
510 case EVENT_SPARK_RUN: // (cap)
511 debugBelch("cap %d: running a spark\n",
512 cap->no);
513 break;
514 case EVENT_SPARK_STEAL: // (cap, victim_cap)
515 debugBelch("cap %d: stealing a spark from cap %d\n",
516 cap->no, (int)info1);
517 break;
518 case EVENT_SPARK_FIZZLE: // (cap)
519 debugBelch("cap %d: fizzled spark removed from pool\n",
520 cap->no);
521 break;
522 case EVENT_SPARK_GC: // (cap)
523 debugBelch("cap %d: GCd spark removed from pool\n",
524 cap->no);
525 break;
526 default:
527 barf("traceSparkEvent: unknown event tag %d", tag);
528 break;
529 }
530
531 RELEASE_LOCK(&trace_utx);
532 }
533 #endif
534
535 void traceSparkEvent_ (Capability *cap, EventTypeNum tag, StgWord info1)
536 {
537 #ifdef DEBUG
538 if (RtsFlags.TraceFlags.tracing == TRACE_STDERR) {
539 traceSparkEvent_stderr(cap, tag, info1);
540 } else
541 #endif
542 {
543 postSparkEvent(cap,tag,info1);
544 }
545 }
546
547 void traceSparkCounters_ (Capability *cap,
548 SparkCounters counters,
549 StgWord remaining)
550 {
551 #ifdef DEBUG
552 if (RtsFlags.TraceFlags.tracing == TRACE_STDERR) {
553 /* we currently don't do debug tracing of spark stats but we must
554 test for TRACE_STDERR because of the !eventlog_enabled case. */
555 } else
556 #endif
557 {
558 postSparkCountersEvent(cap, counters, remaining);
559 }
560 }
561
562 void traceTaskCreate_ (Task *task,
563 Capability *cap)
564 {
565 #ifdef DEBUG
566 if (RtsFlags.TraceFlags.tracing == TRACE_STDERR) {
567 /* We currently don't do debug tracing of tasks but we must
568 test for TRACE_STDERR because of the !eventlog_enabled case. */
569 } else
570 #endif
571 {
572 EventTaskId taskid = serialisableTaskId(task);
573 EventKernelThreadId tid = kernelThreadId();
574 postTaskCreateEvent(taskid, cap->no, tid);
575 }
576 }
577
578 void traceTaskMigrate_ (Task *task,
579 Capability *cap,
580 Capability *new_cap)
581 {
582 #ifdef DEBUG
583 if (RtsFlags.TraceFlags.tracing == TRACE_STDERR) {
584 /* We currently don't do debug tracing of tasks but we must
585 test for TRACE_STDERR because of the !eventlog_enabled case. */
586 } else
587 #endif
588 {
589 EventTaskId taskid = serialisableTaskId(task);
590 postTaskMigrateEvent(taskid, cap->no, new_cap->no);
591 }
592 }
593
594 void traceTaskDelete_ (Task *task)
595 {
596 #ifdef DEBUG
597 if (RtsFlags.TraceFlags.tracing == TRACE_STDERR) {
598 /* We currently don't do debug tracing of tasks but we must
599 test for TRACE_STDERR because of the !eventlog_enabled case. */
600 } else
601 #endif
602 {
603 EventTaskId taskid = serialisableTaskId(task);
604 postTaskDeleteEvent(taskid);
605 }
606 }
607
608 void traceHeapProfBegin(StgWord8 profile_id)
609 {
610 if (eventlog_enabled) {
611 postHeapProfBegin(profile_id);
612 }
613 }
614
615 void traceHeapProfSampleBegin(StgInt era)
616 {
617 if (eventlog_enabled) {
618 postHeapProfSampleBegin(era);
619 }
620 }
621
622 void traceHeapProfSampleString(StgWord8 profile_id,
623 const char *label, StgWord residency)
624 {
625 if (eventlog_enabled) {
626 postHeapProfSampleString(profile_id, label, residency);
627 }
628 }
629
630 #ifdef PROFILING
631 void traceHeapProfCostCentre(StgWord32 ccID,
632 const char *label,
633 const char *module,
634 const char *srcloc,
635 StgBool is_caf)
636 {
637 if (eventlog_enabled) {
638 postHeapProfCostCentre(ccID, label, module, srcloc, is_caf);
639 }
640 }
641
642 void traceHeapProfSampleCostCentre(StgWord8 profile_id,
643 CostCentreStack *stack, StgWord residency)
644 {
645 if (eventlog_enabled) {
646 postHeapProfSampleCostCentre(profile_id, stack, residency);
647 }
648 }
649 #endif
650
651 #ifdef DEBUG
652 static void vtraceCap_stderr(Capability *cap, char *msg, va_list ap)
653 {
654 ACQUIRE_LOCK(&trace_utx);
655
656 tracePreface();
657 debugBelch("cap %d: ", cap->no);
658 vdebugBelch(msg,ap);
659 debugBelch("\n");
660
661 RELEASE_LOCK(&trace_utx);
662 }
663
664 static void traceCap_stderr(Capability *cap, char *msg, ...)
665 {
666 va_list ap;
667 va_start(ap,msg);
668 vtraceCap_stderr(cap, msg, ap);
669 va_end(ap);
670 }
671 #endif
672
673 void traceCap_(Capability *cap, char *msg, ...)
674 {
675 va_list ap;
676 va_start(ap,msg);
677
678 #ifdef DEBUG
679 if (RtsFlags.TraceFlags.tracing == TRACE_STDERR) {
680 vtraceCap_stderr(cap, msg, ap);
681 } else
682 #endif
683 {
684 postCapMsg(cap, msg, ap);
685 }
686
687 va_end(ap);
688 }
689
690 #ifdef DEBUG
691 static void vtrace_stderr(char *msg, va_list ap)
692 {
693 ACQUIRE_LOCK(&trace_utx);
694
695 tracePreface();
696 vdebugBelch(msg,ap);
697 debugBelch("\n");
698
699 RELEASE_LOCK(&trace_utx);
700 }
701 #endif
702
703 void trace_(char *msg, ...)
704 {
705 va_list ap;
706 va_start(ap,msg);
707
708 #ifdef DEBUG
709 if (RtsFlags.TraceFlags.tracing == TRACE_STDERR) {
710 vtrace_stderr(msg, ap);
711 } else
712 #endif
713 {
714 postMsg(msg, ap);
715 }
716
717 va_end(ap);
718 }
719
720 void traceUserMsg(Capability *cap, char *msg)
721 {
722 /* Note: normally we don't check the TRACE_* flags here as they're checked
723 by the wrappers in Trace.h. But traceUserMsg is special since it has no
724 wrapper (it's called from cmm code), so we check TRACE_user here
725 */
726 #ifdef DEBUG
727 if (RtsFlags.TraceFlags.tracing == TRACE_STDERR && TRACE_user) {
728 // Use "%s" as format string to ignore format specifiers in msg (#3874).
729 traceCap_stderr(cap, "%s", msg);
730 } else
731 #endif
732 {
733 if (eventlog_enabled && TRACE_user) {
734 postUserEvent(cap, EVENT_USER_MSG, msg);
735 }
736 }
737 dtraceUserMsg(cap->no, msg);
738 }
739
740 void traceUserMarker(Capability *cap, char *markername)
741 {
742 /* Note: traceUserMarker is special since it has no wrapper (it's called
743 from cmm code), so we check eventlog_enabled and TRACE_user here.
744 */
745 #ifdef DEBUG
746 if (RtsFlags.TraceFlags.tracing == TRACE_STDERR && TRACE_user) {
747 traceCap_stderr(cap, "User marker: %s", markername);
748 } else
749 #endif
750 {
751 if (eventlog_enabled && TRACE_user) {
752 postUserEvent(cap, EVENT_USER_MARKER, markername);
753 }
754 }
755 dtraceUserMarker(cap->no, markername);
756 }
757
758
759 void traceThreadLabel_(Capability *cap,
760 StgTSO *tso,
761 char *label)
762 {
763 #ifdef DEBUG
764 if (RtsFlags.TraceFlags.tracing == TRACE_STDERR) {
765 ACQUIRE_LOCK(&trace_utx);
766 tracePreface();
767 debugBelch("cap %d: thread %" FMT_Word " has label %s\n",
768 cap->no, (W_)tso->id, label);
769 RELEASE_LOCK(&trace_utx);
770 } else
771 #endif
772 {
773 postThreadLabel(cap, tso->id, label);
774 }
775 }
776
777 void traceThreadStatus_ (StgTSO *tso USED_IF_DEBUG)
778 {
779 #ifdef DEBUG
780 if (RtsFlags.TraceFlags.tracing == TRACE_STDERR) {
781 printThreadStatus(tso);
782 } else
783 #endif
784 {
785 /* nothing - no event for this one yet */
786 }
787 }
788
789 #ifdef DEBUG
790 void traceBegin (const char *str, ...)
791 {
792 va_list ap;
793 va_start(ap,str);
794
795 ACQUIRE_LOCK(&trace_utx);
796
797 tracePreface();
798 vdebugBelch(str,ap);
799 va_end(ap);
800 }
801
802 void traceEnd (void)
803 {
804 debugBelch("\n");
805 RELEASE_LOCK(&trace_utx);
806 }
807 #endif /* DEBUG */
808
809 #endif /* TRACING */
810
811 // If DTRACE is enabled, but neither DEBUG nor TRACING, we need a C land
812 // wrapper for the user-msg probe (as we can't expand that in PrimOps.cmm)
813 //
814 #if !defined(DEBUG) && !defined(TRACING) && defined(DTRACE)
815
816 void dtraceUserMsgWrapper(Capability *cap, char *msg)
817 {
818 dtraceUserMsg(cap->no, msg);
819 }
820
821 void dtraceUserMarkerWrapper(Capability *cap, char *msg)
822 {
823 dtraceUserMarker(cap->no, msg);
824 }
825
826 #endif /* !defined(DEBUG) && !defined(TRACING) && defined(DTRACE) */