summaryrefslogtreecommitdiff
path: root/rts/Trace.h
blob: 3cec74cfa9a4ac370fe348bdd57f272f888764a8 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
/* -----------------------------------------------------------------------------
 *
 * (c) The GHC Team, 2008-2009
 *
 * Support for fast binary event logging and user-space dtrace probes.
 *
 * ---------------------------------------------------------------------------*/

#pragma once

#include "eventlog/EventLog.h"
#include "sm/NonMovingCensus.h"
#include "Capability.h"

#if defined(DTRACE)
#include "RtsProbes.h"
#endif /* defined(DTRACE) */

#include "BeginPrivate.h"

// -----------------------------------------------------------------------------
// EventLog API
// -----------------------------------------------------------------------------

#if defined(TRACING)

void initTracing (void);
void endTracing  (void);
void freeTracing (void);
void resetTracing (void);
void tracingAddCapabilities (uint32_t from, uint32_t to);

#endif /* TRACING */

typedef StgWord32 CapsetID;
#if !defined(__cplusplus)
typedef StgWord16 CapsetType;
#endif
enum CapsetType { CapsetTypeCustom = CAPSET_TYPE_CUSTOM,
                  CapsetTypeOsProcess = CAPSET_TYPE_OSPROCESS,
                  CapsetTypeClockdomain = CAPSET_TYPE_CLOCKDOMAIN };
#define CAPSET_OSPROCESS_DEFAULT   ((CapsetID)0)
#define CAPSET_HEAP_DEFAULT        ((CapsetID)0)   /* reusing the same capset */
#define CAPSET_CLOCKDOMAIN_DEFAULT ((CapsetID)1)

// -----------------------------------------------------------------------------
// Message classes
// -----------------------------------------------------------------------------

// shorthand for RtsFlags.DebugFlags.<blah>, useful with debugTrace()
#define DEBUG_sched       RtsFlags.DebugFlags.scheduler
#define DEBUG_interp      RtsFlags.DebugFlags.interp
#define DEBUG_weak        RtsFlags.DebugFlags.weak
#define DEBUG_gccafs      RtsFlags.DebugFlags.gccafs
#define DEBUG_gc          RtsFlags.DebugFlags.gc
#define DEBUG_nonmoving_gc RtsFlags.DebugFlags.nonmoving_gc
#define DEBUG_block_alloc RtsFlags.DebugFlags.alloc
#define DEBUG_sanity      RtsFlags.DebugFlags.sanity
#define DEBUG_zero_on_gc  RtsFlags.DebugFlags.zero_on_gc
#define DEBUG_stable      RtsFlags.DebugFlags.stable
#define DEBUG_stm         RtsFlags.DebugFlags.stm
#define DEBUG_prof        RtsFlags.DebugFlags.prof
#define DEBUG_gran        RtsFlags.DebugFlags.gran
#define DEBUG_par         RtsFlags.DebugFlags.par
#define DEBUG_linker      RtsFlags.DebugFlags.linker
#define DEBUG_squeeze     RtsFlags.DebugFlags.squeeze
#define DEBUG_hpc         RtsFlags.DebugFlags.hpc
#define DEBUG_sparks      RtsFlags.DebugFlags.sparks
#define DEBUG_compact     RtsFlags.DebugFlags.compact
#define DEBUG_continuation RtsFlags.DebugFlags.continuation

// Event-enabled flags
// These semantically booleans but we use a dense packing to minimize their
// cache impact.
extern uint8_t TRACE_sched;
extern uint8_t TRACE_gc;
extern uint8_t TRACE_nonmoving_gc;
extern uint8_t TRACE_spark_sampled;
extern uint8_t TRACE_spark_full;
extern uint8_t TRACE_cap;
/* extern uint8_t TRACE_user; */  // only used in Trace.c

// -----------------------------------------------------------------------------
// Posting events
//
// We use macros rather than inline functions deliberately.  We want
// the not-taken case to be as efficient as possible, a simple
// test-and-jump, and with inline functions gcc seemed to move some of
// the instructions from the branch up before the test.
//
// -----------------------------------------------------------------------------

#if defined(DEBUG)
void traceBegin (const char *str, ...);
void traceEnd (void);
#endif

#if defined(TRACING)

/*
 * Record a scheduler event
 */
#define traceSchedEvent(cap, tag, tso, other)   \
    if (RTS_UNLIKELY(TRACE_sched)) {            \
        traceSchedEvent_(cap, tag, tso, other, 0); \
    }

#define traceSchedEvent2(cap, tag, tso, info1, info2) \
    if (RTS_UNLIKELY(TRACE_sched)) {            \
        traceSchedEvent_(cap, tag, tso, info1, info2); \
    }

void traceSchedEvent_ (Capability *cap, EventTypeNum tag,
                       StgTSO *tso, StgWord info1, StgWord info2);

#define traceInitEvent(event) postInitEvent(event)

/*
 * Record a GC event
 */
#define traceGcEvent(cap, tag)    \
    if (RTS_UNLIKELY(TRACE_gc)) { \
        traceGcEvent_(cap, tag);  \
    }

void traceGcEvent_ (Capability *cap, EventTypeNum tag);

/*
 * Record a GC event at the explicitly given timestamp
 */
