1 /* -----------------------------------------------------------------------------
2  *
3  * (c) The GHC Team, 2019
4  * Author: Daniel Gröber
5  *
6  * Generalised profiling heap traversal.
7  *
8  * ---------------------------------------------------------------------------*/
9 
10 #pragma once
11 
12 #if defined(PROFILING)
13 
14 #include <rts/Types.h>
15 #include "RetainerSet.h"
16 
17 #include "BeginPrivate.h"
18 
19 void resetStaticObjectForProfiling(StgClosure *static_objects);
20 
21 /* See Note [Profiling heap traversal visited bit]. */
22 extern StgWord flip;
23 
24 #define isTravDataValid(c) \
25   ((((StgWord)(c)->header.prof.hp.trav.lsb & 1) ^ flip) == 0)
26 
27 typedef struct traverseState_ traverseState;
28 
29 typedef union stackData_ {
30      /**
31       * Most recent retainer for the corresponding closure on the stack.
32       */
33     retainer c_child_r;
34 } stackData;
35 
36 typedef struct stackElement_ stackElement;
37 
38 typedef struct traverseState_ {
39     /**
40      * Invariants:
41      *
42      *    firstStack points to the first block group.
43      *
44      *    currentStack points to the block group currently being used.
45      *
46      *    currentStack->free == stackLimit.
47      *
48      *    stackTop points to the topmost byte in the stack of currentStack.
49      *
50      *    Unless the whole stack is empty, stackTop must point to the topmost
51      *    object (or byte) in the whole stack. Thus, it is only when the whole
52      *    stack is empty that stackTop == stackLimit (not during the execution
53      *    of pushStackElement() and popStackElement()).
54      *
55      *    stackBottom == currentStack->start.
56      *
57      *    stackLimit
58      *      == currentStack->start + BLOCK_SIZE_W * currentStack->blocks.
59      *
60      *  Note:
61      *
62      *    When a current stack becomes empty, stackTop is set to point to
63      *    the topmost element on the previous block group so as to satisfy
64      *    the invariants described above.
65      */
66     bdescr *firstStack;
67     bdescr *currentStack;
68     stackElement *stackBottom, *stackTop, *stackLimit;
69 
70     /**
71      * stackSize: records the current size of the stack.
72      * maxStackSize: records its high water mark.
73      *
74      * Invariants:
75      *
76      *   stackSize <= maxStackSize
77      *
78      * Note:
79      *
80      *   stackSize is just an estimate measure of the depth of the graph. The
81      *   reason is that some heap objects have only a single child and may not
82      *   result in a new element being pushed onto the stack. Therefore, at the
83      *   end of retainer profiling, maxStackSize is some value no greater than
84      *   the actual depth of the graph.
85      */
86     int stackSize, maxStackSize;
87 } traverseState;
88 
89 /**
90  * Callback called when heap traversal visits a closure.
91  *
92  * The callback can assume that the closure's profiling data has been
93  * initialized to zero if this is the first visit during a pass.
94  *
95  * See Note [Profiling heap traversal visited bit].
96  *
97  * Returning 'false' will instruct the heap traversal code to skip processing
98  * this closure's children. If you don't need to traverse any closure more than
99  * once you can simply return 'first_visit'.
100  */
101 typedef bool (*visitClosure_cb) (
102     StgClosure *c,
103     const StgClosure *cp,
104     const stackData data,
105     const bool first_visit,
106     stackData *child_data);
107 
108 void traverseWorkStack(traverseState *ts, visitClosure_cb visit_cb);
109 void traversePushClosure(traverseState *ts, StgClosure *c, StgClosure *cp, stackData data);
110 bool traverseMaybeInitClosureData(StgClosure *c);
111 
112 void initializeTraverseStack(traverseState *ts);
113 void closeTraverseStack(traverseState *ts);
114 int getTraverseStackMaxSize(traverseState *ts);
115 
116 W_ traverseWorkStackBlocks(traverseState *ts);
117 
118 #include "EndPrivate.h"
119 
120 #endif /* PROFILING */
121