~ chicken-core (chicken-5) e2abe211ab5e719631d1dbc01b0903e61509ed41


commit e2abe211ab5e719631d1dbc01b0903e61509ed41
Author:     felix <felix@call-with-current-continuation.org>
AuthorDate: Wed Jul 7 13:41:18 2010 +0200
Commit:     felix <felix@call-with-current-continuation.org>
CommitDate: Wed Jul 7 13:41:18 2010 +0200

    added runtime routine to dump object counts in heap

diff --git a/chicken.h b/chicken.h
index 0d1f4a66..6f673062 100644
--- a/chicken.h
+++ b/chicken.h
@@ -1692,6 +1692,7 @@ C_fctexport void C_ccall C_cpu_time(C_word c, C_word closure, C_word k) C_noret;
 C_fctexport void C_ccall C_locative_ref(C_word c, C_word closure, C_word k, C_word loc) C_noret;
 C_fctexport void C_ccall C_call_with_cthulhu(C_word c, C_word self, C_word k, C_word proc) C_noret;
 C_fctexport void C_ccall C_copy_closure(C_word c, C_word closure, C_word k, C_word proc) C_noret;
+C_fctexport void C_ccall C_dump_heap_state(C_word x, C_word closure, C_word k) C_noret;
 
 #if !defined(__GNUC__) && !defined(__INTEL_COMPILER)
 C_fctexport C_word *C_a_i(C_word **a, int n);
diff --git a/library.scm b/library.scm
index 094e2eea..32376ae4 100644
--- a/library.scm
+++ b/library.scm
@@ -4671,3 +4671,8 @@ EOF
       (pstr " GCs (major/minor)")))
   (##sys#write-char-0 #\newline ##sys#standard-error)
   (##sys#flush-output ##sys#standard-error))
+
+
+;;; Dump heap state to stderr:
+
+(define ##sys#dump-heap-state (##core#primitive "C_dump_heap_state"))
diff --git a/runtime.c b/runtime.c
index eed675db..00fdecc5 100644
--- a/runtime.c
+++ b/runtime.c
@@ -172,11 +172,10 @@ extern void _C_do_apply_hack(void *proc, C_word *args, int count) C_noret;
 # define FLONUM_PRINT_PRECISION         15
 #endif
 
-#define WORDS_PER_FLONUM              C_SIZEOF_FLONUM
-
+#define WORDS_PER_FLONUM               C_SIZEOF_FLONUM
 #define MAXIMAL_NUMBER_OF_COMMAND_LINE_ARGUMENTS 32
-
 #define INITIAL_TIMER_INTERRUPT_PERIOD 10000
+#define HDUMP_TABLE_SIZE               1001
 
 
 /* Constants: */
@@ -184,12 +183,12 @@ extern void _C_do_apply_hack(void *proc, C_word *args, int count) C_noret;
 #ifdef C_SIXTY_FOUR
 # define ALIGNMENT_HOLE_MARKER         ((C_word)0xfffffffffffffffeL)
 # define FORWARDING_BIT_SHIFT          63
-# define UWORD_FORMAT_STRING           "0x%lx"
+# define UWORD_FORMAT_STRING           "0x%016lx"
 # define UWORD_COUNT_FORMAT_STRING     "%ld"
 #else
 # define ALIGNMENT_HOLE_MARKER         ((C_word)0xfffffffe)
 # define FORWARDING_BIT_SHIFT          31
-# define UWORD_FORMAT_STRING           "0x%x"
+# define UWORD_FORMAT_STRING           "0x%08x"
 # define UWORD_COUNT_FORMAT_STRING     "%d"
 #endif
 
@@ -304,6 +303,13 @@ typedef struct trace_info_struct
   C_word cooked1, cooked2, thread;
 } TRACE_INFO;
 
+typedef struct hdump_bucket_struct
+{
+  C_word key;
+  int count, total;
+  struct hdump_bucket_struct *next;
+} HDUMP_BUCKET;
+
 
 /* Variables: */
 
@@ -447,6 +453,8 @@ static C_TLS FINALIZER_NODE
   **pending_finalizer_indices;
 static C_TLS void *current_module_handle;
 static C_TLS int flonum_print_precision = FLONUM_PRINT_PRECISION;
+static C_TLS HDUMP_BUCKET **hdump_table;
+
 
 /* Prototypes: */
 
@@ -491,6 +499,7 @@ static void callback_trampoline(void *dummy) C_noret;
 static C_ccall void callback_return_continuation(C_word c, C_word self, C_word r) C_noret;
 static void become_2(void *dummy) C_noret;
 static void copy_closure_2(void *dummy) C_noret;
+static void dump_heap_state_2(void *dummy) C_noret;
 
 static C_PTABLE_ENTRY *create_initial_ptable();
 
@@ -3084,8 +3093,12 @@ C_regparm void C_fcall C_rereclaim2(C_uword size, int double_plus)
 	  (C_uword)heap_size / 1000, size / 1000);
 
   if(gc_report_flag) {
-    C_dbg(C_text("GC"), C_text("(old) fromspace: \tstart=%08lx, \tlimit=%08lx\n"), (long)fromspace_start, (long)C_fromspace_limit);
-    C_dbg(C_text("GC"), C_text("(old) tospace:   \tstart=%08lx, \tlimit=%08lx\n"), (long)tospace_start, (long)tospace_limit);
+    C_dbg(C_text("GC"), C_text("(old) fromspace: \tstart=" UWORD_FORMAT_STRING 
+			       ", \tlimit=" UWORD_FORMAT_STRING "\n"),
+	  (long)fromspace_start, (long)C_fromspace_limit);
+    C_dbg(C_text("GC"), C_text("(old) tospace:   \tstart=" UWORD_FORMAT_STRING
+			       ", \tlimit=" UWORD_FORMAT_STRING "\n"),
+	  (long)tospace_start, (long)tospace_limit);
   }
 
   heap_size = size;
@@ -3198,8 +3211,12 @@ C_regparm void C_fcall C_rereclaim2(C_uword size, int double_plus)
 
   if(gc_report_flag) {
     C_dbg(C_text("GC"), C_text("resized heap to %d bytes\n"), heap_size);
-    C_dbg(C_text("GC"), C_text("(new) fromspace: \tstart=%08lx, \tlimit=%08lx\n"), (long)fromspace_start, (long)C_fromspace_limit);
-    C_dbg(C_text("GC"), C_text("(new) tospace:   \tstart=%08lx, \tlimit=%08lx\n"), (long)tospace_start, (long)tospace_limit);
+    C_dbg(C_text("GC"), C_text("(new) fromspace: \tstart=" UWORD_FORMAT_STRING 
+			       ", \tlimit=" UWORD_FORMAT_STRING "\n"),
+	  (long)fromspace_start, (long)C_fromspace_limit);
+    C_dbg(C_text("GC"), C_text("(new) tospace:   \tstart=" UWORD_FORMAT_STRING
+			       ", \tlimit=" UWORD_FORMAT_STRING "\n"),
+	  (long)tospace_start, (long)tospace_limit);
   }
 
   if(C_post_gc_hook != NULL) C_post_gc_hook(GC_REALLOC, 0);
@@ -8773,3 +8790,170 @@ C_i_get_keyword(C_word kw, C_word args, C_word def)
 
   return def;
 }
