From ded96fb3ad540e0145483574b4a09bdcbe964c88 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=96mer=20Sinan=20A=C4=9Facan?= Date: Thu, 19 Sep 2019 10:16:09 +0300 Subject: [PATCH] Document MIN_PAYLOAD_SIZE and mark-compact GC mark bits This updates the documentation of the MIN_PAYLOAD_SIZE constant and adds a new Note [Mark bits in mark-compact collector] explaning why the mark-compact collector uses two bits per objet and why we need MIN_PAYLOAD_SIZE. --- includes/rts/Constants.h | 8 +++++--- rts/sm/Compact.c | 9 +++++---- rts/sm/Compact.h | 39 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 49 insertions(+), 7 deletions(-) diff --git a/includes/rts/Constants.h b/includes/rts/Constants.h index 15ff2a43d9..c2cad8fc80 100644 --- a/includes/rts/Constants.h +++ b/includes/rts/Constants.h @@ -22,9 +22,11 @@ /* ----------------------------------------------------------------------------- Minimum closure sizes - This is the minimum number of words in the payload of a - heap-allocated closure, so that the closure has enough room to be - overwritten with a forwarding pointer during garbage collection. + This is the minimum number of words in the payload of a heap-allocated + closure, so that the closure has two bits in the bitmap for mark-compact + collection. + + See Note [Mark bits in mark-compact collector] in rts/sm/Compact.h -------------------------------------------------------------------------- */ #define MIN_PAYLOAD_SIZE 1 diff --git a/rts/sm/Compact.c b/rts/sm/Compact.c index 3bfefa7ceb..927a50595a 100644 --- a/rts/sm/Compact.c +++ b/rts/sm/Compact.c @@ -830,10 +830,11 @@ update_fwd_compact( bdescr *blocks ) size = p - q; if (free + size > free_bd->start + BLOCK_SIZE_W) { - // set the next bit in the bitmap to indicate that - // this object needs to be pushed into the next - // block. This saves us having to run down the - // threaded info pointer list twice during the next pass. + // set the next bit in the bitmap to indicate that this object + // needs to be pushed into the next block. This saves us having + // to run down the threaded info pointer list twice during the + // next pass. See Note [Mark bits in mark-compact collector] in + // Compact.h. mark(q+1,bd); free_bd = free_bd->link; free = free_bd->start; diff --git a/rts/sm/Compact.h b/rts/sm/Compact.h index b0521122df..be9a09d4ab 100644 --- a/rts/sm/Compact.h +++ b/rts/sm/Compact.h @@ -15,6 +15,45 @@ #include "BeginPrivate.h" +/* ----------------------------------------------------------------------------- + Note [Mark bits in mark-compact collector] + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + In mark-compact collector each closure has two mark bits: + + - Liveness bit: not marked == unreachable (dead) + + - "Too large" bit: when this is set it means that the closure won't fit in + the current heap block and we need to move it to the next block in the + heap. + + Why do we need the second bit? We only know a closure's size *before* + threading it, because after threading the info table pointer will be end of + the chain. So by the time we do the second pass to move the closures and + unthread chains we'd have to do two passes, one for to get the info table + pointer at the end of the chain to compute the closure size and update the + free pointer if it's too large to fit in the current block, and then another + pass to actually unthread. + + To avoid this we update the second bit when we first visit an object (in the + "forward" pass) and realize that it won't fit in the current block, and check + that bit in the second pass (where we actually move the object and update all + references). If the bit is set we move the object to the free location in the + next block in heap chain, otherwise we use the free pointer in the current + block. + + Instead of allocating two bits per object, we use the fact that most heap + closures will be at least two words (as one-word closures will mostly be + static objects), and allocate one bit per word in the heap. In the rare cases + where we allocate single-word heap objects (e.g. a non-top-level FUN with + empty payload) we add one non-pointer field to the payload so that the object + will have two words. The minimum amount of words in the payload is defined in + includes/rts/Constants.h as MIN_PAYLOAD_SIZE. + + (See also !1701 where we discussed lifting this restriction and allocating + two bits per object) + -------------------------------------------------------------------------- */ + INLINE_HEADER void mark(StgPtr p, bdescr *bd) { -- 2.22.0