summaryrefslogtreecommitdiff
path: root/rts
diff options
context:
space:
mode:
authorDaniel Gröber <dxld@darkboxed.org>2019-06-14 18:01:59 +0200
committerDaniel Gröber <dxld@darkboxed.org>2019-09-22 15:18:10 +0200
commit2f2f6dd5b708eae4888782ca3eb555152b64ee90 (patch)
tree31b7e16d658dec5c706d6dd74c101d99b987f1a2 /rts
parentf083358b177fad4d5f0325d3cc099eeed64e7f54 (diff)
downloadhaskell-2f2f6dd5b708eae4888782ca3eb555152b64ee90.tar.gz
rts: Generalise profiling heap traversal flip bit handling
This commit starts renaming some flip bit related functions for the generalised heap traversal code and adds provitions for sharing the per-closure profiling header field currently used exclusively for retainer profiling with other heap traversal profiling modes.
Diffstat (limited to 'rts')
-rw-r--r--rts/ProfHeap.c4
-rw-r--r--rts/RetainerProfile.c61
-rw-r--r--rts/RetainerProfile.h13
3 files changed, 49 insertions, 29 deletions
diff --git a/rts/ProfHeap.c b/rts/ProfHeap.c
index 55541f70cc..77e0e6962a 100644
--- a/rts/ProfHeap.c
+++ b/rts/ProfHeap.c
@@ -130,7 +130,7 @@ closureIdentity( const StgClosure *p )
case HEAP_BY_RETAINER:
// AFAIK, the only closures in the heap which might not have a
// valid retainer set are DEAD_WEAK closures.
- if (isRetainerSetFieldValid(p))
+ if (isTravDataValid(p))
return retainerSetOf(p);
else
return NULL;
@@ -638,7 +638,7 @@ closureSatisfiesConstraints( const StgClosure* p )
// reason it might not be valid is if this closure is a
// a newly deceased weak pointer (i.e. a DEAD_WEAK), since
// these aren't reached by the retainer profiler's traversal.
- if (isRetainerSetFieldValid((StgClosure *)p)) {
+ if (isTravDataValid((StgClosure *)p)) {
rs = retainerSetOf((StgClosure *)p);
if (rs != NULL) {
for (i = 0; i < rs->num; i++) {
diff --git a/rts/RetainerProfile.c b/rts/RetainerProfile.c
index ee325ea109..3011029636 100644
--- a/rts/RetainerProfile.c
+++ b/rts/RetainerProfile.c
@@ -81,19 +81,40 @@ static uint32_t numObjectVisited; // total number of objects visited
static uint32_t timesAnyObjectVisited; // number of times any objects are
// visited
-/*
- The rs field in the profile header of any object points to its retainer
- set in an indirect way: if flip is 0, it points to the retainer set;
- if flip is 1, it points to the next byte after the retainer set (even
- for NULL pointers). Therefore, with flip 1, (rs ^ 1) is the actual
- pointer. See retainerSetOf().
+/** Note [Profiling heap traversal visited bit]
+ *
+ * If the RTS is compiled with profiling enabled StgProfHeader can be used by
+ * profiling code to store per-heap object information.
+ *
+ * When using the generic heap traversal code we use this field to store
+ * profiler specific information. However we reserve the LSB of the *entire*
+ * 'trav' union (which will overlap with the other fields) for the generic
+ * traversal code. We use the bit to decide whether we've already visited this
+ * closure in this pass or not. We do this as the heap may contain cyclic
+ * references, it being a graph and all, so we would likely just infinite loop
+ * if we didn't.
+ *
+ * We assume that at least the LSB of the largest field in the corresponding
+ * union is insignificant. This is true at least for the word aligned pointers
+ * which the retainer profiler currently stores there and should be maintained
+ * by new users of the 'trav' union.
+ *
+ * Now the way the traversal works is that the interpretation of the "visited?"
+ * bit depends on the value of the global 'flip' variable. We don't want to have
+ * to do another pass over the heap just to reset the bit to zero so instead on
+ * each traversal (i.e. each run of the profiling code) we invert the value of
+ * the global 'flip' variable. We interpret this as resetting all the "visited?"
+ * flags on the heap.
+ *
+ * There is one exception to this rule, namely: static objects. There we do just
+ * go over the heap and reset the bit manually. See
+ * 'resetStaticObjectForRetainerProfiling'.
*/
-
StgWord flip = 0; // flip bit
// must be 0 if DEBUG_RETAINER is on (for static closures)
-#define setRetainerSetToNull(c) \
- (c)->header.prof.hp.rs = (RetainerSet *)((StgWord)NULL | flip)
+#define setTravDataToZero(c) \
+ (c)->header.prof.hp.trav.lsb = flip
#if defined(DEBUG_RETAINER)
static uint32_t sumOfNewCost; // sum of the cost of each object, computed
@@ -1017,10 +1038,10 @@ endRetainerProfiling( void )
* The reason is that we do not know when a closure is visited last.
* -------------------------------------------------------------------------- */
static INLINE void
-maybeInitRetainerSet( StgClosure *c )
+maybeInitTravData( StgClosure *c )
{
- if (!isRetainerSetFieldValid(c)) {
- setRetainerSetToNull(c);
+ if (!isTravDataValid(c)) {
+ setTravDataToZero(c);
}
}
@@ -1570,7 +1591,7 @@ inner_loop:
timesAnyObjectVisited++;
// If this is the first visit to c, initialize its retainer set.
- maybeInitRetainerSet(c);
+ maybeInitTravData(c);
retainerSetOfc = retainerSetOf(c);
// Now compute s:
@@ -1720,7 +1741,7 @@ retainRoot(void *user, StgClosure **tl)
ts->currentStackBoundary = ts->stackTop;
c = UNTAG_CLOSURE(*tl);
- maybeInitRetainerSet(c);
+ maybeInitTravData(c);
if (c != &stg_END_TSO_QUEUE_closure && isRetainer(c)) {
retainClosure(ts, c, c, getRetainerFrom(c));
} else {
@@ -1786,7 +1807,7 @@ computeRetainerSet( traverseState *ts )
for (bd = capabilities[n]->mut_lists[g]; bd != NULL; bd = bd->link) {
for (ml = bd->start; ml < bd->free; ml++) {
- maybeInitRetainerSet((StgClosure *)*ml);
+ maybeInitTravData((StgClosure *)*ml);
#if defined(DEBUG_RETAINER)
rtl = retainerSetOf((StgClosure *)*ml);
@@ -1818,7 +1839,7 @@ computeRetainerSet( traverseState *ts )
/* -----------------------------------------------------------------------------
* Traverse all static objects for which we compute retainer sets,
* and reset their rs fields to NULL, which is accomplished by
- * invoking maybeInitRetainerSet(). This function must be called
+ * invoking maybeInitTravData(). This function must be called
* before zeroing all objects reachable from scavenged_static_objects
* in the case of major garbage collections. See GarbageCollect() in
* GC.c.
@@ -1834,9 +1855,9 @@ computeRetainerSet( traverseState *ts )
* SDM (20/7/2011): I don't think this is doing anything sensible,
* because it happens before retainerProfile() and at the beginning of
* retainerProfil() we change the sense of 'flip'. So all of the
- * calls to maybeInitRetainerSet() here are initialising retainer sets
+ * calls to maybeInitTravData() here are initialising retainer sets
* with the wrong flip. Also, I don't see why this is necessary. I
- * added a maybeInitRetainerSet() call to retainRoot(), and that seems
+ * added a maybeInitTravData() call to retainRoot(), and that seems
* to have fixed the assertion failure in retainerSetOf() I was
* encountering.
* -------------------------------------------------------------------------- */
@@ -1865,7 +1886,7 @@ resetStaticObjectForRetainerProfiling( StgClosure *static_objects )
p = (StgClosure*)*IND_STATIC_LINK(p);
break;
case THUNK_STATIC:
- maybeInitRetainerSet(p);
+ maybeInitTravData(p);
p = (StgClosure*)*THUNK_STATIC_LINK(p);
break;
case FUN_STATIC:
@@ -1874,7 +1895,7 @@ resetStaticObjectForRetainerProfiling( StgClosure *static_objects )
case CONSTR_2_0:
case CONSTR_1_1:
case CONSTR_NOCAF:
- maybeInitRetainerSet(p);
+ maybeInitTravData(p);
p = (StgClosure*)*STATIC_LINK(get_itbl(p), p);
break;
default:
diff --git a/rts/RetainerProfile.h b/rts/RetainerProfile.h
index bc11cc7e80..3eb27a7346 100644
--- a/rts/RetainerProfile.h
+++ b/rts/RetainerProfile.h
@@ -20,21 +20,20 @@ void endRetainerProfiling ( void );
void retainerProfile ( void );
void resetStaticObjectForRetainerProfiling( StgClosure *static_objects );
-// flip is either 1 or 0, changed at the beginning of retainerProfile()
-// It is used to tell whether a retainer set has been touched so far
-// during this pass.
+/* See Note [Profiling heap traversal visited bit]. */
extern StgWord flip;
// extract the retainer set field from c
-#define RSET(c) ((c)->header.prof.hp.rs)
+#define RSET(c) ((c)->header.prof.hp.trav.rs)
-#define isRetainerSetFieldValid(c) \
- ((((StgWord)(c)->header.prof.hp.rs & 1) ^ flip) == 0)
+
+#define isTravDataValid(c) \
+ ((((StgWord)(c)->header.prof.hp.trav.lsb & 1) ^ flip) == 0)
static inline RetainerSet *
retainerSetOf( const StgClosure *c )
{
- ASSERT( isRetainerSetFieldValid(c) );
+ ASSERT( isTravDataValid(c) );
// StgWord has the same size as pointers, so the following type
// casting is okay.
return (RetainerSet *)((StgWord)RSET(c) ^ flip);