+
+
+void C_ccall
+C_dump_heap_state(C_word c, C_word closure, C_word k)
+{
+  /* make sure heap is compacted */
+  C_save(k);
+  C_reclaim(dump_heap_state_2, NULL);
+}
+
+
+static unsigned long
+hdump_hash(C_word key)
+{
+  return (unsigned long)key % HDUMP_TABLE_SIZE;
+}
+
+
+static void
+hdump_count(C_word key, int n, int t)
+{
+  HDUMP_BUCKET **bp = hdump_table + hdump_hash(key);
+  HDUMP_BUCKET *b = *bp;
+
+  while(b != NULL) {
+    if(b->key == key) {
+      b->count += n;
+      b->total += t;
+      return;
+    }
+    else b = b->next;
+  }
+
+  b = (HDUMP_BUCKET *)C_malloc(sizeof(HDUMP_BUCKET));
+  
+  if(b == 0)
+    panic(C_text("out of memory - can not allocate heap-dump table-bucket"));
+
+  b->next = *bp;
+  b->key = key;
+  *bp = b;
+  b->count = n;
+  b->total = t;
+}
+
+
+static void 
+dump_heap_state_2(void *dummy)
+{
+  C_word k = C_restore;
+  HDUMP_BUCKET *b, *b2, **bp;
+  int n, bytes;
+  C_byte *scan;
+  C_SCHEME_BLOCK *sbp;
+  C_header h;
+  C_word x, key, *p;
+  int imm = 0, blk = 0;
+  
+  hdump_table = (HDUMP_BUCKET **)C_malloc(HDUMP_TABLE_SIZE * sizeof(HDUMP_BUCKET *));
+
+  if(hdump_table == NULL)
+    panic(C_text("out of memory - can not allocate heap-dump table"));
+
+  C_memset(hdump_table, 0, sizeof(HDUMP_BUCKET *) * HDUMP_TABLE_SIZE);
+
+  scan = fromspace_start;
+
+  while(scan < C_fromspace_top) {
+    ++blk;
+    sbp = (C_SCHEME_BLOCK *)scan;
+
+    if(*((C_word *)sbp) == ALIGNMENT_HOLE_MARKER) 
+      sbp = (C_SCHEME_BLOCK *)((C_word *)sbp + 1);
+
+    n = C_header_size(sbp);
+    h = sbp->header;
+    bytes = (h & C_BYTEBLOCK_BIT) ? n : n * sizeof(C_word);
+    key = (C_word)(h & C_HEADER_BITS_MASK);
+    p = sbp->data;
+
+    if(key == C_STRUCTURE_TYPE) key = *p;
+
+    hdump_count(key, 1, bytes);
+
+    if(n > 0 && (h & C_BYTEBLOCK_BIT) == 0) {
+      if((h & C_SPECIALBLOCK_BIT) != 0) {
+	--n;
+	++p;
+      }
+
+      while(n--) {
+	x = *(p++);
+
+	if(C_immediatep(x)) {
+	  ++imm;
+
+	  if((x & C_FIXNUM_BIT) != 0) key = C_fix(1);
+	  else {
+	    switch(x & C_IMMEDIATE_TYPE_BITS) {
+	    case C_BOOLEAN_BITS: key = C_SCHEME_TRUE; break;
+	    case C_CHARACTER_BITS: key = C_make_character('A'); break;
+	    default: key = x;
+	    }
+	  }
+
+	  hdump_count(key, 1, 0);
+	}
+      }
+    }
+
+    scan = (C_byte *)sbp + C_align(bytes) + sizeof(C_word);
+  }
+
+  bp = hdump_table;
+  
+  for(n = 0; n < HDUMP_TABLE_SIZE; ++n) {
+    for(b = bp[ n ]; b != NULL; b = b2) {
+      b2 = b->next;
+
+      switch(b->key) {
+      case C_fix(1): C_fprintf(C_stderr,              C_text("fixnum         ")); break;
+      case C_SCHEME_TRUE: C_fprintf(C_stderr,         C_text("boolean        ")); break;
+      case C_SCHEME_END_OF_LIST: C_fprintf(C_stderr,  C_text("null           ")); break;
+      case C_SCHEME_UNDEFINED  : C_fprintf(C_stderr,  C_text("void           ")); break;
+      case C_make_character('A'): C_fprintf(C_stderr, C_text("character      ")); break;
+      case C_SCHEME_END_OF_FILE: C_fprintf(C_stderr,  C_text("eof            ")); break;
+      case C_SCHEME_UNBOUND: C_fprintf(C_stderr,      C_text("unbound        ")); break;
+      case C_SYMBOL_TYPE: C_fprintf(C_stderr,         C_text("symbol         ")); break;
+      case C_STRING_TYPE: C_fprintf(C_stderr,         C_text("string         ")); break;
+      case C_PAIR_TYPE: C_fprintf(C_stderr,           C_text("pair           ")); break;
+      case C_CLOSURE_TYPE: C_fprintf(C_stderr,        C_text("closure        ")); break;
+      case C_FLONUM_TYPE: C_fprintf(C_stderr,         C_text("flonum         ")); break;
+      case C_PORT_TYPE: C_fprintf(C_stderr,           C_text("port           ")); break;
+      case C_POINTER_TYPE: C_fprintf(C_stderr,        C_text("pointer        ")); break;
+      case C_LOCATIVE_TYPE: C_fprintf(C_stderr,       C_text("locative       ")); break;
+      case C_TAGGED_POINTER_TYPE: C_fprintf(C_stderr, C_text("tagged pointer ")); break;
+      case C_SWIG_POINTER_TYPE: C_fprintf(C_stderr,   C_text("swig pointer   ")); break;
+      case C_LAMBDA_INFO_TYPE: C_fprintf(C_stderr,    C_text("lambda info    ")); break;
+      case C_BUCKET_TYPE: C_fprintf(C_stderr,         C_text("bucket         ")); break;
+      case C_VECTOR_TYPE: C_fprintf(C_stderr,         C_text("vector         ")); break;
+      case C_BYTEVECTOR_TYPE: C_fprintf(C_stderr,     C_text("bytevector     ")); break;
+      default:
+	x = b->key;
+
+	if(!C_immediatep(x) && C_header_bits(x) == C_SYMBOL_TYPE) {
+	  x = C_block_item(x, 1);
+	  C_fprintf(C_stderr, C_text("`%.*s'"), C_header_size(x), C_c_string(x));
+	}
+	else C_fprintf(C_stderr, C_text("unknown key " UWORD_FORMAT_STRING), b->key);
+      }
+
+      C_fprintf(C_stderr, C_text("\t" UWORD_COUNT_FORMAT_STRING), b->count);
+
+      if(b->total > 0) 
+	C_fprintf(C_stderr, C_text("\t" UWORD_COUNT_FORMAT_STRING " bytes"), b->total);
+
+      C_fputc('\n', C_stderr);
+      C_free(b);
+    }
+  }
+
+  C_fprintf(C_stderr, C_text("\ntotal number of blocks: " UWORD_COUNT_FORMAT_STRING
+			     ", immediates: " UWORD_COUNT_FORMAT_STRING "\n"),
+	    blk, imm);
+  C_free(hdump_table);
+  C_kontinue(k, C_SCHEME_UNDEFINED);
+}
Trap