conv-core/memory-charmdebug.c

Go to the documentation of this file.
00001 /*
00002  * Filippo's charm debug memory module, gioachin@uiuc.edu, 2005/10
00003  * based on Orion's memory-leak.c
00004  *
00005  * This special version of malloc() and company is meant to be used in
00006  * conjunction with the parallel debugger CharmDebug.
00007  *
00008  * Functionalities provided:
00009  * - detect multiple delete on a pointer
00010  * - stacktrace for all memory allocated
00011  * - division of the memory in differnt types of allocations
00012  * - sweep of the memory searching for leaks
00013  */
00014 
00015 #if ! CMK_MEMORY_BUILD_OS
00016 /* Use Gnumalloc as meta-meta malloc fallbacks (mm_*) */
00017 #include "memory-gnu.c"
00018 #endif
00019 #include "tracec.h"
00020 #include <sys/mman.h>
00021 
00022 /* Utilities needed by the code */
00023 #include "ckhashtable.h"
00024 
00025 /*#include "pup_c.h" */
00026 
00027 #include "crc32.h"
00028 
00029 typedef struct _Slot Slot;
00030 typedef struct _SlotStack SlotStack;
00031 
00032 int nextChareID;
00033 extern int memory_chare_id;
00034 
00039 struct _Slot {
00040   /*Doubly-linked allocated block list*/
00041   Slot *next;
00042   Slot *prev;
00043         
00044   /*The number of bytes of user data*/
00045   int userSize;
00046 
00047 #define FLAGS_MASK        0xF
00048 #define LEAK_FLAG         0x8
00049 #define UNKNOWN_TYPE      0x0
00050 #define SYSTEM_TYPE       0x1
00051 #define USER_TYPE         0x2
00052 #define CHARE_TYPE        0x3
00053 #define MESSAGE_TYPE      0x4
00054   /* A magic number field, to verify this is an actual malloc'd buffer, and what
00055      type of allocation it is. The last 4 bits of the magic number are used to
00056      define a classification of mallocs. */
00057 #define SLOTMAGIC            0x8402a5e0
00058 #define SLOTMAGIC_VALLOC     0x7402a5e0
00059 #define SLOTMAGIC_FREED      0xDEADBEEF
00060   int magic;
00061 
00062   int chareID;
00063   /* Controls the number of stack frames to print out. Should be always odd, so
00064      the total size of this struct becomes multiple of 8 bytes everywhere */
00065 //#define STACK_LEN 15
00066   int stackLen;
00067   void **from;
00068 
00069   /* Pointer to extra stacktrace, when the user requested more trace */
00070   SlotStack *extraStack;
00071 
00072   /* CRC32 checksums */
00073   unsigned int slotCRC;
00074   unsigned int userCRC;
00075 };
00076 
00077 struct _SlotStack {
00078   char *protectedMemory;
00079   int protectedMemoryLength;
00080   /* empty for the moment, to be filled when needed */
00081 };
00082 
00083 /*Convert a slot to a user address*/
00084 static char *SlotToUser(Slot *s) {
00085   return ((char *)s)+sizeof(Slot);
00086 }
00087 
00088 
00089 /*Convert a user address to a slot*/
00090 static Slot *UserToSlot(void *user) {
00091   char *cu=(char *)user;
00092   Slot *s=(Slot *)(cu-sizeof(Slot));
00093   return s;
00094 }
00095 
00096 static int isLeakSlot(Slot *s) {
00097   return s->magic & LEAK_FLAG;
00098 }
00099 
00100 static void printSlot(Slot *s) {
00101   CmiPrintf("[%d] Leaked block of %d bytes at %p:\n",
00102             CmiMyPe(), s->userSize, SlotToUser(s));
00103   CmiBacktracePrint(s->from,s->stackLen);
00104 }
00105 
00106 /********* Circural list of allocated memory *********/
00107 
00108 /* First memory slot */
00109 Slot slot_first_storage = {&slot_first_storage, &slot_first_storage};
00110 Slot *slot_first = &slot_first_storage;
00111 
00112 int memory_allocated_user_total;
00113 int get_memory_allocated_user_total() {return memory_allocated_user_total;}
00114 
00115 /********* Cpd routines for pupping data to the debugger *********/
00116 
00117 int cpd_memory_length(void *lenParam) {
00118   int n=0;
00119   Slot *cur = slot_first->next;
00120   while (cur != slot_first) {
00121     n++;
00122     cur = cur->next;
00123   }
00124   return n;
00125 }
00126 
00127 void cpd_memory_single_pup(Slot* list, pup_er p) {
00128   Slot *cur = list->next;
00129   /* Stupid hack to avoid sending the memory we just allocated for this packing,
00130      otherwise the lenghts will mismatch */
00131   if (pup_isPacking(p)) cur = cur->next;
00132   while (cur != list) {
00133     int i;
00134     int flags;
00135     void *loc = (void*)(cur+1);
00136     CpdListBeginItem(p, 0);
00137     pup_comment(p, "loc");
00138     pup_pointer(p, &loc);
00139     pup_comment(p, "size");
00140     pup_int(p, &cur->userSize);
00141     pup_comment(p, "flags");
00142     flags = cur->magic & FLAGS_MASK;
00143     pup_int(p, &flags);
00144     pup_comment(p, "chare");
00145     pup_int(p, &cur->chareID);
00146     pup_comment(p, "stack");
00147     //for (i=0; i<STACK_LEN; ++i) {
00148     //  if (cur->from[i] <= 0) break;
00149       //      if (cur->from[i] > 0) pup_uint(p, (unsigned int*)&cur->from[i]);
00150       //      else break;
00151     //}
00152     pup_pointers(p, cur->from, cur->stackLen);
00153     cur = cur->next;
00154   }
00155 }
00156 
00157 void cpd_memory_pup(void *itemParam, pup_er p, CpdListItemsRequest *req) {
00158   CpdListBeginItem(p, 0);
00159   pup_comment(p, "name");
00160   pup_chars(p, "memory", strlen("memory"));
00161   pup_comment(p, "slots");
00162   pup_syncComment(p, pup_sync_begin_array, 0);
00163   cpd_memory_single_pup(slot_first, p);
00164   pup_syncComment(p, pup_sync_end_array, 0);
00165 }
00166 
00167 void check_memory_leaks(CpdListItemsRequest *);
00168 void cpd_memory_leak(void *iterParam, pup_er p, CpdListItemsRequest *req) {
00169   if (pup_isSizing(p)) {
00170     // let's perform the memory leak checking. This is the first step in the
00171     // packing, where we size, in the second step we pack and we avoid doing
00172     // this check again.
00173     check_memory_leaks(req);
00174   }
00175   cpd_memory_pup(iterParam, p, req);
00176 }
00177 
00178 int cpd_memory_getLength(void *lenParam) { return 1; }
00179 void cpd_memory_get(void *iterParam, pup_er p, CpdListItemsRequest *req) {
00180   void *userData = (void*)(((unsigned int)req->lo) + (((unsigned long)req->hi)<<32));
00181   Slot *sl = ((Slot*)userData)-1;
00182   CpdListBeginItem(p, 0);
00183   pup_comment(p, "size");
00184   //printf("value: %x %x %x %d\n",sl->magic, sl->magic&~FLAGS_MASK, SLOTMAGIC, ((sl->magic&~FLAGS_MASK) != SLOTMAGIC));
00185   if ((sl->magic&~FLAGS_MASK) != SLOTMAGIC) {
00186     int zero = 0;
00187     pup_int(p, &zero);
00188   } else {
00189     pup_int(p, &sl->userSize);
00190     pup_comment(p, "value");
00191     pup_bytes(p, userData, sl->userSize);
00192   }
00193 }
00194 
00195 /********* Heap Checking ***********/
00196 
00197 int charmEnvelopeSize = 0;
00198 
00199 // FIXME: this function assumes that all memory is allocated in slot_unknown!
00200 void check_memory_leaks(CpdListItemsRequest *req) {
00201   FILE* fd=fopen("check_memory_leaks", "w");
00202   // Step 1)
00203   // index all memory into a CkHashtable, with a scan of 4 bytes.
00204   CkHashtable_c table;
00205   Slot leaking, inProgress;
00206   Slot *sl, **fnd, *found;
00207   char *scanner;
00208   char *begin_stack, *end_stack;
00209   char *begin_data, *end_data;
00210   char *begin_bss, *end_bss;
00211   int growing_dimension = 0;
00212 
00213   // copy all the memory from "slot_first" to "leaking"
00214   slot_first->next->prev = &leaking;
00215   slot_first->prev->next = &leaking;
00216   leaking.prev = slot_first->prev;
00217   leaking.next = slot_first->next;
00218   slot_first->next = slot_first;
00219   slot_first->prev = slot_first;
00220 
00221   table = CkCreateHashtable_pointer(sizeof(char *), 10000);
00222   for (sl = leaking.next; sl != &leaking; sl = sl->next) {
00223     // index the i-th memory slot
00224     char *ptr;
00225     sl->magic |= LEAK_FLAG;
00226     if (req->lo > 0) {
00227       //CmiPrintf("checking memory fast\n");
00228       // means index only specific offsets of the memory region
00229       ptr = ((char*)sl)+sizeof(Slot);
00230       char **object = (char**)CkHashtablePut(table, &ptr);
00231       *object = (char*)sl;
00232       ptr += 4;
00233       object = (char**)CkHashtablePut(table, &ptr);
00234       *object = (char*)sl;
00235       // beginning of converse header
00236       ptr += sizeof(CmiChunkHeader) - 4;
00237       if (ptr < ((char*)sl)+2*sizeof(Slot)+sl->userSize) {
00238         object = (char**)CkHashtablePut(table, &ptr);
00239         *object = (char*)sl;
00240       }
00241       // beginning of charm header
00242       ptr += CmiReservedHeaderSize;
00243       if (ptr < ((char*)sl)+2*sizeof(Slot)+sl->userSize) {
00244         object = (char**)CkHashtablePut(table, &ptr);
00245         *object = (char*)sl;
00246       }
00247       // beginning of ampi header
00248       ptr += charmEnvelopeSize - CmiReservedHeaderSize;
00249       if (ptr < ((char*)sl)+2*sizeof(Slot)+sl->userSize) {
00250         object = (char**)CkHashtablePut(table, &ptr);
00251         *object = (char*)sl;
00252       }
00253     } else {
00254       //CmiPrintf("checking memory extensively\n");
00255       // means index every fourth byte of the memory region
00256       for (ptr = ((char*)sl)+sizeof(Slot); ptr < ((char*)sl)+sizeof(Slot)+sl->userSize; ptr+=sizeof(char*)) {
00257         //printf("memory %p\n",ptr);
00258         //growing_dimension++;
00259         //if ((growing_dimension&0xFF) == 0) printf("inserted %d objects\n",growing_dimension);
00260         char **object = (char**)CkHashtablePut(table, &ptr);
00261         *object = (char*)sl;
00262       }
00263     }
00264   }
00265 
00266   // Step 2)
00267   // start the check with the stack and the global data. The stack is found
00268   // through the current pointer, going up until 16 bits filling (considering
00269   // the stack grows toward decreasing addresses). The pointers to the global
00270   // data (segments .data and .bss) are passed in with "req" as the "extra"
00271   // field, with the structure "begin .data", "end .data", "begin .bss", "end .bss".
00272   inProgress.prev = &inProgress;
00273   inProgress.next = &inProgress;
00274   begin_stack = (char*)&table;
00275   end_stack = (char*)memory_stack_top;
00276   if (req->extraLen != 4*4/*sizeof(char*) FIXME: assumes 64 bit addresses of .data and .bss are small enough*/) {
00277     CmiPrintf("requested for a memory leak check with wrong information! %d bytes\n",req->extraLen);
00278   }
00279   //if (sizeof(char*) == 4) {
00280     /* 32 bit addresses; for 64 bit machines it assumes the following addresses were small enough */
00281     begin_data = (char*)ntohl(((int*)(req->extra))[0]);
00282     end_data = (char*)ntohl(((int*)(req->extra))[1]) - sizeof(char*) + 1;
00283     begin_bss = (char*)ntohl(((int*)(req->extra))[2]);
00284     end_bss = (char*)ntohl(((int*)(req->extra))[3]) - sizeof(char*) + 1;
00285   /*} else {
00286     CmiAbort("not ready yet");
00287     begin_data = ntohl(((char**)(req->extra))[0]);
00288     end_data = ntohl(((char**)(req->extra))[1]) - sizeof(char*) + 1;
00289     begin_bss = ntohl(((char**)(req->extra))[2]);
00290     end_bss = ntohl(((char**)(req->extra))[3]) - sizeof(char*) + 1;
00291   }*/
00292   printf("scanning stack from %p (%d) to %p (%d)\n",begin_stack,begin_stack,end_stack,end_stack);
00293   for (scanner = begin_stack; scanner < end_stack; scanner+=sizeof(char*)) {
00294     fnd = (Slot**)CkHashtableGet(table, scanner);
00295     //if (fnd != NULL) printf("scanning stack %p, %d\n",*fnd,isLeakSlot(*fnd));
00296     if (fnd != NULL && isLeakSlot(*fnd)) {
00297       found = *fnd;
00298       /* mark slot as not leak */
00299       //printf("stack pointing to %p\n",found+1);
00300       found->magic &= ~LEAK_FLAG;
00301       /* move the slot a inProgress */
00302       found->next->prev = found->prev;
00303       found->prev->next = found->next;
00304       found->next = inProgress.next;
00305       found->prev = &inProgress;
00306       found->next->prev = found;
00307       found->prev->next = found;
00308     }
00309   }
00310   printf("scanning data from %p (%d) to %p (%d)\n",begin_data,begin_data,end_data,end_data);
00311   for (scanner = begin_data; scanner < end_data; scanner+=sizeof(char*)) {
00312     //fprintf(fd, "scanner = %p\n",scanner);
00313     fflush(fd);
00314     fnd = (Slot**)CkHashtableGet(table, scanner);
00315     //if (fnd != NULL) printf("scanning data %p, %d\n",*fnd,isLeakSlot(*fnd));
00316     if (fnd != NULL && isLeakSlot(*fnd)) {
00317       found = *fnd;
00318       /* mark slot as not leak */
00319       //printf("data pointing to %p\n",found+1);
00320       found->magic &= ~LEAK_FLAG;
00321       /* move the slot a inProgress */
00322       found->next->prev = found->prev;
00323       found->prev->next = found->next;
00324       found->next = inProgress.next;
00325       found->prev = &inProgress;
00326       found->next->prev = found;
00327       found->prev->next = found;
00328     }
00329   }
00330   printf("scanning bss from %p (%d) to %p (%d)\n",begin_bss,begin_bss,end_bss,end_bss);
00331   for (scanner = begin_bss; scanner < end_bss; scanner+=sizeof(char*)) {
00332     //printf("bss: %p %p\n",scanner,*(char**)scanner);
00333     fnd = (Slot**)CkHashtableGet(table, scanner);
00334     //if (fnd != NULL) printf("scanning bss %p, %d\n",*fnd,isLeakSlot(*fnd));
00335     if (fnd != NULL && isLeakSlot(*fnd)) {
00336       found = *fnd;
00337       /* mark slot as not leak */
00338       //printf("bss pointing to %p\n",found+1);
00339       found->magic &= ~LEAK_FLAG;
00340       /* move the slot a inProgress */
00341       found->next->prev = found->prev;
00342       found->prev->next = found->next;
00343       found->next = inProgress.next;
00344       found->prev = &inProgress;
00345       found->next->prev = found;
00346       found->prev->next = found;
00347     }
00348   }
00349 
00350   // Step 3)
00351   // continue iteratively to check the memory by sweeping it with the
00352   // "inProcess" list
00353   while (inProgress.next != &inProgress) {
00354     sl = inProgress.next;
00355     printf("scanning memory %p of size %d\n",sl,sl->userSize);
00356     /* move slot back to the main list (slot_first) */
00357     sl->next->prev = sl->prev;
00358     sl->prev->next = sl->next;
00359     sl->next = slot_first->next;
00360     sl->prev = slot_first;
00361     sl->next->prev = sl;
00362     sl->prev->next = sl;
00363     /* scan through this memory and pick all the slots which are still leaking
00364        and add them to the inProgress list */
00365     if (sl->extraStack != NULL && sl->extraStack->protectedMemory != NULL) mprotect(sl->extraStack->protectedMemory, sl->extraStack->protectedMemoryLength, PROT_READ);
00366     for (scanner = ((char*)sl)+sizeof(Slot); scanner < ((char*)sl)+sizeof(Slot)+sl->userSize-sizeof(char*)+1; scanner+=sizeof(char*)) {
00367       fnd = (Slot**)CkHashtableGet(table, scanner);
00368       //if (fnd != NULL) printf("scanning heap %p, %d\n",*fnd,isLeakSlot(*fnd));
00369       if (fnd != NULL && isLeakSlot(*fnd)) {
00370         found = *fnd;
00371         /* mark slot as not leak */
00372         //printf("heap pointing to %p\n",found+1);
00373         found->magic &= ~LEAK_FLAG;
00374         /* move the slot a inProgress */
00375         found->next->prev = found->prev;
00376         found->prev->next = found->next;
00377         found->next = inProgress.next;
00378         found->prev = &inProgress;
00379         found->next->prev = found;
00380         found->prev->next = found;
00381       }
00382     }
00383     if (sl->extraStack != NULL && sl->extraStack->protectedMemory != NULL) mprotect(sl->extraStack->protectedMemory, sl->extraStack->protectedMemoryLength, PROT_NONE);
00384   }
00385 
00386   // Step 4)
00387   // move back all the entries in leaking to slot_first
00388   if (leaking.next != &leaking) {
00389     leaking.next->prev = slot_first;
00390     leaking.prev->next = slot_first->next;
00391     slot_first->next->prev = leaking.prev;
00392     slot_first->next = leaking.next;
00393   }
00394 
00395 
00396   // mark all the entries in the leaking list as leak, and put them back
00397   // into the main list
00398   /*sl = leaking.next;
00399   while (sl != &leaking) {
00400     sl->magic | LEAK_FLAG;
00401   }
00402   if (leaking.next != &leaking) {
00403     slot_first->next->prev = leaking.prev;
00404     leaking.prev->next = slot_first->next;
00405     leaking.next->prev = slot_first;
00406     slot_first->next = leaking.next;
00407   }  
00408   */
00409 
00410   CkDeleteHashtable(table);
00411 }
00412 
00413 /****************** memory allocation tree ******************/
00414 
00415 /* This allows the representation and creation of a tree where each node
00416  * represents a line in the code part of a stack trace of a malloc. The node
00417  * contains how much data has been allocated starting from that line of code,
00418  * down the stack.
00419  */
00420 
00421 typedef struct _AllocationPoint AllocationPoint;
00422 
00423 struct _AllocationPoint {
00424   /* The stack pointer this allocation refers to */
00425   void * key;
00426   /* Pointer to the parent AllocationPoint of this AllocationPoint in the tree */
00427   AllocationPoint * parent;
00428   /* Pointer to the first child AllocationPoint in the tree */
00429   AllocationPoint * firstChild;
00430   /* Pointer to the sibling of this AllocationPoint (i.e the next child of the parent) */
00431   AllocationPoint * sibling;
00432   /* Pointer to the next AllocationPoint with the same key.
00433    * There can be more than one AllocationPoint with the same key because the
00434    * parent can be different. Used only in the hashtable. */
00435   AllocationPoint * next;
00436   /* Size of the memory allocate */
00437   int size;
00438   /* How many blocks have been allocated from this point */
00439   int count;
00440   /* Flags pertaining to the allocation point, currently only LEAK_FLAG */
00441   char flags;
00442 };
00443 
00444 // pup a single AllocationPoint. The data structure must be already allocated
00445 void pupAllocationPointSingle(pup_er p, AllocationPoint *node, int *numChildren) {
00446   pup_pointer(p, &node->key);
00447   pup_int(p, &node->size);
00448   pup_int(p, &node->count);
00449   pup_char(p, &node->flags);
00450   if (pup_isUnpacking(p)) {
00451     node->parent = NULL;
00452     node->firstChild = NULL;
00453     node->sibling = NULL;
00454     node->next = NULL;
00455   }
00456   *numChildren = 0;
00457   AllocationPoint *child;
00458   for (child = node->firstChild; child != NULL; child = child->sibling) (*numChildren) ++;
00459   pup_int(p, numChildren);
00460  
00461 }
00462 
00463 // TODO: the following pup does not work for unpacking!
00464 void pupAllocationPoint(pup_er p, void *data) {
00465   AllocationPoint *node = (AllocationPoint*)data;
00466   int numChildren;
00467   pupAllocationPointSingle(p, node, &numChildren);
00468   AllocationPoint *child;
00469   for (child = node->firstChild; child != NULL; child = child->sibling) {
00470     pupAllocationPoint(p, child);
00471   }
00472 }
00473 
00474 void deleteAllocationPoint(void *ptr) {
00475   AllocationPoint *node = (AllocationPoint*)ptr;
00476   AllocationPoint *child;
00477   for (child = node->firstChild; child != NULL; child = child->sibling) deleteAllocationPoint(child);
00478   mm_free(node);
00479 }
00480 
00481 void printAllocationTree(AllocationPoint *node, FILE *fd, int depth) {
00482   int i;
00483   if (node==NULL) return;
00484   int numChildren = 0;
00485   AllocationPoint *child;
00486   for (child = node->firstChild; child != NULL; child = child->sibling) numChildren ++; 
00487   for (i=0; i<depth; ++i) fprintf(fd, " ");
00488   fprintf(fd, "node %p: bytes=%d, count=%d, child=%d\n",node->key,node->size,node->count,numChildren);
00489   printAllocationTree(node->sibling, fd, depth);
00490   printAllocationTree(node->firstChild, fd, depth+2);
00491 }
00492 
00493 AllocationPoint * CreateAllocationTree(int *nodesCount) {
00494   Slot *scanner;
00495   CkHashtable_c table;
00496   int i, isnew;
00497   AllocationPoint *parent, **start, *cur;
00498   AllocationPoint *root = NULL;
00499   int numNodes = 0;
00500   
00501   scanner=slot_first->next;
00502   table = CkCreateHashtable_pointer(sizeof(char *), 10000);
00503 
00504   root = (AllocationPoint*) mm_malloc(sizeof(AllocationPoint));
00505   *(AllocationPoint**)CkHashtablePut(table, &numNodes) = root;
00506   numNodes ++;
00507   root->key = 0;
00508   root->parent = NULL;
00509   root->size = 0;
00510   root->count = 0;
00511   root->flags = 0;
00512   root->firstChild = NULL;
00513   root->sibling = NULL;
00514   root->next = root;
00515 
00516   for ( ; scanner!=slot_first; scanner=scanner->next) {
00517     parent = root;
00518     for (i=scanner->stackLen-1; i>=0; --i) {
00519       isnew = 0;
00520       start = (AllocationPoint**)CkHashtableGet(table, &scanner->from[i]);
00521       if (start == NULL) {
00522         cur = (AllocationPoint*) mm_malloc(sizeof(AllocationPoint));
00523         numNodes ++;
00524         isnew = 1;
00525         cur->next = cur;
00526         *(AllocationPoint**)CkHashtablePut(table, &scanner->from[i]) = cur;
00527       } else {
00528         for (cur = (*start)->next; cur != *start && cur->parent != parent; cur = cur->next);
00529         if (cur->parent != parent) {
00530           cur = (AllocationPoint*) mm_malloc(sizeof(AllocationPoint));
00531           numNodes ++;
00532           isnew = 1;
00533           cur->next = (*start)->next;
00534           (*start)->next = cur;
00535         }
00536       }
00537       // here "cur" points to the correct AllocationPoint for this stack frame
00538       if (isnew) {
00539         cur->key = scanner->from[i];
00540         cur->parent = parent;
00541         cur->size = 0;
00542         cur->count = 0;
00543         cur->flags = 0;
00544         cur->firstChild = NULL;
00545         //if (parent == NULL) {
00546         //  cur->sibling = NULL;
00547         //  CmiAssert(root == NULL);
00548         //  root = cur;
00549         //} else {
00550           cur->sibling = parent->firstChild;
00551           parent->firstChild = cur;
00552         //}
00553       }
00554       cur->size += scanner->userSize;
00555       cur->count ++;
00556       cur->flags |= isLeakSlot(scanner);
00557       parent = cur;
00558     }
00559   }
00560   
00561   char filename[100];
00562   sprintf(filename, "allocationTree_%d", CmiMyPe());
00563   FILE *fd = fopen(filename, "w");
00564   fprintf(fd, "digraph %s {\n", filename);
00565   CkHashtableIterator_c it = CkHashtableGetIterator(table);
00566   AllocationPoint **startscan, *scan;
00567   while ((startscan=(AllocationPoint**)CkHashtableIteratorNext(it,NULL))!=NULL) {
00568     fprintf(fd, "\t\"n%p\" [label=\"%p\\nsize=%d\\ncount=%d\"];\n",*startscan,(*startscan)->key,
00569           (*startscan)->size,(*startscan)->count);
00570     for (scan = (*startscan)->next; scan != *startscan; scan = scan->next) {
00571       fprintf(fd, "\t\"n%p\" [label=\"%p\\nsize=%d\\ncount=%d\"];\n",scan,scan->key,scan->size,scan->count);
00572     }
00573   }
00574   CkHashtableIteratorSeekStart(it);
00575   while ((startscan=(AllocationPoint**)CkHashtableIteratorNext(it,NULL))!=NULL) {
00576     fprintf(fd, "\t\"n%p\" -> \"n%p\";\n",(*startscan)->parent,(*startscan));
00577     for (scan = (*startscan)->next; scan != *startscan; scan = scan->next) {
00578       fprintf(fd, "\t\"n%p\" -> \"n%p\";\n",scan->parent,scan);
00579     }
00580   }
00581   fprintf(fd, "}\n");
00582   fclose(fd);
00583   
00584   sprintf(filename, "allocationTree_%d.tree", CmiMyPe());
00585   fd = fopen(filename, "w");
00586   printAllocationTree(root, fd, 0);
00587   fclose(fd);
00588  
00589   CkDeleteHashtable(table);
00590   if (nodesCount != NULL) *nodesCount = numNodes;
00591   return root;
00592 }
00593 
00594 void MergeAllocationTreeSingle(AllocationPoint *node, AllocationPoint *remote, int numChildren, pup_er p) {
00595   AllocationPoint child;
00596   int numChildChildren;
00597   int i;
00598   //pupAllocationPointSingle(p, &remote, &numChildren);
00599   /* Update the node with the information coming from remote */
00600   node->size += remote->size;
00601   node->count += remote->count;
00602   node->flags |= remote->flags;
00603   /* Recursively merge the children */
00604   for (i=0; i<numChildren; ++i) {
00605     AllocationPoint *localChild;
00606     pupAllocationPointSingle(p, &child, &numChildChildren);
00607     /* Find the child in the local tree */
00608     for (localChild = node->firstChild; localChild != NULL; localChild = localChild->sibling) {
00609       if (localChild->key == child.key) {
00610         break;
00611       }
00612     }
00613     if (localChild == NULL) {
00614       /* This child did not exist locally, allocate it */
00615       localChild = (AllocationPoint*) mm_malloc(sizeof(AllocationPoint));
00616       localChild->key = child.key;
00617       localChild->flags = 0;
00618       localChild->count = 0;
00619       localChild->size = 0;
00620       localChild->firstChild = NULL;
00621       localChild->next = NULL;
00622       localChild->parent = node;
00623       localChild->sibling = node->firstChild;
00624       node->firstChild = localChild;
00625     }
00626     MergeAllocationTreeSingle(localChild, &child, numChildChildren, p);
00627   }
00628 }
00629 
00630 void * MergeAllocationTree(void *data, void **remoteData, int numRemote) {
00631   int i;
00632   for (i=0; i<numRemote; ++i) {
00633     pup_er p = pup_new_fromMem(remoteData[i]);
00634     AllocationPoint root;
00635     int numChildren;
00636     pupAllocationPointSingle(p, &root, &numChildren);
00637     MergeAllocationTreeSingle((AllocationPoint*)data, &root, numChildren, p);
00638   }
00639   return data;
00640 }
00641 
00642 
00643 int checkSlotCRC(void *userPtr) {
00644   Slot *sl = UserToSlot(userPtr);
00645   unsigned int crc = crc32((unsigned char*)sl, sizeof(Slot)-2*sizeof(unsigned int));
00646   crc = crc32_update((unsigned char*)sl->from, sl->stackLen*sizeof(void*), crc);
00647   return sl->slotCRC == crc;
00648 }
00649 
00650 int checkUserCRC(void *userPtr) {
00651   Slot *sl = UserToSlot(userPtr);
00652   return sl->userCRC == crc32((unsigned char*)userPtr, sl->userSize);
00653 }
00654 
00655 void resetUserCRC(void *userPtr) {
00656   Slot *sl = UserToSlot(userPtr);
00657   sl->userCRC = crc32((unsigned char*)userPtr, sl->userSize);
00658 }
00659 
00660 void checkAllCRC(int report) {
00661   Slot *cur;
00662   unsigned int crc1, crc2;
00663   
00664   for (cur = slot_first->next; cur != slot_first; cur = cur->next) {
00665     crc1 = crc32((unsigned char*)cur, sizeof(Slot)-2*sizeof(unsigned int));
00666     crc1 = crc32_update((unsigned char*)cur->from, cur->stackLen*sizeof(void*), crc1);
00667     crc2 = crc32((unsigned char*)SlotToUser(cur), cur->userSize);
00668     /* Here we can check if a modification has occured */
00669     if (report && cur->slotCRC != crc1) CmiPrintf("Object %d modified slot for %p\n",memory_chare_id,SlotToUser(cur));
00670     cur->slotCRC = crc1;
00671     if (report && cur->userCRC != crc2 && memory_chare_id != cur->chareID)
00672       CmiPrintf("Object %d modified memory of object %d for %p\n",memory_chare_id,cur->chareID,SlotToUser(cur));
00673     cur->userCRC = crc2;
00674   }
00675 }
00676 
00677 /*
00678 
00679 / *Head of the current circular allocated block list* /
00680 Slot slot_first_storage={&slot_first_storage,&slot_first_storage};
00681 Slot *slot_first=&slot_first_storage;
00682 
00683 #define CMI_MEMORY_ROUTINES 1
00684 
00685 / * Mark all allocated memory as being OK * /
00686 void CmiMemoryMark(void) {
00687         CmiMemLock();
00688         / * Just make a new linked list of slots * /
00689         slot_first=(Slot *)mm_malloc(sizeof(Slot));
00690         slot_first->next=slot_first->prev=slot_first;
00691         CmiMemUnlock();
00692 }
00693 
00694 / * Mark this allocated block as being OK * /
00695 void CmiMemoryMarkBlock(void *blk) {
00696         Slot *s=Slot_fmUser(blk);
00697         CmiMemLock();
00698         if (s->magic!=SLOTMAGIC) CmiAbort("CmiMemoryMarkBlock called on non-malloc'd block!\n");
00699         / * Splice us out of the current linked list * /
00700         s->next->prev=s->prev;
00701         s->prev->next=s->next;
00702         s->prev=s->next=s; / * put us in our own list * /
00703         CmiMemUnlock();
00704 }
00705 
00706 / * Print out all allocated memory * /
00707 void CmiMemorySweep(const char *where) {
00708         Slot *cur;
00709         int nBlocks=0,nBytes=0;
00710         CmiMemLock();
00711         cur=slot_first->next;
00712         CmiPrintf("[%d] ------- LEAK CHECK: %s -----\n",CmiMyPe(), where);
00713         while (cur!=slot_first) {
00714                 printSlot(cur);
00715                 nBlocks++; nBytes+=cur->userSize;
00716                 cur=cur->next;
00717         }
00718         if (nBlocks) {
00719                 CmiPrintf("[%d] Total leaked memory: %d blocks, %d bytes\n",
00720                         CmiMyPe(),nBlocks,nBytes);
00721                 / * CmiAbort("Memory leaks detected!\n"); * /
00722         }
00723         CmiMemUnlock();
00724         CmiMemoryMark();
00725 }
00726 void CmiMemoryCheck(void) {}
00727 */
00728 
00729 
00730 /********** Allocation/Free ***********/
00731 
00732 static int memoryTraceDisabled = 0;
00733 #define MAX_STACK_FRAMES   2048
00734 static int numStackFrames; // the number of frames presetn in stackFrames - 4 (this number is trimmed at 0
00735 static void *stackFrames[MAX_STACK_FRAMES];
00736 
00737 /* Write a valid slot to this field */
00738 static void *setSlot(Slot *s,int userSize) {
00739   char *user=SlotToUser(s);
00740   
00741   /* Splice into the slot list just past the head */
00742   s->next=slot_first->next;
00743   s->prev=slot_first;
00744   s->next->prev=s;
00745   s->prev->next=s;
00746   
00747   /* Set the last 4 bits of magic to classify the memory together with the magic */
00748   s->magic=SLOTMAGIC + (memory_status_info>0? USER_TYPE : SYSTEM_TYPE);
00749   //if (memory_status_info>0) printf("user allocation\n");
00750   s->chareID = memory_chare_id;
00751   s->userSize=userSize;
00752   s->extraStack=(SlotStack *)0;
00753 
00754   /* Set the stack frames */
00755   s->stackLen=numStackFrames;
00756   s->from=(void**)(user+userSize);
00757   memcpy(s->from, &stackFrames[4], numStackFrames*sizeof(void*));
00758   
00759   unsigned int crc = crc32((unsigned char*)s, sizeof(Slot)-2*sizeof(unsigned int));
00760   s->slotCRC = crc32_update((unsigned char*)s->from, numStackFrames*sizeof(void*), crc);
00761   s->userCRC = crc32((unsigned char*)user, userSize);
00762   return (void *)user;
00763 }
00764 
00765 /* Delete this slot structure */
00766 static void freeSlot(Slot *s) {
00767   /* Splice out of the slot list */
00768   s->next->prev=s->prev;
00769   s->prev->next=s->next;
00770   s->prev=s->next=(Slot *)0;//0x0F00; why was it not 0?
00771 
00772   s->magic=SLOTMAGIC_FREED;
00773   s->userSize=-1;
00774 }
00775 
00776 void dumpStackFrames() {
00777   numStackFrames=MAX_STACK_FRAMES;
00778   if (memoryTraceDisabled==0) {
00779     memoryTraceDisabled = 1;
00780     CmiBacktraceRecordHuge(stackFrames,&numStackFrames);
00781     memoryTraceDisabled = 0;
00782     numStackFrames-=4;
00783     if (numStackFrames < 0) numStackFrames = 0;
00784   } else {
00785     numStackFrames=0;
00786     stackFrames[0] = (void*)0;
00787   }
00788 }
00789 
00790 /********** meta_ routines ***********/
00791 
00792 /* Return the system page size */
00793 static int meta_getpagesize(void) {
00794   static int cache=0;
00795 #if defined(CMK_GETPAGESIZE_AVAILABLE)
00796   if (cache==0) cache=getpagesize();
00797 #else
00798   if (cache==0) cache=8192;
00799 #endif
00800   return cache;
00801 }
00802 
00803 /* Only display startup status messages from processor 0 */
00804 static void status(char *msg) {
00805   if (CmiMyPe()==0 && !CmiArgGivingUsage()) {
00806     CmiPrintf("%s",msg);
00807   }
00808 }
00809 
00810 extern int getCharmEnvelopeSize();
00811 
00812 static void meta_init(char **argv) {
00813   status("Converse -memory mode: charmdebug\n");
00814   char buf[100];
00815   sprintf(buf,"slot size %d\n",sizeof(Slot));
00816   status(buf);
00817   charmEnvelopeSize = getCharmEnvelopeSize();
00818   CpdDebugGetAllocationTree = (void* (*)(int*))CreateAllocationTree;
00819   CpdDebug_pupAllocationPoint = pupAllocationPoint;
00820   CpdDebug_deleteAllocationPoint = deleteAllocationPoint;
00821   CpdDebug_MergeAllocationTree = MergeAllocationTree;
00822   memory_allocated_user_total = 0;
00823   nextChareID = 1;
00824 }
00825 
00826 static void *meta_malloc(size_t size) {
00827   dumpStackFrames();
00828   Slot *s=(Slot *)mm_malloc(sizeof(Slot)+size+numStackFrames*sizeof(void*));
00829   char *user = (char*)s;
00830   if (s!=NULL) {
00831     user = (char*)setSlot(s,size);
00832     memory_allocated_user_total += size;
00833     traceMalloc_c(user, size, s->from, s->stackLen);
00834   }
00835   return user;
00836 }
00837 
00838 static void meta_free(void *mem) {
00839   Slot *s;
00840   if (mem==NULL) return; /*Legal, but misleading*/
00841 #if CMK_MEMORY_BUILD_OS
00842   /* In this situation, we can have frees that were not allocated by our malloc...
00843    * for now simply skip over them. */
00844   s=((Slot *)mem)-1;
00845   if ((s->magic&~FLAGS_MASK) != SLOTMAGIC_VALLOC &&
00846       (s->magic&~FLAGS_MASK) != SLOTMAGIC) {
00847     mm_free(mem);
00848     return;
00849   }
00850 #endif
00851   int memSize = 0;
00852   if (mem!=NULL) memSize = (((Slot*)mem)-1)->userSize;
00853