#define traceGcEventAtT(cap, ts, tag)   \
    if (RTS_UNLIKELY(TRACE_gc)) {       \
        traceGcEventAtT_(cap, ts, tag); \
    }

void traceGcEventAtT_ (Capability *cap, StgWord64 ts, EventTypeNum tag);

/*
 * Record a heap event
 */
#define traceHeapEvent(cap, tag, heap_capset, info1) \
    if (RTS_UNLIKELY(TRACE_gc)) { \
        traceHeapEvent_(cap, tag, heap_capset, info1);  \
    }
void traceHeapEvent_ (Capability   *cap,
                      EventTypeNum  tag,
                      CapsetID      heap_capset,
                      W_          info1);

void traceEventHeapInfo_ (CapsetID    heap_capset,
                          uint32_t  gens,
                          W_        maxHeapSize,
                          W_        allocAreaSize,
                          W_        mblockSize,
                          W_        blockSize);

void traceEventGcStats_  (Capability *cap,
                          CapsetID    heap_capset,
                          uint32_t  gen,
                          W_        copied,
                          W_        slop,
                          W_        fragmentation,
                          uint32_t  par_n_threads,
                          W_        par_max_copied,
                          W_        par_tot_copied,
                          W_        par_balanced_copied);

void traceEventMemReturn_  (Capability *cap,
                          uint32_t    current_mblocks,
                          uint32_t    needed_mblocks,
                          uint32_t    returned_mblocks );

/*
 * Record a spark event
 */
#define traceSparkEvent(cap, tag)         \
    if (RTS_UNLIKELY(TRACE_spark_full)) { \
        traceSparkEvent_(cap, tag, 0);    \
    }

#define traceSparkEvent2(cap, tag, other)  \
    if (RTS_UNLIKELY(TRACE_spark_full)) {  \
        traceSparkEvent_(cap, tag, other); \
    }

void traceSparkEvent_ (Capability *cap, EventTypeNum tag, StgWord info1);

// variadic macros are C99, and supported by gcc.  However, the
// ##__VA_ARGS syntax is a gcc extension, which allows the variable
// argument list to be empty (see gcc docs for details).

/*
 * Emit a trace message on a particular Capability
 */
