initial multicore gargbage collection, not finish yet
[IRC.git] / Robust / src / Runtime / garbage.c
index fb6c161ffad5d2ad28b1d7cdf43cbcb880c2e0bb..e43dd3cb3e067e0f3cf025cc56530f096b4c3f8c 100644 (file)
 #ifdef STM
 #include "tm.h"
 #endif
+#ifdef DELAYCOMP
+#include "delaycomp.h"
+#endif
+
 
 #define NUMPTRS 100
 
-#define INITIALHEAPSIZE 64*1024*1024
-#define GCPOINT(x) ((int)((x)*0.95))
+#define INITIALHEAPSIZE 256*1024*1024L
+#define GCPOINT(x) ((INTPTR)((x)*0.99))
 /* This define takes in how full the heap is initially and returns a new heap size to use */
-#define HEAPSIZE(x,y) ((int)(x+y))*2
+#define HEAPSIZE(x,y) ((INTPTR)(x+y))*2
 
 #ifdef TASK
 extern struct genhashtable * activetasks;
@@ -39,10 +43,18 @@ extern struct ctable *reverse;
 extern struct RuntimeHash *fdtoobject;
 #endif
 
+#ifdef GARBAGESTATS
+#define MAXSTATS 500
+long garbagearray[MAXSTATS];
+#endif
+
 #if defined(THREADS) || defined(DSTM) || defined(STM)
 int needtocollect=0;
 struct listitem * list=NULL;
 int listcount=0;
+#ifndef MAC
+__thread struct listitem litem;
+#endif
 #endif
 
 //Need to check if pointers are transaction pointers
@@ -53,7 +65,7 @@ int listcount=0;
     if (orig>=curr_heapbase&&orig<curr_heaptop) { \
       void *copy; \
       if (gc_createcopy(orig,&copy)) \
-       enqueue(orig);\
+       enqueue(copy);\
       dst=copy; \
     } \
   }
@@ -62,14 +74,14 @@ int listcount=0;
   if (orig>=curr_heapbase&&orig<curr_heaptop) { \
     void *copy; \
     if (gc_createcopy(orig,&copy)) \
-      enqueue(orig);\
+      enqueue(copy);\
     dst=copy; \
   }
 #define SENQUEUE(orig, dst) \
   { \
     void *copy; \
     if (gc_createcopy(orig,&copy)) \
-      enqueue(orig);\
+      enqueue(copy);\
     dst=copy; \
   }
 #elif defined(FASTCHECK)
@@ -77,13 +89,13 @@ int listcount=0;
   if (((unsigned int)orig)!=1) { \
     void *copy; \
     if (gc_createcopy(orig,&copy)) \
-      enqueue(orig);\
+      enqueue(copy);\
     dst=copy; }
 #else
 #define ENQUEUE(orig, dst) \
   void *copy; \
   if (gc_createcopy(orig,&copy)) \
-    enqueue(orig);\
+    enqueue(copy);\
   dst=copy
 #endif
 
@@ -147,14 +159,15 @@ void fixobjlist(struct objlist * ptr) {
   }
 }
 
