[Git][ghc/ghc][wip/T7275] 2 commits: rts: Break up census logic

Ben Gamari gitlab at gitlab.haskell.org
Wed Dec 9 21:23:46 UTC 2020



Ben Gamari pushed to branch wip/T7275 at Glasgow Haskell Compiler / GHC


Commits:
8e9210ff by Ben Gamari at 2020-12-09T16:14:02-05:00
rts: Break up census logic

Move the logic for taking censuses of "normal" and pinned blocks to
their own functions.

- - - - -
48beb603 by Ben Gamari at 2020-12-09T16:16:32-05:00
rts: Implement heap census support for pinned objects

It turns out that this was fairly straightforward to implement since we
are now pretty careful about zeroing slop.

- - - - -


1 changed file:

- rts/ProfHeap.c


Changes:

=====================================
rts/ProfHeap.c
=====================================
@@ -1103,214 +1103,240 @@ 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);
+    StgWord *p = (StgWord *) bd->start;
+    while (p < bd->free) {
+        if (*(StgWord *) p == 0) {
+            p++;
             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;
+        ASSERT(LOOKS_LIKE_CLOSURE_PTR(p));
+        const StgInfoTable *info = get_itbl((StgClosure *) p);
+        switch (info->type) {
+          case ARR_WORDS:
+            {
+              StgArrBytes *arr = (StgArrBytes *) p;
+              const size_t size = arr_words_sizeW(arr);
+              heapProfObject(census, (StgClosure *)p, size, /*prim*/ true);
+              p += size;
+              break;
+            }
+          default:
+            barf("heapCensusPinnedBlock: Unknown object: %p (info=%p, type=%d)", p, info, info->type);
         }
+    }
+}
 
+/*
+ * 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;
 
-        while (p < bd->free) {
-            info = get_itbl((const StgClosure *)p);
-            prim = false;
-
-            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;
+
+        // 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;
         }
+
+        if (bd->flags & BF_PINNED) {
+            heapCensusPinnedBlock(census, bd);
+            continue;
+        }
+
+        heapCensusNormalBlock(census, bd);
     }
 }
 



View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/compare/9bcaaaabfa80e58912cb4f0a26c3d3f94c6519aa...48beb6035a1727e8688fef9f974d52dfca1d1fab

-- 
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/compare/9bcaaaabfa80e58912cb4f0a26c3d3f94c6519aa...48beb6035a1727e8688fef9f974d52dfca1d1fab
You're receiving this email because of your account on gitlab.haskell.org.


-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.haskell.org/pipermail/ghc-commits/attachments/20201209/419727aa/attachment-0001.html>


More information about the ghc-commits mailing list