#define traceCap(class, cap, msg, ...)          \
    if (RTS_UNLIKELY(class)) {                  \
        traceCap_(cap, msg, ##__VA_ARGS__);     \
    }

void traceCap_(Capability *cap, char *msg, ...);

/*
 * Emit a trace message
 */
#define trace(class, msg, ...)                  \
    if (RTS_UNLIKELY(class)) {                  \
        trace_(msg, ##__VA_ARGS__);             \
    }

void trace_(char *msg, ...);

/*
 * A message or event emitted by the program
 * Used by Debug.Trace.{traceEvent, traceEventIO}
 */
void traceUserMsg(Capability *cap, char *msg);

/*
 * A marker event emitted by the program
 * Used by Debug.Trace.{traceMarker, traceMarkerIO}
 */
void traceUserMarker(Capability *cap, char *msg);

/*
 * A binary message or event emitted by the program
 */
void traceUserBinaryMsg(Capability *cap, uint8_t *msg, size_t size);

/*
 * An event to record a Haskell thread's label/name
 * Used by GHC.Conc.labelThread
 */
void traceThreadLabel_(Capability *cap,
                       StgTSO     *tso,
                       char       *label,
                       size_t      len);

/*
 * Emit a debug message (only when DEBUG is defined)
 */
#if defined(DEBUG)
#define debugTrace(class, msg, ...)             \
    if (RTS_UNLIKELY(class)) {                  \
        trace_(msg, ##__VA_ARGS__);             \
    }
#else
#define debugTrace(class, str, ...) /* nothing */
#endif

#if defined(DEBUG)
#define debugTraceCap(class, cap, msg, ...)      \
    if (RTS_UNLIKELY(class)) {                  \
        traceCap_(cap, msg, ##__VA_ARGS__);     \
    }
#else
#define debugTraceCap(class, cap, str, ...) /* nothing */
#endif

/*
 * Emit a message/event describing the state of a thread
 */
#define traceThreadStatus(class, tso)           \
    if (RTS_UNLIKELY(class)) {                  \
        traceThreadStatus_(tso);                \
    }

void traceThreadStatus_ (StgTSO *tso);

/*
 * Events for describing capabilities and capability sets in the eventlog
 */
#define traceCapEvent(cap, tag)                 \
    if (RTS_UNLIKELY(TRACE_cap)) {              \
        traceCapEvent_(cap, tag);               \
    }

void traceCapEvent_ (Capability   *cap,
                    EventTypeNum  tag);

#define traceCapsetEvent(cap, capset, info)     \
    if (RTS_UNLIKELY(TRACE_cap)) {              \
        traceCapsetEvent_(cap, capset, info);   \
    }

void traceCapsetEvent_ (EventTypeNum tag,
                        CapsetID     capset,
                        StgWord      info);

void traceWallClockTime_(void);

void traceOSProcessInfo_ (void);

void traceSparkCounters_ (Capability *cap,
                          SparkCounters counters,
                          StgWord remaining);

void traceTaskCreate_ (Task       *task,
                       Capability *cap);

void traceTaskMigrate_ (Task       *task,
                        Capability *cap,
                        Capability *new_cap);

void traceTaskDelete_ (Task       *task);

void traceHeapProfBegin(StgWord8 profile_id);
void traceHeapProfSampleBegin(StgInt era);
void traceHeapBioProfSampleBegin(StgInt era, StgWord64 time);
void traceHeapProfSampleEnd(StgInt era);
void traceHeapProfSampleString(StgWord8 profile_id,
                               const char *label, StgWord residency);
#if defined(PROFILING)
void traceHeapProfCostCentre(StgWord32 ccID,
                             const char *label,
                             const char *module,
                             const char *srcloc,
                             StgBool is_caf);
void traceHeapProfSampleCostCentre(StgWord8 profile_id,
                                   CostCentreStack *stack, StgWord residency);

void traceProfSampleCostCentre(Capability *cap,
                               CostCentreStack *stack, StgWord ticks);
void traceProfBegin(void);
#endif /* PROFILING */

void traceConcMarkBegin(void);
void traceConcMarkEnd(StgWord32 marked_obj_count);
void traceConcSyncBegin(void);
void traceConcSyncEnd(void);
void traceConcSweepBegin(void);
void traceConcSweepEnd(void);
void traceConcUpdRemSetFlush(Capability *cap);
void traceNonmovingHeapCensus(uint32_t log_blk_size,
                              const struct NonmovingAllocCensus *census);

void traceIPE(const InfoProvEnt *ipe);
void flushTrace(void);

#else /* !TRACING */

#define traceSchedEvent(cap, tag, tso, other) /* nothing */
#define traceInitEvent(event) /* nothing */
#define traceSchedEvent2(cap, tag, tso, other, info) /* nothing */
#define traceGcEvent(cap, tag) /* nothing */
#define traceGcEventAtT(cap, ts, tag) /* nothing */
#define traceEventGcStats_(cap, heap_capset, gen, \
                           copied, slop, fragmentation, \
                           par_n_threads, par_max_copied, \
                           par_tot_copied, par_balanced_copied) /* nothing */
#define traceEventMemReturn_(cap, current, needed, returned) /* nothing */
#define traceHeapEvent(cap, tag, heap_capset, info1) /* nothing */
#define traceEventHeapInfo_(heap_capset, gens, \
                            maxHeapSize, allocAreaSize, \
                            mblockSize, blockSize) /* nothing */
#define traceSparkEvent(cap, tag) /* nothing */
#define traceSparkEvent2(cap, tag, other) /* nothing */
#define traceCap(class, cap, msg, ...) /* nothing */
#define trace(class, msg, ...) /* nothing */
#define debugTrace(class, str, ...) /* nothing */
#define debugTraceCap(class, cap, str, ...) /* nothing */
#define traceThreadStatus(class, tso) /* nothing */
#define traceThreadLabel_(cap, tso, label, len) /* nothing */
#define traceCapEvent(cap, tag) /* nothing */
#define traceCapsetEvent(tag, capset, info) /* nothing */
#define traceWallClockTime_() /* nothing */
#define traceOSProcessInfo_()  /* nothing */
#define traceSparkCounters_(cap, counters, remaining) /* nothing */
#define traceTaskCreate_(taskID, cap) /* nothing */
#define traceTaskMigrate_(taskID, cap, new_cap) /* nothing */
#define traceTaskDelete_(taskID) /* nothing */
#define traceHeapProfBegin(profile_id) /* nothing */
#define traceHeapProfCostCentre(ccID, label, module, srcloc, is_caf) /* nothing */
#define traceIPE(ipe) /* nothing */
#define traceHeapProfSampleBegin(era) /* nothing */
#define traceHeapBioProfSampleBegin(era, time) /* nothing */
#define traceHeapProfSampleEnd(era) /* nothing */
#define traceHeapProfSampleCostCentre(profile_id, stack, residency) /* nothing */
#define traceHeapProfSampleString(profile_id, label, residency) /* nothing */

#define traceConcMarkBegin() /* nothing */
#define traceConcMarkEnd(marked_obj_count) /* nothing */
#define traceConcSyncBegin() /* nothing */
#define traceConcSyncEnd() /* nothing */
#define traceConcSweepBegin() /* nothing */
#define traceConcSweepEnd() /* nothing */
#define traceConcUpdRemSetFlush(cap) /* nothing */
#define traceNonmovingHeapCensus(blk_size, census) /* nothing */

#define flushTrace() /* nothing */

#endif /* TRACING */

// If DTRACE is enabled, but neither DEBUG nor TRACING, we need a C land
// wrapper for the user-msg probe (as we can't expand that in GHC.Builtin.PrimOpss.cmm)
//
#if !defined(DEBUG) && !defined(TRACING) && defined(DTRACE)

void dtraceUserMsgWrapper(Capability *cap, char *msg);
void dtraceUserMarkerWrapper(Capability *cap, char *msg);

#endif /* !defined(DEBUG) && !defined(TRACING) && defined(DTRACE) */

// -----------------------------------------------------------------------------
// Aliases for static dtrace probes if dtrace is available
// -----------------------------------------------------------------------------

#if defined(DTRACE)

#define dtraceCreateThread(cap, tid)                    \
    HASKELLEVENT_CREATE_THREAD(cap, tid)
#define dtraceRunThread(cap, tid)                       \
    HASKELLEVENT_RUN_THREAD(cap, tid)
#define dtraceStopThread(cap, tid, status, info)        \
    HASKELLEVENT_STOP_THREAD(cap, tid, status, info)
#define dtraceThreadRunnable(cap, tid)                  \
    HASKELLEVENT_THREAD_RUNNABLE(cap, tid)
#define dtraceMigrateThread(cap, tid, new_cap)          \
    HASKELLEVENT_MIGRATE_THREAD(cap, tid, new_cap)
#define dtraceThreadWakeup(cap, tid, other_cap)         \
    HASKELLEVENT_THREAD_WAKEUP(cap, tid, other_cap)
#define dtraceGcStart(cap)                              \
    HASKELLEVENT_GC_START(cap)
#define dtraceGcEnd(cap)                                \
    HASKELLEVENT_GC_END(cap)
#define dtraceRequestSeqGc(cap)                         \
    HASKELLEVENT_REQUEST_SEQ_GC(cap)
#define dtraceRequestParGc(cap)                         \
    HASKELLEVENT_REQUEST_PAR_GC(cap)
#define dtraceCreateSparkThread(cap, spark_tid)         \
    HASKELLEVENT_CREATE_SPARK_THREAD(cap, spark_tid)
#define dtraceThreadLabel(cap, tso, label, len)         \
    HASKELLEVENT_THREAD_LABEL(cap, tso, label, len)
#define dtraceCapCreate(cap)                            \
    HASKELLEVENT_CAP_CREATE(cap)
#define dtraceCapDelete(cap)                            \
    HASKELLEVENT_CAP_DELETE(cap)
#define dtraceCapEnable(cap)                            \
    HASKELLEVENT_CAP_ENABLE(cap)
#define dtraceCapDisable(cap)                           \
    HASKELLEVENT_CAP_DISABLE(cap)
#define dtraceUserMsg(cap, msg)                         \
    HASKELLEVENT_USER_MSG(cap, msg)
#define dtraceUserMarker(cap, msg)                      \
    HASKELLEVENT_USER_MARKER(cap, msg)
#define dtraceGcIdle(cap)                               \
    HASKELLEVENT_GC_IDLE(cap)
#define dtraceGcWork(cap)                               \
    HASKELLEVENT_GC_WORK(cap)
#define dtraceGcDone(cap)                               \
    HASKELLEVENT_GC_DONE(cap)
#define dtraceGcGlobalSync(cap)                         \
    HASKELLEVENT_GC_GLOBAL_SYNC(cap)
#define dtraceEventGcStats(heap_capset, gens,           \
                           copies, slop, fragmentation, \
                           par_n_threads,               \
                           par_max_copied,              \
                           par_tot_copied,              \
                           par_balanced_copied)         \
    HASKELLEVENT_GC_STATS(heap_capset, gens,            \
                           copies, slop, fragmentation, \
                           par_n_threads,               \
                           par_max_copied,              \
                           par_balanced_copied,         \
                           par_tot_copied)
#define dtraceEventMemReturn(current, needed, returned) \
    HASKELLEVENT_MEM_RETURN(current, needed, returned)
#define dtraceHeapInfo(heap_capset, gens,               \
                       maxHeapSize, allocAreaSize,      \
                       mblockSize, blockSize)           \
    HASKELLEVENT_HEAP_INFO(heap_capset, gens,           \
                           maxHeapSize, allocAreaSize,  \
                           mblockSize, blockSize)
