[BACK]Return to backgraph.c CVS log [TXT][DIR] Up to [local] / OpenXM_contrib2 / asir2000 / gc

Annotation of OpenXM_contrib2/asir2000/gc/backgraph.c, Revision 1.1

1.1     ! noro        1: /*
        !             2:  * Copyright (c) 2001 by Hewlett-Packard Company. All rights reserved.
        !             3:  *
        !             4:  * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
        !             5:  * OR IMPLIED.  ANY USE IS AT YOUR OWN RISK.
        !             6:  *
        !             7:  * Permission is hereby granted to use or copy this program
        !             8:  * for any purpose,  provided the above notices are retained on all copies.
        !             9:  * Permission to modify the code and to distribute modified code is granted,
        !            10:  * provided the above notices are retained, and a notice that the code was
        !            11:  * modified is included with the above copyright notice.
        !            12:  *
        !            13:  */
        !            14:
        !            15: /*
        !            16:  * This implements a full, though not well-tuned, representation of the
        !            17:  * backwards points-to graph.  This is used to test for non-GC-robust
        !            18:  * data structures; the code is not used during normal garbage collection.
        !            19:  *
        !            20:  * One restriction is that we drop all back-edges from nodes with very
        !            21:  * high in-degree, and simply add them add them to a list of such
        !            22:  * nodes.  They are then treated as permanent roots.  Id this by itself
        !            23:  * doesn't introduce a space leak, then such nodes can't contribute to
        !            24:  * a growing space leak.
        !            25:  */
        !            26:
        !            27: #ifdef MAKE_BACK_GRAPH
        !            28:
        !            29: #define MAX_IN 10      /* Maximum in-degree we handle directly */
        !            30:
        !            31: #include "private/dbg_mlc.h"
        !            32: #include <unistd.h>
        !            33:
        !            34: #if !defined(DBG_HDRS_ALL) || (ALIGNMENT != CPP_WORDSZ/8) || !defined(UNIX_LIKE)
        !            35: # error Configuration doesnt support MAKE_BACK_GRAPH
        !            36: #endif
        !            37:
        !            38: /* We store single back pointers directly in the object's oh_bg_ptr field.   */
        !            39: /* If there is more than one ptr to an object, we store q | FLAG_MANY,              */
        !            40: /* where q is a pointer to a back_edges object.                                     */
        !            41: /* Every once in a while we use a back_edges object even for a single       */
        !            42: /* pointer, since we need the other fields in the back_edges structure to    */
        !            43: /* be present in some fraction of the objects.  Otherwise we get serious     */
        !            44: /* performance issues.                                                      */
        !            45: #define FLAG_MANY 2
        !            46:
        !            47: typedef struct back_edges_struct {
        !            48:   word n_edges;        /* Number of edges, including those in continuation     */
        !            49:                /* structures.                                          */
        !            50:   unsigned short flags;
        !            51: #      define RETAIN 1 /* Directly points to a reachable object;       */
        !            52:                        /* retain for next GC.                          */
        !            53:   unsigned short height_gc_no;
        !            54:                /* If height > 0, then the GC_gc_no value when it       */
        !            55:                /* was computed.  If it was computed this cycle, then   */
        !            56:                /* it is current.  If it was computed during the        */
        !            57:                /* last cycle, then it represents the old height,       */
        !            58:                /* which is only saved for live objects referenced by   */
        !            59:                /* dead ones.  This may grow due to refs from newly     */
        !            60:                /* dead objects.                                        */
        !            61:   signed_word height;
        !            62:                /* Longest path through unreachable nodes to this node  */
        !            63:                /* that we found using depth first search.              */
        !            64:
        !            65: #   define HEIGHT_UNKNOWN ((signed_word)(-2))
        !            66: #   define HEIGHT_IN_PROGRESS ((signed_word)(-1))
        !            67:   ptr_t edges[MAX_IN];
        !            68:   struct back_edges_struct *cont;
        !            69:                /* Pointer to continuation structure; we use only the   */
        !            70:                /* edges field in the continuation.                     */
        !            71:                /* also used as free list link.                         */
        !            72: } back_edges;
        !            73:
        !            74: /* Allocate a new back edge structure.  Should be more sophisticated   */
        !            75: /* if this were production code.                                       */
        !            76: #define MAX_BACK_EDGE_STRUCTS 100000
        !            77: static back_edges *back_edge_space = 0;
        !            78: int GC_n_back_edge_structs = 0;        /* Serves as pointer to never used      */
        !            79:                                /* back_edges space.                    */
        !            80: static back_edges *avail_back_edges = 0;
        !            81:                                /* Pointer to free list of deallocated  */
        !            82:                                /* back_edges structures.               */
        !            83:
        !            84: static back_edges * new_back_edges(void)
        !            85: {
        !            86:   if (0 == back_edge_space) {
        !            87:     back_edge_space = (back_edges *)
        !            88:                        sbrk(MAX_BACK_EDGE_STRUCTS*sizeof(back_edges));
        !            89:   }
        !            90:   if (0 != avail_back_edges) {
        !            91:     back_edges * result = avail_back_edges;
        !            92:     avail_back_edges = result -> cont;
        !            93:     result -> cont = 0;
        !            94:     return result;
        !            95:   }
        !            96:   if (GC_n_back_edge_structs >= MAX_BACK_EDGE_STRUCTS - 1) {
        !            97:     ABORT("needed too much space for back edges: adjust "
        !            98:          "MAX_BACK_EDGE_STRUCTS");
        !            99:   }
        !           100:   return back_edge_space + (GC_n_back_edge_structs++);
        !           101: }
        !           102:
        !           103: /* Deallocate p and its associated continuation structures.    */
        !           104: static void deallocate_back_edges(back_edges *p)
        !           105: {
        !           106:    back_edges *last = p;
        !           107:
        !           108:    while (0 != last -> cont) last = last -> cont;
        !           109:    last -> cont = avail_back_edges;
        !           110:    avail_back_edges = p;
        !           111: }
        !           112:
        !           113: /* Table of objects that are currently on the depth-first search       */
        !           114: /* stack.  Only objects with in-degree one are in this table.          */
        !           115: /* Other objects are identified using HEIGHT_IN_PROGRESS.              */
        !           116: /* This data structure NEEDS IMPROVEMENT.                              */
        !           117: #define MAX_IN_PROGRESS 10000
        !           118: static ptr_t * in_progress_space = 0;
        !           119: static int n_in_progress = 0;
        !           120:
        !           121: static void push_in_progress(ptr_t p)
        !           122: {
        !           123:   if (in_progress_space == 0)
        !           124:       in_progress_space = sbrk(MAX_IN_PROGRESS * sizeof(ptr_t));
        !           125:   if (n_in_progress == MAX_IN_PROGRESS)
        !           126:       ABORT("Exceeded MAX_IN_PROGRESS");
        !           127:   in_progress_space[n_in_progress++] = p;
        !           128: }
        !           129:
        !           130: static GC_bool is_in_progress(ptr_t p)
        !           131: {
        !           132:   int i;
        !           133:   for (i = 0; i < n_in_progress; ++i) {
        !           134:     if (in_progress_space[i] == p) return TRUE;
        !           135:   }
        !           136:   return FALSE;
        !           137: }
        !           138:
        !           139: static void pop_in_progress(ptr_t p)
        !           140: {
        !           141:   --n_in_progress;
        !           142:   GC_ASSERT(in_progress_space[n_in_progress] == p);
        !           143: }
        !           144:
        !           145: #define GET_OH_BG_PTR(p) \
        !           146:                (ptr_t)REVEAL_POINTER(((oh *)(p)) -> oh_bg_ptr)
        !           147: #define SET_OH_BG_PTR(p,q) (((oh *)(p)) -> oh_bg_ptr) = HIDE_POINTER(q)
        !           148:
        !           149: /* Execute s once for each predecessor q of p in the points-to graph.  */
        !           150: /* s should be a bracketed statement.  We declare q.                   */
        !           151: #define FOR_EACH_PRED(q, p, s) \
        !           152:   { \
        !           153:     ptr_t q = GET_OH_BG_PTR(p); \
        !           154:     if (!((word)q & FLAG_MANY)) { \
        !           155:       if (q && !((word)q & 1)) s \
        !           156:              /* !((word)q & 1) checks for a misnterpreted freelist link */ \
        !           157:     } else { \
        !           158:       back_edges *orig_be_ = (back_edges *)((word)q & ~FLAG_MANY); \
        !           159:       back_edges *be_ = orig_be_; \
        !           160:       int total_, local_; \
        !           161:       int n_edges_ = be_ -> n_edges; \
        !           162:       for (total_ = 0, local_ = 0; total_ < n_edges_; ++local_, ++total_) { \
        !           163:          if (local_ == MAX_IN) { \
        !           164:              be_ = be_ -> cont; \
        !           165:              local_ = 0; \
        !           166:          } \
        !           167:          q = be_ -> edges[local_]; s \
        !           168:       } \
        !           169:     } \
        !           170:   }
        !           171:
        !           172: /* Ensure that p has a back_edges structure associated with it.        */
        !           173: static void ensure_struct(ptr_t p)
        !           174: {
        !           175:   ptr_t old_back_ptr = GET_OH_BG_PTR(p);
        !           176:
        !           177:   if (!((word)old_back_ptr & FLAG_MANY)) {
        !           178:     back_edges *be = new_back_edges();
        !           179:     be -> flags = 0;
        !           180:     if (0 == old_back_ptr) {
        !           181:       be -> n_edges = 0;
        !           182:     } else {
        !           183:       be -> n_edges = 1;
        !           184:       be -> edges[0] = old_back_ptr;
        !           185:     }
        !           186:     be -> height = HEIGHT_UNKNOWN;
        !           187:     be -> height_gc_no = GC_gc_no - 1;
        !           188:     GC_ASSERT(be >= back_edge_space);
        !           189:     SET_OH_BG_PTR(p, (word)be | FLAG_MANY);
        !           190:   }
        !           191: }
        !           192:
        !           193: /* Add the (forward) edge from p to q to the backward graph.  Both p   */
        !           194: /* q are pointers to the object base, i.e. pointers to an oh.          */
        !           195: static void add_edge(ptr_t p,  ptr_t q)
        !           196: {
        !           197:     ptr_t old_back_ptr = GET_OH_BG_PTR(q);
        !           198:     back_edges * be, *be_cont;
        !           199:     word i;
        !           200:     static unsigned random_number = 13;
        !           201: #   define GOT_LUCKY_NUMBER (((++random_number) & 0x7f) == 0)
        !           202:       /* A not very random number we use to occasionally allocate a    */
        !           203:       /* back_edges structure even for a single backward edge.  This   */
        !           204:       /* prevents us from repeatedly tracing back through very long    */
        !           205:       /* chains, since we will have some place to store height and     */
        !           206:       /* in_progress flags along the way.                              */
        !           207:
        !           208:     GC_ASSERT(p == GC_base(p) && q == GC_base(q));
        !           209:     if (!GC_HAS_DEBUG_INFO(q) || !GC_HAS_DEBUG_INFO(p)) {
        !           210:       /* This is really a misinterpreted free list link, since we saw */
        !           211:       /* a pointer to a free list.  Dont overwrite it!               */
        !           212:       return;
        !           213:     }
        !           214:     if (0 == old_back_ptr) {
        !           215:        SET_OH_BG_PTR(q, p);
        !           216:        if (GOT_LUCKY_NUMBER) ensure_struct(q);
        !           217:        return;
        !           218:     }
        !           219:     /* Check whether it was already in the list of predecessors. */
        !           220:       FOR_EACH_PRED(pred, q, { if (p == pred) return; });
        !           221:     ensure_struct(q);
        !           222:     old_back_ptr = GET_OH_BG_PTR(q);
        !           223:     be = (back_edges *)((word)old_back_ptr & ~FLAG_MANY);
        !           224:     for (i = be -> n_edges, be_cont = be; i > MAX_IN;
        !           225:        be_cont = be_cont -> cont, i -= MAX_IN) {}
        !           226:     if (i == MAX_IN) {
        !           227:        be_cont -> cont = new_back_edges();
        !           228:        be_cont = be_cont -> cont;
        !           229:        i = 0;
        !           230:     }
        !           231:     be_cont -> edges[i] = p;
        !           232:     be -> n_edges++;
        !           233:     if (be -> n_edges == 100) {
        !           234: #       if 0
        !           235:          if (GC_print_stats) {
        !           236:            GC_err_printf0("The following object has in-degree >= 100:\n");
        !           237:            GC_print_heap_obj(q);
        !           238:          }
        !           239: #      endif
        !           240:     }
        !           241: }
        !           242:
        !           243: typedef void (*per_object_func)(ptr_t p, word n_words, word gc_descr);
        !           244:
        !           245: static void per_object_helper(struct hblk *h, word fn)
        !           246: {
        !           247:   hdr * hhdr = HDR(h);
        !           248:   word sz = hhdr -> hb_sz;
        !           249:   word descr = hhdr -> hb_descr;
        !           250:   per_object_func f = (per_object_func)fn;
        !           251:   int i = 0;
        !           252:
        !           253:   do {
        !           254:     f((ptr_t)(h -> hb_body + i), sz, descr);
        !           255:     i += sz;
        !           256:   } while (i + sz <= BYTES_TO_WORDS(HBLKSIZE));
        !           257: }
        !           258:
        !           259: void GC_apply_to_each_object(per_object_func f)
        !           260: {
        !           261:   GC_apply_to_all_blocks(per_object_helper, (word)f);
        !           262: }
        !           263:
        !           264: static void reset_back_edge(ptr_t p, word n_words, word gc_descr)
        !           265: {
        !           266:   /* Skip any free list links, or dropped blocks */
        !           267:   if (GC_HAS_DEBUG_INFO(p)) {
        !           268:     ptr_t old_back_ptr = GET_OH_BG_PTR(p);
        !           269:     if ((word)old_back_ptr & FLAG_MANY) {
        !           270:       back_edges *be = (back_edges *)((word)old_back_ptr & ~FLAG_MANY);
        !           271:       if (!(be -> flags & RETAIN)) {
        !           272:        deallocate_back_edges(be);
        !           273:         SET_OH_BG_PTR(p, 0);
        !           274:       } else {
        !           275:         word *currentp;
        !           276:
        !           277:        GC_ASSERT(GC_is_marked(p));
        !           278:
        !           279:        /* Back edges may point to objects that will not be retained.   */
        !           280:        /* Delete them for now, but remember the height.                */
        !           281:        /* Some will be added back at next GC.                          */
        !           282:          be -> n_edges = 0;
        !           283:          if (0 != be -> cont) {
        !           284:            deallocate_back_edges(be -> cont);
        !           285:            be -> cont = 0;
        !           286:          }
        !           287:
        !           288:        GC_ASSERT(GC_is_marked(p));
        !           289:
        !           290:        /* We only retain things for one GC cycle at a time.            */
        !           291:          be -> flags &= ~RETAIN;
        !           292:       }
        !           293:     } else /* Simple back pointer */ {
        !           294:       /* Clear to avoid dangling pointer. */
        !           295:       SET_OH_BG_PTR(p, 0);
        !           296:     }
        !           297:   }
        !           298: }
        !           299:
        !           300: static void add_back_edges(ptr_t p, word n_words, word gc_descr)
        !           301: {
        !           302:   word *currentp = (word *)(p + sizeof(oh));
        !           303:
        !           304:   /* For now, fix up non-length descriptors conservatively.    */
        !           305:     if((gc_descr & GC_DS_TAGS) != GC_DS_LENGTH) {
        !           306:       gc_descr = WORDS_TO_BYTES(n_words);
        !           307:     }
        !           308:   while (currentp < (word *)(p + gc_descr)) {
        !           309:     word current = *currentp++;
        !           310:     if (current >= (word)GC_least_plausible_heap_addr &&
        !           311:        current <= (word)GC_greatest_plausible_heap_addr) {
        !           312:        ptr_t target = GC_base((GC_PTR)current);
        !           313:        if (0 != target) {
        !           314:         add_edge(p, target);
        !           315:        }
        !           316:     }
        !           317:   }
        !           318: }
        !           319:
        !           320: /* Rebuild the reprentation of the backward reachability graph.        */
        !           321: /* Does not examine mark bits.  Can be called before GC.       */
        !           322: void GC_build_back_graph(void)
        !           323: {
        !           324:   GC_apply_to_each_object(add_back_edges);
        !           325: }
        !           326:
        !           327: /* Return an approximation to the length of the longest simple path    */
        !           328: /* through unreachable objects to p.  We refer to this as the height   */
        !           329: /* of p.                                                               */
        !           330: static word backwards_height(ptr_t p)
        !           331: {
        !           332:   word result;
        !           333:   ptr_t back_ptr = GET_OH_BG_PTR(p);
        !           334:   back_edges *be;
        !           335:
        !           336:   if (0 == back_ptr) return 1;
        !           337:   if (!((word)back_ptr & FLAG_MANY)) {
        !           338:     if (is_in_progress(p)) return 0;  /* DFS back edge, i.e. we followed  */
        !           339:                                      /* an edge to an object already     */
        !           340:                                      /* on our stack: ignore             */
        !           341:     push_in_progress(p);
        !           342:     result = backwards_height(back_ptr)+1;
        !           343:     pop_in_progress(p);
        !           344:     return result;
        !           345:   }
        !           346:   be = (back_edges *)((word)back_ptr & ~FLAG_MANY);
        !           347:   if (be -> height >= 0 && be -> height_gc_no == GC_gc_no)
        !           348:       return be -> height;
        !           349:   /* Ignore back edges in DFS */
        !           350:     if (be -> height == HEIGHT_IN_PROGRESS) return 0;
        !           351:   result = (be -> height > 0? be -> height : 1);
        !           352:   be -> height = HEIGHT_IN_PROGRESS;
        !           353:   FOR_EACH_PRED(q, p, {
        !           354:     word this_height;
        !           355:     if (GC_is_marked(q) && !(FLAG_MANY & (word)GET_OH_BG_PTR(p))) {
        !           356:       if (GC_print_stats)
        !           357:          GC_printf2("Found bogus pointer from 0x%lx to 0x%lx\n", q, p);
        !           358:        /* Reachable object "points to" unreachable one.                */
        !           359:        /* Could be caused by our lax treatment of GC descriptors.      */
        !           360:       this_height = 1;
        !           361:     } else {
        !           362:         this_height = backwards_height(q);
        !           363:     }
        !           364:     if (this_height >= result) result = this_height + 1;
        !           365:   });
        !           366:   be -> height = result;
        !           367:   be -> height_gc_no = GC_gc_no;
        !           368:   return result;
        !           369: }
        !           370:
        !           371: word GC_max_height;
        !           372: ptr_t GC_deepest_obj;
        !           373:
        !           374: /* Compute the maximum height of every unreachable predecessor p of  a         */
        !           375: /* reachable object.  Arrange to save the heights of all such objects p        */
        !           376: /* so that they can be used in calculating the height of objects in the        */
        !           377: /* next GC.                                                            */
        !           378: /* Set GC_max_height to be the maximum height we encounter, and        */
        !           379: /* GC_deepest_obj to be the corresponding object.                      */
        !           380: static void update_max_height(ptr_t p, word n_words, word gc_descr)
        !           381: {
        !           382:   if (GC_is_marked(p) && GC_HAS_DEBUG_INFO(p)) {
        !           383:     int i;
        !           384:     word p_height = 0;
        !           385:     ptr_t p_deepest_obj = 0;
        !           386:     ptr_t back_ptr;
        !           387:     back_edges *be = 0;
        !           388:
        !           389:     /* If we remembered a height last time, use it as a minimum.       */
        !           390:     /* It may have increased due to newly unreachable chains pointing  */
        !           391:     /* to p, but it can't have decreased.                              */
        !           392:     back_ptr = GET_OH_BG_PTR(p);
        !           393:     if (0 != back_ptr && ((word)back_ptr & FLAG_MANY)) {
        !           394:       be = (back_edges *)((word)back_ptr & ~FLAG_MANY);
        !           395:       if (be -> height != HEIGHT_UNKNOWN) p_height = be -> height;
        !           396:     }
        !           397:     FOR_EACH_PRED(q, p, {
        !           398:       if (!GC_is_marked(q) && GC_HAS_DEBUG_INFO(q)) {
        !           399:         word q_height;
        !           400:
        !           401:         q_height = backwards_height(q);
        !           402:        if (q_height > p_height) {
        !           403:          p_height = q_height;
        !           404:          p_deepest_obj = q;
        !           405:        }
        !           406:       }
        !           407:     });
        !           408:     if (p_height > 0) {
        !           409:       /* Remember the height for next time. */
        !           410:        if (be == 0) {
        !           411:          ensure_struct(p);
        !           412:          back_ptr = GET_OH_BG_PTR(p);
        !           413:          be = (back_edges *)((word)back_ptr & ~FLAG_MANY);
        !           414:        }
        !           415:        be -> flags |= RETAIN;
        !           416:        be -> height = p_height;
        !           417:        be -> height_gc_no = GC_gc_no;
        !           418:     }
        !           419:     if (p_height > GC_max_height) {
        !           420:        GC_max_height = p_height;
        !           421:        GC_deepest_obj = p_deepest_obj;
        !           422:     }
        !           423:   }
        !           424: }
        !           425:
        !           426: void GC_traverse_back_graph(void)
        !           427: {
        !           428:   static word max_max_height = 0;
        !           429:   GC_max_height = 0;
        !           430:   GC_apply_to_each_object(update_max_height);
        !           431:   GC_printf2("Maximum backwards height of reachable objects at GC %lu is %ld\n",
        !           432:             (unsigned long) GC_gc_no, GC_max_height);
        !           433:   if (GC_max_height > max_max_height) {
        !           434:     max_max_height = GC_max_height;
        !           435:     GC_printf0("The following unreachable object is last in a longest chain "
        !           436:               "of unreachable objects:\n");
        !           437:     GC_print_heap_obj(GC_deepest_obj);
        !           438:   }
        !           439:   if (GC_print_stats) {
        !           440:     GC_printf1("Needed max total of %ld back-edge structs\n",
        !           441:               GC_n_back_edge_structs);
        !           442:   }
        !           443:   GC_apply_to_each_object(reset_back_edge);
        !           444:   GC_deepest_obj = 0;
        !           445: }
        !           446:
        !           447: #endif /* MAKE_BACK_GRAPH */

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>