pike.git / src / gc.c

version» Context lines:

pike.git/src/gc.c:23:   #include "constants.h"   #include "interpret.h"   #include "bignum.h"      #include "gc.h"   #include "main.h"   #include <math.h>      #include "block_alloc.h"    - RCSID("$Id: gc.c,v 1.164 2001/07/01 23:44:40 mast Exp $"); + RCSID("$Id: gc.c,v 1.165 2001/07/02 01:02:56 mast Exp $");      /* Run garbage collect approximately every time    * 20 percent of all arrays, objects and programs is    * garbage.    */      #define GC_CONST 20   #define MIN_ALLOC_THRESHOLD 1000   #define MAX_ALLOC_THRESHOLD 10000000   #define MULTIPLIER 0.9   #define MARKER_CHUNK_SIZE 1023 - #define GC_LINK_CHUNK_SIZE 31 + #define GC_LINK_CHUNK_SIZE 63      /* The gc will free all things with no external references that isn't    * referenced by undestructed objects with destroy() lfuns (known as    * "live" objects). Live objects without external references are then    * destructed and garbage collected with normal refcount garbing    * (which might leave dead garbage around for the next gc). These live    * objects are destructed in an order that tries to be as well defined    * as possible using several rules:    *    * o If an object A references B single way, then A is destructed
pike.git/src/gc.c:227: Inside #if defined(PIKE_DEBUG)
     #ifdef PIKE_DEBUG      #undef get_marker   #define get_marker(X) ((struct marker *) debug_malloc_pass(debug_get_marker(X)))   #undef find_marker   #define find_marker(X) ((struct marker *) debug_malloc_pass(debug_find_marker(X)))      int gc_in_cycle_check = 0;   static unsigned delayed_freed, weak_freed, checked, marked, cycle_checked, live_ref; - static unsigned max_gc_frames, num_gc_frames = 0; + static unsigned max_gc_frames, num_gc_frames = 0, live_rec, frame_rot;   static unsigned gc_extra_refs = 0;    -  + static unsigned max_tot_gc_frames = 0; + static unsigned tot_cycle_checked = 0, tot_live_rec = 0, tot_frame_rot = 0; +    void dump_gc_info(void)   {    fprintf(stderr,"Current number of objects: %d\n",num_objects);    fprintf(stderr,"Objects allocated total : %d\n",num_allocs);    fprintf(stderr," threshold for next gc() : %"PRINTPTRDIFFT"d\n",alloc_threshold);    fprintf(stderr,"Average allocs per gc() : %f\n",objects_alloced);    fprintf(stderr,"Average frees per gc() : %f\n",objects_freed);    fprintf(stderr,"Second since last gc() : %ld\n",    DO_NOT_WARN((long)TIME(0) - (long)last_gc));    fprintf(stderr,"Projected garbage : %f\n", objects_freed * (double) num_allocs / (double) alloc_threshold); -  +  fprintf(stderr,"Max used gc frames : %u\n", max_tot_gc_frames); +  fprintf(stderr,"Live recursed ratio : %g\n", (double) tot_live_rec / tot_cycle_checked); +  fprintf(stderr,"Frame rotation ratio : %g\n", (double) tot_frame_rot / tot_cycle_checked);    fprintf(stderr,"in_gc : %d\n", Pike_in_gc);   }      TYPE_T attempt_to_identify(void *something)   {    struct array *a;    struct object *o;    struct program *p;    struct mapping *m;    struct multiset *mu;