#define dtraceEventHeapAllocated(cap, heap_capset,      \
                                 allocated)             \
    HASKELLEVENT_HEAP_ALLOCATED(cap, heap_capset,       \
                                allocated)
#define dtraceEventHeapSize(heap_capset, size)          \
    HASKELLEVENT_HEAP_SIZE(heap_capset, size)
#define dtraceEventBlocksSize(heap_capset, size)        \
    HASKELLEVENT_BLOCKS_SIZE(heap_capset, size)
#define dtraceEventHeapLive(heap_capset, live)          \
    HASKELLEVENT_HEAP_LIVE(heap_capset, live)
#define dtraceCapsetCreate(capset, capset_type)         \
    HASKELLEVENT_CAPSET_CREATE(capset, capset_type)
#define dtraceCapsetDelete(capset)                      \
    HASKELLEVENT_CAPSET_DELETE(capset)
#define dtraceCapsetAssignCap(capset, capno)            \
    HASKELLEVENT_CAPSET_ASSIGN_CAP(capset, capno)
#define dtraceCapsetRemoveCap(capset, capno)            \
    HASKELLEVENT_CAPSET_REMOVE_CAP(capset, capno)
#define dtraceSparkCounters(cap, a, b, c, d, e, f, g) \
    HASKELLEVENT_SPARK_COUNTERS(cap, a, b, c, d, e, f, g)
#define dtraceSparkCreate(cap)                         \
    HASKELLEVENT_SPARK_CREATE(cap)
#define dtraceSparkDud(cap)                             \
    HASKELLEVENT_SPARK_DUD(cap)
#define dtraceSparkOverflow(cap)                        \
    HASKELLEVENT_SPARK_OVERFLOW(cap)
#define dtraceSparkRun(cap)                             \
    HASKELLEVENT_SPARK_RUN(cap)
