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