summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBen Gamari <ben@smart-cactus.org>2020-12-09 13:43:37 -0500
committerMarge Bot <ben+marge-bot@smart-cactus.org>2021-01-07 00:10:15 -0500
commit3e2ea550093c16528a40b4d6352e375d8b4a2064 (patch)
tree9e50a8880085a771cdadcffdefad753ea988b8d6
parent6c771aafa30e261f6822b3ddddbe66f8a55f307c (diff)
downloadhaskell-3e2ea550093c16528a40b4d6352e375d8b4a2064.tar.gz
rts: Break up census logic
Move the logic for taking censuses of "normal" and pinned blocks to their own functions.
-rw-r--r--rts/ProfHeap.c363
1 files changed, 187 insertions, 176 deletions
diff --git a/rts/ProfHeap.c b/rts/ProfHeap.c
index 06bff048e7..1b8b810188 100644
--- a/rts/ProfHeap.c
+++ b/rts/ProfHeap.c
@@ -1103,214 +1103,225 @@ heapCensusCompactList(Census *census, bdescr *bd)
}
}
-/* -----------------------------------------------------------------------------
- * Code to perform a heap census.
- * -------------------------------------------------------------------------- */
static void
-heapCensusChain( Census *census, bdescr *bd )
+heapCensusPinnedBlock( Census *census, bdescr *bd )
{
- StgPtr p;
- const StgInfoTable *info;
- size_t size;
- bool prim;
-
- for (; bd != NULL; bd = bd->link) {
-
- // HACK: pretend a pinned block is just one big ARR_WORDS
- // owned by CCS_PINNED. These blocks can be full of holes due
- // to alignment constraints so we can't traverse the memory
- // and do a proper census.
- if (bd->flags & BF_PINNED) {
- StgClosure arr;
- SET_HDR(&arr, &stg_ARR_WORDS_info, CCS_PINNED);
- heapProfObject(census, &arr, bd->blocks * BLOCK_SIZE_W, true);
- continue;
- }
-
- p = bd->start;
-
- // When we shrink a large ARR_WORDS, we do not adjust the free pointer
- // of the associated block descriptor, thus introducing slop at the end
- // of the object. This slop remains after GC, violating the assumption
- // of the loop below that all slop has been eliminated (#11627).
- // The slop isn't always zeroed (e.g. in non-profiling mode, cf
- // OVERWRITING_CLOSURE_OFS).
- // Consequently, we handle large ARR_WORDS objects as a special case.
- if (bd->flags & BF_LARGE
- && get_itbl((StgClosure *)p)->type == ARR_WORDS) {
- size = arr_words_sizeW((StgArrBytes *)p);
- prim = true;
- heapProfObject(census, (StgClosure *)p, size, prim);
- continue;
- }
-
+ // HACK: pretend a pinned block is just one big ARR_WORDS
+ // owned by CCS_PINNED. These blocks can be full of holes due
+ // to alignment constraints so we can't traverse the memory
+ // and do a proper census.
+ StgClosure arr;
+ SET_HDR(&arr, &stg_ARR_WORDS_info, CCS_PINNED);
+ heapProfObject(census, &arr, bd->blocks * BLOCK_SIZE_W, true);
+}
- while (p < bd->free) {
- info = get_itbl((const StgClosure *)p);
- prim = false;
+/*
+ * Take a census of the contents of a "normal" (e.g. not large, not pinned, not
+ * compact) heap block.
+ */
+static void
+heapCensusNormalBlock(Census *census, bdescr *bd)
+{
+ StgPtr p = bd->start;
+ while (p < bd->free) {
+ const StgInfoTable *info = get_itbl((const StgClosure *)p);
+ bool prim = false;
+ size_t size;
- switch (info->type) {
+ switch (info->type) {
- case THUNK:
- size = thunk_sizeW_fromITBL(info);
- break;
+ case THUNK:
+ size = thunk_sizeW_fromITBL(info);
+ break;
- case THUNK_1_1:
- case THUNK_0_2:
- case THUNK_2_0:
- size = sizeofW(StgThunkHeader) + 2;
- break;
+ case THUNK_1_1:
+ case THUNK_0_2:
+ case THUNK_2_0:
+ size = sizeofW(StgThunkHeader) + 2;
+ break;
- case THUNK_1_0:
- case THUNK_0_1:
- case THUNK_SELECTOR:
- size = sizeofW(StgThunkHeader) + 1;
- break;
+ case THUNK_1_0:
+ case THUNK_0_1:
+ case THUNK_SELECTOR:
+ size = sizeofW(StgThunkHeader) + 1;
+ break;
- case FUN:
- case BLACKHOLE:
- case BLOCKING_QUEUE:
- case FUN_1_0:
- case FUN_0_1:
- case FUN_1_1:
- case FUN_0_2:
- case FUN_2_0:
- case CONSTR:
- case CONSTR_NOCAF:
- case CONSTR_1_0:
- case CONSTR_0_1:
- case CONSTR_1_1:
- case CONSTR_0_2:
- case CONSTR_2_0:
- size = sizeW_fromITBL(info);
- break;
+ case FUN:
+ case BLACKHOLE:
+ case BLOCKING_QUEUE:
+ case FUN_1_0:
+ case FUN_0_1:
+ case FUN_1_1:
+ case FUN_0_2:
+ case FUN_2_0:
+ case CONSTR:
+ case CONSTR_NOCAF:
+ case CONSTR_1_0:
+ case CONSTR_0_1:
+ case CONSTR_1_1:
+ case CONSTR_0_2:
+ case CONSTR_2_0:
+ size = sizeW_fromITBL(info);
+ break;
- case IND:
- // Special case/Delicate Hack: INDs don't normally
- // appear, since we're doing this heap census right
- // after GC. However, GarbageCollect() also does
- // resurrectThreads(), which can update some
- // blackholes when it calls raiseAsync() on the
- // resurrected threads. So we know that any IND will
- // be the size of a BLACKHOLE.
- size = BLACKHOLE_sizeW();
- break;
+ case IND:
+ // Special case/Delicate Hack: INDs don't normally
+ // appear, since we're doing this heap census right
+ // after GC. However, GarbageCollect() also does
+ // resurrectThreads(), which can update some
+ // blackholes when it calls raiseAsync() on the
+ // resurrected threads. So we know that any IND will
+ // be the size of a BLACKHOLE.
+ size = BLACKHOLE_sizeW();
+ break;
- case BCO:
- prim = true;
- size = bco_sizeW((StgBCO *)p);
- break;
+ case BCO:
+ prim = true;
+ size = bco_sizeW((StgBCO *)p);
+ break;
- case MVAR_CLEAN:
- case MVAR_DIRTY:
- case TVAR:
- case WEAK:
- case PRIM:
- case MUT_PRIM:
- case MUT_VAR_CLEAN:
- case MUT_VAR_DIRTY:
- prim = true;
- size = sizeW_fromITBL(info);
- break;
+ case MVAR_CLEAN:
+ case MVAR_DIRTY:
+ case TVAR:
+ case WEAK:
+ case PRIM:
+ case MUT_PRIM:
+ case MUT_VAR_CLEAN:
+ case MUT_VAR_DIRTY:
+ prim = true;
+ size = sizeW_fromITBL(info);
+ break;
- case AP:
- size = ap_sizeW((StgAP *)p);
- break;
+ case AP:
+ size = ap_sizeW((StgAP *)p);
+ break;
- case PAP:
- size = pap_sizeW((StgPAP *)p);
- break;
+ case PAP:
+ size = pap_sizeW((StgPAP *)p);
+ break;
- case AP_STACK:
- size = ap_stack_sizeW((StgAP_STACK *)p);
- break;
+ case AP_STACK:
+ size = ap_stack_sizeW((StgAP_STACK *)p);
+ break;
- case ARR_WORDS:
- prim = true;
- size = arr_words_sizeW((StgArrBytes*)p);
- break;
+ case ARR_WORDS:
+ prim = true;
+ size = arr_words_sizeW((StgArrBytes*)p);
+ break;
- case MUT_ARR_PTRS_CLEAN:
- case MUT_ARR_PTRS_DIRTY:
- case MUT_ARR_PTRS_FROZEN_CLEAN:
- case MUT_ARR_PTRS_FROZEN_DIRTY:
- prim = true;
- size = mut_arr_ptrs_sizeW((StgMutArrPtrs *)p);
- break;
+ case MUT_ARR_PTRS_CLEAN:
+ case MUT_ARR_PTRS_DIRTY:
+ case MUT_ARR_PTRS_FROZEN_CLEAN:
+ case MUT_ARR_PTRS_FROZEN_DIRTY:
+ prim = true;
+ size = mut_arr_ptrs_sizeW((StgMutArrPtrs *)p);
+ break;
- case SMALL_MUT_ARR_PTRS_CLEAN:
- case SMALL_MUT_ARR_PTRS_DIRTY:
- case SMALL_MUT_ARR_PTRS_FROZEN_CLEAN:
- case SMALL_MUT_ARR_PTRS_FROZEN_DIRTY:
- prim = true;
- size = small_mut_arr_ptrs_sizeW((StgSmallMutArrPtrs *)p);
- break;
+ case SMALL_MUT_ARR_PTRS_CLEAN:
+ case SMALL_MUT_ARR_PTRS_DIRTY:
+ case SMALL_MUT_ARR_PTRS_FROZEN_CLEAN:
+ case SMALL_MUT_ARR_PTRS_FROZEN_DIRTY:
+ prim = true;
+ size = small_mut_arr_ptrs_sizeW((StgSmallMutArrPtrs *)p);
+ break;
- case TSO:
- prim = true;
+ case TSO:
+ prim = true;
#if defined(PROFILING)
- if (RtsFlags.ProfFlags.includeTSOs) {
- size = sizeofW(StgTSO);
- break;
- } else {
- // Skip this TSO and move on to the next object
- p += sizeofW(StgTSO);
- continue;
- }
-#else
+ if (RtsFlags.ProfFlags.includeTSOs) {
size = sizeofW(StgTSO);
break;
+ } else {
+ // Skip this TSO and move on to the next object
+ p += sizeofW(StgTSO);
+ continue;
+ }
+#else
+ size = sizeofW(StgTSO);
+ break;
#endif
- case STACK:
- prim = true;
+ case STACK:
+ prim = true;
#if defined(PROFILING)
- if (RtsFlags.ProfFlags.includeTSOs) {
- size = stack_sizeW((StgStack*)p);
- break;
- } else {
- // Skip this TSO and move on to the next object
- p += stack_sizeW((StgStack*)p);
- continue;
- }
-#else
+ if (RtsFlags.ProfFlags.includeTSOs) {
size = stack_sizeW((StgStack*)p);
break;
+ } else {
+ // Skip this TSO and move on to the next object
+ p += stack_sizeW((StgStack*)p);
+ continue;
+ }
+#else
+ size = stack_sizeW((StgStack*)p);
+ break;
#endif
- case TREC_CHUNK:
- prim = true;
- size = sizeofW(StgTRecChunk);
- break;
+ case TREC_CHUNK:
+ prim = true;
+ size = sizeofW(StgTRecChunk);
+ break;
- case COMPACT_NFDATA:
- barf("heapCensus, found compact object in the wrong list");
- break;
+ case COMPACT_NFDATA:
+ barf("heapCensus, found compact object in the wrong list");
+ break;
- default:
- barf("heapCensus, unknown object: %d", info->type);
- }
+ default:
+ barf("heapCensus, unknown object: %d", info->type);
+ }
+
+ heapProfObject(census,(StgClosure*)p,size,prim);
+
+ p += size;
+
+ /* skip over slop, see Note [slop on the heap] */
+ while (p < bd->free && !*p) p++;
+ /* Note [skipping slop in the heap profiler]
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ * We make sure to zero slop that can remain after a major GC so
+ * here we can assume any slop words we see until the block's free
+ * pointer are zero. Since info pointers are always nonzero we can
+ * use this to scan for the next valid heap closure.
+ *
+ * Note that not all types of slop are relevant here, only the ones
+ * that can reman after major GC. So essentially just large objects
+ * and pinned objects. All other closures will have been packed nice
+ * and thight into fresh blocks.
+ */
+ }
+}
- heapProfObject(census,(StgClosure*)p,size,prim);
-
- p += size;
-
- /* skip over slop, see Note [slop on the heap] */
- while (p < bd->free && !*p) p++;
- /* Note [skipping slop in the heap profiler]
- * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- *
- * We make sure to zero slop that can remain after a major GC so
- * here we can assume any slop words we see until the block's free
- * pointer are zero. Since info pointers are always nonzero we can
- * use this to scan for the next valid heap closure.
- *
- * Note that not all types of slop are relevant here, only the ones
- * that can reman after major GC. So essentially just large objects
- * and pinned objects. All other closures will have been packed nice
- * and thight into fresh blocks.
- */
+/* -----------------------------------------------------------------------------
+ * Code to perform a heap census.
+ * -------------------------------------------------------------------------- */
+static void
+heapCensusChain( Census *census, bdescr *bd )
+{
+ for (; bd != NULL; bd = bd->link) {
+ StgPtr p = bd->start;
+
+ if (bd->flags & BF_PINNED) {
+ heapCensusPinnedBlock(census, bd);
+ continue;
}
+
+ // When we shrink a large ARR_WORDS, we do not adjust the free pointer
+ // of the associated block descriptor, thus introducing slop at the end
+ // of the object. This slop remains after GC, violating the assumption
+ // of the loop below that all slop has been eliminated (#11627).
+ // The slop isn't always zeroed (e.g. in non-profiling mode, cf
+ // OVERWRITING_CLOSURE_OFS).
+ // Consequently, we handle large ARR_WORDS objects as a special case.
+ if (bd->flags & BF_LARGE
+ && get_itbl((StgClosure *)p)->type == ARR_WORDS) {
+ size_t size = arr_words_sizeW((StgArrBytes *)p);
+ bool prim = true;
+ heapProfObject(census, (StgClosure *)p, size, prim);
+ continue;
+ }
+
+ heapCensusNormalBlock(census, bd);
}
}