#define dtraceSparkSteal(cap, victim_cap)               \
    HASKELLEVENT_SPARK_STEAL(cap, victim_cap)
#define dtraceSparkFizzle(cap)                          \
    HASKELLEVENT_SPARK_FIZZLE(cap)
#define dtraceSparkGc(cap)                              \
    HASKELLEVENT_SPARK_GC(cap)
#define dtraceTaskCreate(taskID, cap, tid)              \
    HASKELLEVENT_TASK_CREATE(taskID, cap, tid)
#define dtraceTaskMigrate(taskID, cap, new_cap)         \
    HASKELLEVENT_TASK_MIGRATE(taskID, cap, new_cap)
#define dtraceTaskDelete(taskID)                        \
    HASKELLEVENT_TASK_DELETE(taskID)

#else /* !defined(DTRACE) */

#define dtraceCreateThread(cap, tid)                    /* nothing */
#define dtraceRunThread(cap, tid)                       /* nothing */
#define dtraceStopThread(cap, tid, status, info)        /* nothing */
#define dtraceThreadRunnable(cap, tid)                  /* nothing */
#define dtraceMigrateThread(cap, tid, new_cap)          /* nothing */
#define dtraceThreadWakeup(cap, tid, other_cap)         /* nothing */
#define dtraceGcStart(cap)                              /* nothing */
#define dtraceGcEnd(cap)                                /* nothing */
#define dtraceRequestSeqGc(cap)                         /* nothing */
#define dtraceRequestParGc(cap)                         /* nothing */
#define dtraceCreateSparkThread(cap, spark_tid)         /* nothing */
#define dtraceThreadLabel(cap, tso, label, len)         /* nothing */
#define dtraceUserMsg(cap, msg)                         /* nothing */
#define dtraceUserMarker(cap, msg)                      /* nothing */
#define dtraceGcIdle(cap)                               /* nothing */
#define dtraceGcWork(cap)                               /* nothing */
#define dtraceGcDone(cap)                               /* nothing */
#define dtraceGcGlobalSync(cap)                         /* nothing */
#define dtraceEventGcStats(heap_capset, gens,           \
                           copies, slop, fragmentation, \
                           par_n_threads,               \
                           par_max_copied,              \
                           par_tot_copied,              \
                           par_balanced_copied)         /* nothing */
#define dtraceEventMemReturn(current, needed, returned) /* nothing */
#define dtraceHeapInfo(heap_capset, gens,               \
                       maxHeapSize, allocAreaSize,      \
                       mblockSize, blockSize)           /* nothing */
#define dtraceEventHeapAllocated(cap, heap_capset,      \
                                 allocated)             /* nothing */
#define dtraceEventHeapSize(heap_capset, size)          /* nothing */
#define dtraceEventBlocksSize(heap_capset, size)        /* nothing */
#define dtraceEventHeapLive(heap_capset, live)          /* nothing */
#define dtraceCapCreate(cap)                            /* nothing */
#define dtraceCapDelete(cap)                            /* nothing */
#define dtraceCapEnable(cap)                            /* nothing */
#define dtraceCapDisable(cap)                           /* nothing */
#define dtraceCapsetCreate(capset, capset_type)         /* nothing */
#define dtraceCapsetDelete(capset)                      /* nothing */
#define dtraceCapsetAssignCap(capset, capno)            /* nothing */
#define dtraceCapsetRemoveCap(capset, capno)            /* nothing */
#define dtraceSparkCounters(cap, a, b, c, d, e, f, g)   /* nothing */
#define dtraceSparkCreate(cap)                          /* nothing */
#define dtraceSparkDud(cap)                             /* nothing */
#define dtraceSparkOverflow(cap)                        /* nothing */
#define dtraceSparkRun(cap)                             /* nothing */
#define dtraceSparkSteal(cap, victim_cap)               /* nothing */
#define dtraceSparkFizzle(cap)                          /* nothing */
#define dtraceSparkGc(cap)                              /* nothing */
#define dtraceTaskCreate(taskID, cap, tid)              /* nothing */
#define dtraceTaskMigrate(taskID, cap, new_cap)         /* nothing */
#define dtraceTaskDelete(taskID)                        /* nothing */

#endif

// -----------------------------------------------------------------------------
// Trace probes dispatching to various tracing frameworks
//
// In order to avoid accumulating multiple calls to tracing calls at trace
// points, we define inline probe functions that contain the various
// invocations.
//
// Dtrace - dtrace probes are unconditionally added as probe activation is
//   handled by the dtrace component of the kernel, and inactive probes are
//   very cheap - usually, one no-op.  Consequently, dtrace can be used with
//   all flavours of the RTS.  In addition, we still support logging events to
//   a file, even in the presence of dtrace.  This is, eg, useful when tracing
//   on a server, but browsing trace information with ThreadScope on a local
//   client.
//
// -----------------------------------------------------------------------------

INLINE_HEADER void traceEventCreateThread(Capability *cap STG_UNUSED,
                                          StgTSO     *tso STG_UNUSED)
{
    traceSchedEvent(cap, EVENT_CREATE_THREAD, tso, tso->stackobj->stack_size);
    dtraceCreateThread((EventCapNo)cap->no, (EventThreadID)tso->id);
}