pike.git/src/gc.c:1590:    else beg = l; /* Keep the cycle continuous. */    }       CYCLE_DEBUG_MSG(find_marker(beg->data), "> rotate_rec_list, begin at");       {    struct gc_frame *b = beg, *p = pos, *old_rec_top;    while (b->frameflags & GC_OFF_STACK) {    if ((b = NEXT(b)) == pos) goto done;    CHECK_POP_FRAME(b); +  DO_IF_DEBUG(frame_rot++);    }    while (p->frameflags & GC_OFF_STACK) {    if (!(p = NEXT(p))) goto done;    CHECK_POP_FRAME(p); -  +  DO_IF_DEBUG(frame_rot++);    }    old_rec_top = gc_rec_top;    gc_rec_top = p->back;    p->back = b->back;    b->back = old_rec_top;    }   done: -  +  DO_IF_DEBUG(frame_rot++);       {    struct gc_frame *new_rec_last = PREV(pos);    NEXT(PREV(beg)) = pos;    PREV(pos) = PREV(beg);    NEXT(gc_rec_last) = beg;    PREV(beg) = gc_rec_last;    gc_rec_last = new_rec_last;    NEXT(gc_rec_last) = 0;    }
pike.git/src/gc.c:1896:    {    /* Recurse without linking onto rec_list. */    struct gc_frame *l = gc_cycle_enqueue_pop(x);   #ifdef GC_CYCLE_DEBUG    CYCLE_DEBUG_MSG(m, "gc_cycle_push, live recurse");    gc_cycle_indent += 2;   #endif    gc_rec_last = l;    }    + #ifdef PIKE_DEBUG +  live_rec++; + #endif    return 1;   }      static void gc_cycle_pop(void *a)   {    struct marker *m = find_marker(a);    struct gc_frame *here, *base, *p;      #ifdef PIKE_DEBUG    if (!a) fatal("Got null pointer.\n");
pike.git/src/gc.c:2160:    objects_alloced*=multiplier;    objects_alloced += (double) num_allocs;       objects_freed*=multiplier;       /* Thread switches, object alloc/free and any reference changes are    * disallowed now. */      #ifdef PIKE_DEBUG    delayed_freed = weak_freed = checked = marked = cycle_checked = live_ref = 0; +  live_rec = frame_rot = 0;    if (gc_debug) {    unsigned n;    Pike_in_gc = GC_PASS_PRETOUCH;    n = gc_touch_all_arrays();    n += gc_touch_all_multisets();    n += gc_touch_all_mappings();    n += gc_touch_all_programs();    n += gc_touch_all_objects();    gc_touch_all_strings();    if (n != (unsigned) num_objects)
pike.git/src/gc.c:2272: Inside #if defined(PIKE_DEBUG)
   fatal("Recurse list not empty or inconsistent after cycle check pass.\n");    if (gc_ext_weak_refs != orig_ext_weak_refs)    fatal("gc_ext_weak_refs changed from %"PRINTSIZET"u "    "to %"PRINTSIZET"u in cycle check pass.\n",    orig_ext_weak_refs, gc_ext_weak_refs);   #endif       GC_VERBOSE_DO(fprintf(stderr,    "| cycle: %u internal things visited, %u cycle ids used,\n"    "| %u weak references freed, %d more things to free,\n" +  "| %u live recursed frames, %u frame rotations,\n"    "| space for %u gc frames used\n",    cycle_checked, last_cycle, weak_freed, -  delayed_freed - obj_count, max_gc_frames)); +  delayed_freed - obj_count, +  live_rec, frame_rot, max_gc_frames));    }       if (gc_ext_weak_refs) {    size_t to_free = gc_ext_weak_refs;   #ifdef PIKE_DEBUG    obj_count = delayed_freed;   #endif    Pike_in_gc = GC_PASS_ZAP_WEAK;    /* Zap weak references from external to internal things. That    * doesn't occur very often; only when something have both
pike.git/src/gc.c:2505: Inside #if defined(PIKE_DEBUG) and #if defined(HAVE_GETHRTIME)
  #ifdef HAVE_GETHRTIME    fprintf(stderr,    "done (freed %"PRINTPTRDIFFT"d of %"PRINTPTRDIFFT"d things), %ld ms.\n",    objs, objs + num_objects, (long)((gethrtime() - gcstarttime)/1000000));   #else    fprintf(stderr,    "done (freed %"PRINTPTRDIFFT"d of %"PRINTPTRDIFFT"d things)\n",    objs, objs + num_objects);   #endif    } +  if (max_gc_frames > max_tot_gc_frames) max_tot_gc_frames = max_gc_frames; +  tot_cycle_checked += cycle_checked; +  tot_live_rec += live_rec, tot_frame_rot += frame_rot;   #endif      #ifdef ALWAYS_GC    ADD_GC_CALLBACK();   #else    if(d_flag > 3) ADD_GC_CALLBACK();   #endif       return objs;   }
pike.git/src/gc.c:2544:    *! Time when the garbage-collector last ran.    *! @member float "projected_garbage"    *! Heuristic for the amount of garbage in the system.    *! @endmapping    *!    *! @seealso    *! @[gc()]    */   void f__gc_status(INT32 args)   { +  int size = 0; +     pop_n_elems(args);       push_constant_text("num_objects");    push_int(num_objects); -  +  size++;       push_constant_text("num_allocs");    push_int(num_allocs); -  +  size++;       push_constant_text("alloc_threshold");    push_int64(alloc_threshold); -  +  size++;       push_constant_text("objects_alloced");    push_int64(objects_alloced); -  +  size++;       push_constant_text("objects_freed");    push_int64(objects_freed); -  +  size++;       push_constant_text("last_gc");    push_int64(last_gc); -  +  size++;       push_constant_text("projected_garbage");    push_float(objects_freed * (double) num_allocs / (double) alloc_threshold); -  +  size++;    -  f_aggregate_mapping(14); +  f_aggregate_mapping(size * 2);   }      void cleanup_gc(void)   {   #ifdef PIKE_DEBUG    if (gc_evaluator_callback) {    remove_callback(gc_evaluator_callback);    gc_evaluator_callback = NULL;    }   #endif /* PIKE_DEBUG */   }