-void fixtable(chashlistnode_t ** tc_table, unsigned int tc_size) {
-  unsigned int mask=(tc_size<<3)-1;
+void fixtable(chashlistnode_t ** tc_table, chashlistnode_t **tc_list, cliststruct_t **cstr, unsigned int tc_size) {
+  unsigned int mask=(tc_size<<4)-1;
   chashlistnode_t *node=calloc(tc_size, sizeof(chashlistnode_t));
   chashlistnode_t *ptr=*tc_table;
   chashlistnode_t *curr;
   unsigned int i;
   unsigned int index;
   int isfirst;
+  chashlistnode_t *newlist=NULL;
   for(i=0;i<tc_size;i++) {
     curr=&ptr[i];
     isfirst=1;
@@ -199,7 +212,7 @@ void fixtable(chashlistnode_t ** tc_table, unsigned int tc_size) {
       }
 
       next = curr->next;
-      index = (((unsigned INTPTR)key) & mask) >>3;
+      index = (((unsigned INTPTR)key) & mask) >>4;
 
       curr->key=key;
       tmp=&node[index];
@@ -207,16 +220,30 @@ void fixtable(chashlistnode_t ** tc_table, unsigned int tc_size) {
       if(tmp->key == 0) {
        tmp->key = curr->key;
        tmp->val = curr->val;
-       if (!isfirst) {
-         free(curr);
-       }
+       tmp->lnext=newlist;
+       newlist=tmp;
       } else if (isfirst) {
-       chashlistnode_t *newnode= calloc(1, sizeof(chashlistnode_t));
+       chashlistnode_t *newnode;
+       if ((*cstr)->num<NUMCLIST) {
+         newnode=&(*cstr)->array[(*cstr)->num];
+         (*cstr)->num++;
+       } else {
+         //get new list
+         cliststruct_t *tcl=calloc(1,sizeof(cliststruct_t));
+         tcl->next=*cstr;
+         *cstr=tcl;
+         newnode=&tcl->array[0];
+         tcl->num=1;
+       }
        newnode->key = curr->key;
        newnode->val = curr->val;
        newnode->next = tmp->next;
+       newnode->lnext=newlist;
+       newlist=newnode;
        tmp->next=newnode;
       } else {
+       curr->lnext=newlist;
+       newlist=curr;
        curr->next=tmp->next;
        tmp->next=curr;
       }
@@ -226,6 +253,7 @@ void fixtable(chashlistnode_t ** tc_table, unsigned int tc_size) {
   }
   free(ptr);
   (*tc_table)=node;
+  (*tc_list)=newlist;
 }
 #endif
 
@@ -250,7 +278,7 @@ void enqueuetag(struct ___TagDescriptor___ *ptr) {
 }
 #endif
 
-#ifdef STM
+#if defined(STM)||defined(THREADS)
 __thread char * memorybase=NULL;
 __thread char * memorytop=NULL;
 #endif
@@ -267,6 +295,18 @@ void collect(struct garbagelist * stackptr) {
     pthread_cond_wait(&gccond, &gclistlock);
   }
 #endif
+#ifdef DELAYCOMP
+  ptrstack.prev=stackptr;
+  stackptr=(struct garbagelist *) &ptrstack;
+#endif
+
+#ifdef GARBAGESTATS
+  {
+    int i;
+    for(i=0;i<MAXSTATS;i++)
+      garbagearray[i]=0;
+  }
+#endif
 
   if (head==NULL) {
     headindex=0;
@@ -284,8 +324,11 @@ void collect(struct garbagelist * stackptr) {
 
 #ifdef STM
   if (c_table!=NULL) {
-      fixtable(&c_table, c_size);
-      fixobjlist(newobjs);
+    fixtable(&c_table, &c_list, &c_structs, c_size);
+    fixobjlist(newobjs);
+#ifdef STMSTATS
+    fixobjlist(lockedobjs);
+#endif
   }
   memorybase=NULL;
 #endif
@@ -307,6 +350,20 @@ void collect(struct garbagelist * stackptr) {
   }
 #if defined(THREADS)||defined(DSTM)||defined(STM)
   /* Go to next thread */
+#ifndef MAC
+  //skip over us
+  if (listptr==&litem) {
+    listptr=listptr->next;
+  }
+#else
+ {
+  struct listitem *litem=pthread_getspecific(litemkey);
+  if (listptr==litem) {
+    listptr=listptr->next;
+  }
+ }
+#endif
+
   if (listptr!=NULL) {
 #ifdef THREADS
     void * orig=listptr->locklist;
@@ -314,8 +371,11 @@ void collect(struct garbagelist * stackptr) {
 #endif
 #ifdef STM
     if ((*listptr->tc_table)!=NULL) {
-      fixtable(listptr->tc_table, listptr->tc_size);
+      fixtable(listptr->tc_table, listptr->tc_list, listptr->tc_structs, listptr->tc_size);
       fixobjlist(listptr->objlist);
+#ifdef STMSTATS
+      fixobjlist(listptr->lockedlist);
+#endif
     }
     *(listptr->base)=NULL;
 #endif
@@ -426,7 +486,7 @@ void collect(struct garbagelist * stackptr) {
 
   while(moreItems()) {
     void * ptr=dequeue();
-    void *cpy=((void **)ptr)[1];
+    void *cpy=ptr;
     int type=((int *)cpy)[0];
     unsigned INTPTR * pointer;
 #ifdef TASK
@@ -559,73 +619,76 @@ void * tomalloc(int size) {
 
 #if defined(THREADS)||defined(DSTM)||defined(STM)
 void checkcollect(void * ptr) {
-  struct listitem * tmp=stopforgc((struct garbagelist *)ptr);
-  pthread_mutex_lock(&gclock); // Wait for GC
-  restartaftergc(tmp);
-  pthread_mutex_unlock(&gclock);
+  stopforgc((struct garbagelist *)ptr);
+  restartaftergc();
 }
 
 #ifdef DSTM
 void checkcollect2(void * ptr) {
   int ptrarray[]={1, (int)ptr, (int) revertlist};
-  struct listitem * tmp=stopforgc((struct garbagelist *)ptrarray);
-  pthread_mutex_lock(&gclock); // Wait for GC
-  restartaftergc(tmp);
-  pthread_mutex_unlock(&gclock);
+  stopforgc((struct garbagelist *)ptrarray);
+  restartaftergc();
   revertlist=(struct ___Object___*)ptrarray[2];
 }
 #endif
 
-struct listitem * stopforgc(struct garbagelist * ptr) {
-  struct listitem * litem=malloc(sizeof(struct listitem));
+void stopforgc(struct garbagelist * ptr) {
+#ifdef DELAYCOMP
+  //just append us to the list
+  ptrstack.prev=ptr;
+  ptr=(struct garbagelist *) &ptrstack;
+#endif
+#ifndef MAC
+  litem.stackptr=ptr;
+#ifdef THREADS
+  litem.locklist=pthread_getspecific(threadlocks);
+#endif
+#ifdef STM
+  litem.tc_size=c_size;
+  litem.tc_table=&c_table;
+  litem.tc_list=&c_list;
+  litem.tc_structs=&c_structs;
+  litem.objlist=newobjs;
+#ifdef STMSTATS
+  litem.lockedlist=lockedobjs;
+#endif
+  litem.base=&memorybase;
+#endif
+#else
+  //handle MAC
+  struct listitem *litem=pthread_getspecific(litemkey);
   litem->stackptr=ptr;
 #ifdef THREADS
   litem->locklist=pthread_getspecific(threadlocks);
 #endif
-#ifdef STM
-  litem->tc_size=c_size;
-  litem->tc_table=&c_table;
-  litem->objlist=newobjs;
-  litem->base=&memorybase;
 #endif
-  litem->prev=NULL;
   pthread_mutex_lock(&gclistlock);
-  litem->next=list;
-  if(list!=NULL)
-    list->prev=litem;
-  list=litem;
   listcount++;
-  pthread_cond_signal(&gccond);
+  if ((listcount+1)==threadcount) {
+    //only do wakeup if we are ready to GC
+    pthread_cond_signal(&gccond);
+  }
   pthread_mutex_unlock(&gclistlock);
-  return litem;
 }
 
-void restartaftergc(struct listitem * litem) {
-  pthread_mutex_lock(&gclistlock);
-#ifdef THREADS
-  pthread_setspecific(threadlocks, litem->locklist);
-#endif
-  if (litem->prev==NULL) {
-    list=litem->next;
-  } else {
-    litem->prev->next=litem->next;
-  }
-  if (litem->next!=NULL) {
-    litem->next->prev=litem->prev;
+void restartaftergc() {
+  if (needtocollect) {
+    pthread_mutex_lock(&gclock); // Wait for GC
+    pthread_mutex_unlock(&gclock);
   }
+  pthread_mutex_lock(&gclistlock);
   listcount--;
   pthread_mutex_unlock(&gclistlock);
-  free(litem);
 }
 #endif
 
-#ifdef STM
+#if defined(STM)||defined(THREADS)
 #define MEMORYBLOCK 65536
 void * helper(struct garbagelist *, int);
 void * mygcmalloc(struct garbagelist * stackptr, int size) {
   if ((size&7)!=0)
     size=(size&~7)+8;
-  if (memorybase==NULL||(memorybase+size)>memorytop) {
+  if (memorybase==NULL||size>(memorytop-memorybase)) {
     int toallocate=(size>MEMORYBLOCK)?size:MEMORYBLOCK;
     memorybase=helper(stackptr, toallocate);
     memorytop=memorybase+toallocate;
@@ -641,22 +704,21 @@ void * mygcmalloc(struct garbagelist * stackptr, int size) {
 #endif
   void *ptr;
 #if defined(THREADS)||defined(DSTM)||defined(STM)
-  if (pthread_mutex_trylock(&gclock)!=0) {
-    struct listitem *tmp=stopforgc(stackptr);
-    pthread_mutex_lock(&gclock);
-    restartaftergc(tmp);
+  while (pthread_mutex_trylock(&gclock)!=0) {
+    stopforgc(stackptr);
+    restartaftergc();
   }
 #endif
   ptr=curr_heapptr;
   if ((size&7)!=0)
     size=(size&~7)+8;
   curr_heapptr+=size;
-  if (curr_heapptr>curr_heapgcpoint) {
+  if (curr_heapptr>curr_heapgcpoint||curr_heapptr<curr_heapbase) {
     if (curr_heapbase==0) {
       /* Need to allocate base heap */
       curr_heapbase=malloc(INITIALHEAPSIZE);
       if (curr_heapbase==NULL) {
-       printf("malloc failed\n");
+       printf("malloc failed.  Garbage collector couldn't get enough memory.  Try changing heap size.\n");
        exit(-1);
       }
       bzero(curr_heapbase, INITIALHEAPSIZE);
@@ -666,7 +728,7 @@ void * mygcmalloc(struct garbagelist * stackptr, int size) {
 
       to_heapbase=malloc(INITIALHEAPSIZE);
       if (to_heapbase==NULL) {
-       printf("malloc failed\n");
+       printf("malloc failed.  Garbage collector couldn't get enough memory.  Try changing heap size.\n");
        exit(-1);
       }
       to_heaptop=to_heapbase+INITIALHEAPSIZE;
@@ -680,9 +742,9 @@ void * mygcmalloc(struct garbagelist * stackptr, int size) {
 
     /* Grow the to heap if necessary */
     {
-      int curr_heapsize=curr_heaptop-curr_heapbase;
-      int to_heapsize=to_heaptop-to_heapbase;
-      int last_heapsize=0;
+      INTPTR curr_heapsize=curr_heaptop-curr_heapbase;
+      INTPTR to_heapsize=to_heaptop-to_heapbase;
+      INTPTR last_heapsize=0;
       if (lastgcsize>0) {
        last_heapsize=HEAPSIZE(lastgcsize, size);
        if ((last_heapsize&7)!=0)
@@ -712,6 +774,13 @@ void * mygcmalloc(struct garbagelist * stackptr, int size) {
     printf("Garbage collected: Old bytes: %u\n", curr_heapptr-curr_heapbase);
     printf("New space: %u\n", to_heapptr-to_heapbase);
     printf("Total space: %u\n", to_heaptop-to_heapbase);
+    {
+      int i;
+      for(i=0;i<MAXSTATS;i++) {
+       if (garbagearray[i]!=0)
+         printf("Type=%d Size=%u\n", i, garbagearray[i]);
+      }
+    }
 #endif
     /* Flip to/curr heaps */
     {
@@ -772,6 +841,9 @@ int gc_createcopy(void * orig, void ** copy_ptr) {
       int size=classsize[type];
       void *newobj=tomalloc(size);
       memcpy(newobj, orig, size);
+#endif
+#ifdef GARBAGESTATS
+      garbagearray[type]+=size;
 #endif
       ((int *)orig)[0]=-1;
       ((void **)orig)[1]=newobj;
@@ -792,7 +864,9 @@ int gc_createcopy(void * orig, void ** copy_ptr) {
       void *newobj=tomalloc(size);
       memcpy(newobj, orig, size);
 #endif
-
+#ifdef GARBAGESTATS
+      garbagearray[type]+=size;
+#endif
       ((int *)orig)[0]=-1;
       ((void **)orig)[1]=newobj;
       *copy_ptr=newobj;