INLINE_HEADER void traceEventRunThread(Capability *cap STG_UNUSED,
                                       StgTSO     *tso STG_UNUSED)
{
    traceSchedEvent(cap, EVENT_RUN_THREAD, tso, tso->what_next);
    dtraceRunThread((EventCapNo)cap->no, (EventThreadID)tso->id);
}

INLINE_HEADER void traceEventStopThread(Capability          *cap    STG_UNUSED,
                                        StgTSO              *tso    STG_UNUSED,
                                        StgThreadReturnCode  status STG_UNUSED,
                                        StgWord32           info    STG_UNUSED)
{
    traceSchedEvent2(cap, EVENT_STOP_THREAD, tso, status, info);
    dtraceStopThread((EventCapNo)cap->no, (EventThreadID)tso->id,
                     (EventThreadStatus)status, (EventThreadID)info);
}

INLINE_HEADER void traceEventMigrateThread(Capability *cap     STG_UNUSED,
                                           StgTSO     *tso     STG_UNUSED,
                                           uint32_t    new_cap STG_UNUSED)
{
    traceSchedEvent(cap, EVENT_MIGRATE_THREAD, tso, new_cap);
    dtraceMigrateThread((EventCapNo)cap->no, (EventThreadID)tso->id,
                        (EventCapNo)new_cap);
}

INLINE_HEADER void traceCapCreate(Capability *cap STG_UNUSED)
{
    traceCapEvent(cap, EVENT_CAP_CREATE);
    dtraceCapCreate((EventCapNo)cap->no);
}

INLINE_HEADER void traceCapDelete(Capability *cap STG_UNUSED)
{
    traceCapEvent(cap, EVENT_CAP_DELETE);
    dtraceCapDelete((EventCapNo)cap->no);
}

INLINE_HEADER void traceCapEnable(Capability *cap STG_UNUSED)
{
    traceCapEvent(cap, EVENT_CAP_ENABLE);
    dtraceCapEnable((EventCapNo)cap->no);
}

INLINE_HEADER void traceCapDisable(Capability *cap STG_UNUSED)
{
    traceCapEvent(cap, EVENT_CAP_DISABLE);
    dtraceCapDisable((EventCapNo)cap->no);

    // Ensure that the eventlog buffer is flushed since otherwise its events
    // may never make it to the output stream.
    // See Note [Eventlog concurrency].
#if defined(TRACING)
    if (eventlog_enabled) {
        flushLocalEventsBuf(cap);
    }
# else
    flushLocalEventsBuf(cap);
#endif

}

INLINE_HEADER void traceEventThreadWakeup(Capability *cap       STG_UNUSED,
                                          StgTSO     *tso       STG_UNUSED,
                                          uint32_t    other_cap STG_UNUSED)
{
    traceSchedEvent(cap, EVENT_THREAD_WAKEUP, tso, other_cap);
    dtraceThreadWakeup((EventCapNo)cap->no, (EventThreadID)tso->id,
                       (EventCapNo)other_cap);
}

INLINE_HEADER void traceThreadLabel(Capability *cap   STG_UNUSED,
                                    StgTSO     *tso   STG_UNUSED,
                                    char       *label STG_UNUSED,
                                    size_t      len   STG_UNUSED)
{
    if (RTS_UNLIKELY(TRACE_sched)) {
        traceThreadLabel_(cap, tso, label, len);
    }
    dtraceThreadLabel((EventCapNo)cap->no, (EventThreadID)tso->id, label, len);
}

INLINE_HEADER void traceEventGcStart(Capability *cap STG_UNUSED)
{
    traceGcEvent(cap, EVENT_GC_START);
    dtraceGcStart((EventCapNo)cap->no);
}

INLINE_HEADER void traceEventGcStartAtT(Capability *cap STG_UNUSED,
                                        StgWord64   ts  STG_UNUSED)
{
    traceGcEventAtT(cap, ts, EVENT_GC_START);
    dtraceGcStart((EventCapNo)cap->no);
}

INLINE_HEADER void traceEventGcEnd(Capability *cap STG_UNUSED)
{
    traceGcEvent(cap, EVENT_GC_END);
    dtraceGcEnd((EventCapNo)cap->no);
}

INLINE_HEADER void traceEventGcEndAtT(Capability *cap STG_UNUSED,
                                      StgWord64   ts  STG_UNUSED)
{
    traceGcEventAtT(cap, ts, EVENT_GC_END);
    dtraceGcEnd((EventCapNo)cap->no);
}

INLINE_HEADER void traceEventRequestSeqGc(Capability *cap STG_UNUSED)
{
    traceGcEvent(cap, EVENT_REQUEST_SEQ_GC);
    dtraceRequestSeqGc((EventCapNo)cap->no);
}

INLINE_HEADER void traceEventRequestParGc(Capability *cap STG_UNUSED)
{
    traceGcEvent(cap, EVENT_REQUEST_PAR_GC);
    dtraceRequestParGc((EventCapNo)cap->no);
}

INLINE_HEADER void traceEventGcIdle(Capability *cap STG_UNUSED)
{
    traceGcEvent(cap, EVENT_GC_IDLE);
    dtraceGcIdle((EventCapNo)cap->no);
}

INLINE_HEADER void traceEventGcWork(Capability *cap STG_UNUSED)
{
    traceGcEvent(cap, EVENT_GC_WORK);
    dtraceGcWork((EventCapNo)cap->no);
}

