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