INLINE_HEADER void traceEventGcDone(Capability *cap STG_UNUSED)
{
    traceGcEvent(cap, EVENT_GC_DONE);
    dtraceGcDone((EventCapNo)cap->no);
}

INLINE_HEADER void traceEventGcGlobalSync(Capability *cap STG_UNUSED)
{
    traceGcEvent(cap, EVENT_GC_GLOBAL_SYNC);
    dtraceGcGlobalSync((EventCapNo)cap->no);
}

INLINE_HEADER void traceEventGcStats(Capability *cap            STG_UNUSED,
                                     CapsetID    heap_capset    STG_UNUSED,
                                     uint32_t    gen            STG_UNUSED,
                                     W_        copied         STG_UNUSED,
                                     W_        slop           STG_UNUSED,
                                     W_        fragmentation  STG_UNUSED,
                                     uint32_t  par_n_threads  STG_UNUSED,
                                     W_        par_max_copied STG_UNUSED,
                                     W_        par_tot_copied STG_UNUSED,
                                     W_        par_balanced_copied STG_UNUSED)
{
    if (RTS_UNLIKELY(TRACE_gc)) {
        traceEventGcStats_(cap, heap_capset, gen,
                           copied, slop, fragmentation,
                           par_n_threads, par_max_copied,
                           par_tot_copied, par_balanced_copied);
    }
    dtraceEventGcStats(heap_capset, gen,
                       copied, slop, fragmentation,
                       par_n_threads, par_max_copied,
                       par_tot_copied, par_balanced_copied);
}

INLINE_HEADER void traceEventMemReturn(Capability *cap            STG_UNUSED,
                                     uint32_t    current_mblocks STG_UNUSED,
                                     uint32_t    needed_mblocks  STG_UNUSED,
                                     uint32_t    returned_mblocks STG_UNUSED)
{
    if (RTS_UNLIKELY(TRACE_gc)) {
        traceEventMemReturn_(cap, current_mblocks, needed_mblocks, returned_mblocks);
    }
    dtraceEventMemReturn(current_mblocks, needed_mblocks, returned_mblocks);
}

INLINE_HEADER void traceEventHeapInfo(CapsetID    heap_capset   STG_UNUSED,
                                      uint32_t  gens          STG_UNUSED,
                                      W_        maxHeapSize   STG_UNUSED,
                                      W_        allocAreaSize STG_UNUSED,
                                      W_        mblockSize    STG_UNUSED,
                                      W_        blockSize     STG_UNUSED)
{
    if (RTS_UNLIKELY(TRACE_gc)) {
        traceEventHeapInfo_(heap_capset, gens,
                            maxHeapSize, allocAreaSize,
                            mblockSize, blockSize);
    }
    dtraceHeapInfo(heap_capset, gens,
                   maxHeapSize, allocAreaSize,
                   mblockSize, blockSize);
}

INLINE_HEADER void traceEventHeapAllocated(Capability *cap         STG_UNUSED,
                                           CapsetID    heap_capset STG_UNUSED,
                                           W_        allocated   STG_UNUSED)
{
    traceHeapEvent(cap, EVENT_HEAP_ALLOCATED, heap_capset, allocated);
    dtraceEventHeapAllocated((EventCapNo)cap->no, heap_capset, allocated);
}

INLINE_HEADER void traceEventHeapSize(Capability *cap         STG_UNUSED,
                                      CapsetID    heap_capset STG_UNUSED,
                                      W_        heap_size   STG_UNUSED)
{
    traceHeapEvent(cap, EVENT_HEAP_SIZE, heap_capset, heap_size);
    dtraceEventHeapSize(heap_capset, heap_size);
}

INLINE_HEADER void traceEventBlocksSize(Capability *cap         STG_UNUSED,
                                        CapsetID    heap_capset STG_UNUSED,
                                        W_        heap_size   STG_UNUSED)
{
    traceHeapEvent(cap, EVENT_BLOCKS_SIZE, heap_capset, heap_size);
    dtraceEventBlocksSize(heap_capset, heap_size);
}

INLINE_HEADER void traceEventHeapLive(Capability *cap         STG_UNUSED,
                                      CapsetID    heap_capset STG_UNUSED,
                                      W_        heap_live   STG_UNUSED)
{
    traceHeapEvent(cap, EVENT_HEAP_LIVE, heap_capset, heap_live);
    dtraceEventHeapLive(heap_capset, heap_live);
}

INLINE_HEADER void traceCapsetCreate(CapsetID   capset      STG_UNUSED,
                                     CapsetType capset_type STG_UNUSED)
{
    traceCapsetEvent(EVENT_CAPSET_CREATE, capset, capset_type);
    dtraceCapsetCreate(capset, capset_type);
}

INLINE_HEADER void traceCapsetDelete(CapsetID capset STG_UNUSED)
{
    traceCapsetEvent(EVENT_CAPSET_DELETE, capset, 0);
    dtraceCapsetDelete(capset);
}

INLINE_HEADER void traceCapsetAssignCap(CapsetID capset STG_UNUSED,
                                        uint32_t capno  STG_UNUSED)
{
    traceCapsetEvent(EVENT_CAPSET_ASSIGN_CAP, capset, capno);
    dtraceCapsetAssignCap(capset, capno);
}

INLINE_HEADER void traceCapsetRemoveCap(CapsetID capset STG_UNUSED,
                                        uint32_t capno  STG_UNUSED)
{
    traceCapsetEvent(EVENT_CAPSET_REMOVE_CAP, capset, capno);
    dtraceCapsetRemoveCap(capset, capno);
}

INLINE_HEADER void traceWallClockTime(void)
{
    traceWallClockTime_();
    /* Note: no DTrace equivalent because it is available to DTrace directly */
}

INLINE_HEADER void traceOSProcessInfo(void)
{
    traceOSProcessInfo_();
    /* Note: no DTrace equivalent because all this OS process info
     * is available to DTrace directly */
}

INLINE_HEADER void traceEventCreateSparkThread(Capability  *cap      STG_UNUSED,
                                               StgThreadID spark_tid STG_UNUSED)
{
    traceSparkEvent2(cap, EVENT_CREATE_SPARK_THREAD, spark_tid);
    dtraceCreateSparkThread((EventCapNo)cap->no, (EventThreadID)spark_tid);
}

INLINE_HEADER void traceSparkCounters(Capability *cap STG_UNUSED)
{
#if defined(THREADED_RTS)
    if (RTS_UNLIKELY(TRACE_spark_sampled)) {
        traceSparkCounters_(cap, cap->spark_stats, sparkPoolSize(cap->sparks));
    }
    dtraceSparkCounters((EventCapNo)cap->no,
                        cap->spark_stats.created,
                        cap->spark_stats.dud,
                        cap->spark_stats.overflowed,
                        cap->spark_stats.converted,
                        cap->spark_stats.gcd,
                        cap->spark_stats.fizzled,
                        sparkPoolSize(cap->sparks));
#endif
}

INLINE_HEADER void traceEventSparkCreate(Capability *cap STG_UNUSED)
{
    traceSparkEvent(cap, EVENT_SPARK_CREATE);
    dtraceSparkCreate((EventCapNo)cap->no);
}

INLINE_HEADER void traceEventSparkDud(Capability *cap STG_UNUSED)
{
    traceSparkEvent(cap, EVENT_SPARK_DUD);
    dtraceSparkDud((EventCapNo)cap->no);
}

INLINE_HEADER void traceEventSparkOverflow(Capability *cap STG_UNUSED)
{
    traceSparkEvent(cap, EVENT_SPARK_OVERFLOW);
    dtraceSparkOverflow((EventCapNo)cap->no);
}

INLINE_HEADER void traceEventSparkRun(Capability *cap STG_UNUSED)
{
    traceSparkEvent(cap, EVENT_SPARK_RUN);
    dtraceSparkRun((EventCapNo)cap->no);
}

INLINE_HEADER void traceEventSparkSteal(Capability *cap STG_UNUSED,
                                        uint32_t    victim_cap STG_UNUSED)
{
    traceSparkEvent2(cap, EVENT_SPARK_STEAL, victim_cap);
    dtraceSparkSteal((EventCapNo)cap->no, (EventCapNo)victim_cap);
}

INLINE_HEADER void traceEventSparkFizzle(Capability *cap STG_UNUSED)
{
    traceSparkEvent(cap, EVENT_SPARK_FIZZLE);
    dtraceSparkFizzle((EventCapNo)cap->no);
}

INLINE_HEADER void traceEventSparkGC(Capability *cap STG_UNUSED)
{
    traceSparkEvent(cap, EVENT_SPARK_GC);
    dtraceSparkGc((EventCapNo)cap->no);
}

INLINE_HEADER void traceTaskCreate(Task       *task STG_UNUSED,
                                   Capability *cap  STG_UNUSED)
{
    ASSERT(task->cap == cap);
    // TODO: asserting task->cap == NULL would be much stronger
    // (the intention being that the task structure is just created and empty)
    // but would require large changes of traceTaskCreate calls.
    ASSERT(cap != NULL);
    // A new task gets associated with a cap. We also record
    // the kernel thread id of the task, which should never change.
    if (RTS_UNLIKELY(TRACE_sched)) {
        traceTaskCreate_(task, cap);
    }
    dtraceTaskCreate(serialisableTaskId(task),
                     (EventCapNo)cap->no,
                     kernelThreadId());
}

INLINE_HEADER void traceTaskMigrate(Task       *task    STG_UNUSED,
                                    Capability *cap     STG_UNUSED,
                                    Capability *new_cap STG_UNUSED)
{
    ASSERT(task->cap == cap);
    ASSERT(cap != NULL);
    ASSERT(cap != new_cap);
    ASSERT(new_cap != NULL);
    // A task migrates from a cap to another.
    if (RTS_UNLIKELY(TRACE_sched)) {
        traceTaskMigrate_(task, cap, new_cap);
    }
    dtraceTaskMigrate(serialisableTaskId(task), (EventCapNo)cap->no,
                                                (EventCapNo)new_cap->no);
}

INLINE_HEADER void traceTaskDelete(Task *task STG_UNUSED)
{
    ASSERT(task->cap != NULL);
    if (RTS_UNLIKELY(TRACE_sched)) {
        traceTaskDelete_(task);
    }
    dtraceTaskDelete(serialisableTaskId(task));
}

#include "EndPrivate.h"