initial multicore gargbage collection, not finish yet
[IRC.git] / Robust / src / Runtime / garbage.c
index 0f6938bd379c0516fad19538f913f0ba8e2bb495..e43dd3cb3e067e0f3cf025cc56530f096b4c3f8c 100644 (file)
 #ifdef STM
 #include "tm.h"
 #endif
+#ifdef DELAYCOMP
+#include "delaycomp.h"
+#endif
+
 
 #define NUMPTRS 100
 
-#define INITIALHEAPSIZE 128*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
 
@@ -137,14 +149,25 @@ void * dequeue() {
 }
 
 #ifdef STM
-void fixtable(chashlistnode_t ** tc_table, unsigned int tc_size) {
-  unsigned int mask=(tc_size<<1)-1;
+void fixobjlist(struct objlist * ptr) {
+  while(ptr!=NULL) {
+    int i;
+    for(i=0;i<ptr->offset;i++) {
+      SENQUEUE(ptr->objs[i], ptr->objs[i]);
+    }
+    ptr=ptr->next;
+  }
+}
+
+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;
@@ -156,48 +179,71 @@ void fixtable(chashlistnode_t ** tc_table, unsigned int tc_size) {
        break;                  //key = val =0 for element if not present within the hash table
       }
       SENQUEUE(key, key);
-      if (key>=curr_heapbase&&key<curr_heaptop) {
+      if (curr->val>=curr_heapbase&&curr->val<curr_heaptop) {
        SENQUEUE(curr->val, curr->val);
       } else {
        //rewrite transaction cache entry
-       void *ptr=curr->val;
-       int type=((int *)ptr)[0];
-       unsigned int *pointer=pointerarray[type];
+       void *vptr=curr->val;
+       int type=((int *)vptr)[0];
+       unsigned INTPTR *pointer=pointerarray[type];
        if (pointer==0) {
          //array of primitives - do nothing
-       } else if (((int)pointer)==1) {
+         struct ArrayObject *ao=(struct ArrayObject *) vptr;
+         SENQUEUE((void *)ao->___objlocation___, *((void **)&ao->___objlocation___));
+       } else if (((INTPTR)pointer)==1) {
          //array of pointers
-         struct ArrayObject *ao=(struct ArrayObject *) ptr;
+         struct ArrayObject *ao=(struct ArrayObject *) vptr;
          int length=ao->___length___;
          int i;
+         SENQUEUE((void *)ao->___objlocation___, *((void **)&ao->___objlocation___));
          for(i=0; i<length; i++) {
            void *objptr=((void **)(((char *)&ao->___length___)+sizeof(int)))[i];
-           ENQUEUE(objptr, ((void **)(((char *)&ao->___length___)+sizeof(int)))[i]);
+           SENQUEUE(objptr, ((void **)(((char *)&ao->___length___)+sizeof(int)))[i]);
          }
        } else {
-         int size=pointer[0];
+         INTPTR size=pointer[0];
          int i;
          for(i=1; i<=size; i++) {
            unsigned int offset=pointer[i];
-           void * objptr=*((void **)(((int)ptr)+offset));
-           ENQUEUE(objptr, *((void **)(((int)ptr)+offset)));
+           void * objptr=*((void **)(((char *)vptr)+offset));
+           SENQUEUE(objptr, *((void **)(((char *)vptr)+offset)));
          }
        }
-      }      
+      }
 
       next = curr->next;
-      index = (((unsigned int)key) & mask) >>1;
+      index = (((unsigned INTPTR)key) & mask) >>4;
 
-      curr->key=(unsigned int)key;
+      curr->key=key;
       tmp=&node[index];
       // Insert into the new table
       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;
+       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;
       }
@@ -206,7 +252,8 @@ void fixtable(chashlistnode_t ** tc_table, unsigned int tc_size) {
     } while(curr!=NULL);
   }
   free(ptr);
-  *tc_table=node;
+  (*tc_table)=node;
+  (*tc_list)=newlist;
 }
 #endif
 
@@ -231,6 +278,11 @@ void enqueuetag(struct ___TagDescriptor___ *ptr) {
 }
 #endif
 
+#if defined(STM)||defined(THREADS)
+__thread char * memorybase=NULL;
+__thread char * memorytop=NULL;
+#endif
+
 
 void collect(struct garbagelist * stackptr) {
 #if defined(THREADS)||defined(DSTM)||defined(STM)
@@ -243,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;
@@ -258,6 +322,17 @@ void collect(struct garbagelist * stackptr) {
   }
 #endif
 
+#ifdef STM
+  if (c_table!=NULL) {
+    fixtable(&c_table, &c_list, &c_structs, c_size);
+    fixobjlist(newobjs);
+#ifdef STMSTATS
+    fixobjlist(lockedobjs);
+#endif
+  }
+  memorybase=NULL;
+#endif
+
   /* Check current stack */
 #if defined(THREADS)||defined(DSTM)||defined(STM)
   {
@@ -275,13 +350,34 @@ 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;
     ENQUEUE(orig, listptr->locklist);
 #endif
 #ifdef STM
-    fixtable(listptr->tc_table, listptr->tc_size);
+    if ((*listptr->tc_table)!=NULL) {
+      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
     stackptr=listptr->stackptr;
     listptr=listptr->next;
@@ -390,9 +486,9 @@ void collect(struct garbagelist * stackptr) {
 
   while(moreItems()) {
     void * ptr=dequeue();
-    void *cpy=((void **)ptr)[1];
+    void *cpy=ptr;
     int type=((int *)cpy)[0];
-    unsigned int * pointer;
+    unsigned INTPTR * pointer;
 #ifdef TASK
     if(type==TAGTYPE) {
       /* Enqueue Tag */
@@ -411,13 +507,21 @@ void collect(struct garbagelist * stackptr) {
       ENQUEUE((void *)ao->___nextobject___, *((void **)&ao_cpy->___nextobject___));
       ENQUEUE((void *)ao->___localcopy___, *((void **)&ao_cpy->___localcopy___));
 #endif
-    } else if (((int)pointer)==1) {
+#if defined(STM)
+      struct ArrayObject *ao=(struct ArrayObject *) ptr;
+      struct ArrayObject *ao_cpy=(struct ArrayObject *) cpy;
+      SENQUEUE((void *)ao->___objlocation___, *((void **)&ao_cpy->___objlocation___));
+#endif
+    } else if (((INTPTR)pointer)==1) {
       /* Array of pointers */
       struct ArrayObject *ao=(struct ArrayObject *) ptr;
       struct ArrayObject *ao_cpy=(struct ArrayObject *) cpy;
 #if (defined(DSTM)||defined(FASTCHECK))
       ENQUEUE((void *)ao->___nextobject___, *((void **)&ao_cpy->___nextobject___));
       ENQUEUE((void *)ao->___localcopy___, *((void **)&ao_cpy->___localcopy___));
+#endif
+#if defined(STM)
+      SENQUEUE((void *)ao->___objlocation___, *((void **)&ao_cpy->___objlocation___));
 #endif
       int length=ao->___length___;
       int i;
@@ -426,12 +530,12 @@ void collect(struct garbagelist * stackptr) {
        ENQUEUE(objptr, ((void **)(((char *)&ao_cpy->___length___)+sizeof(int)))[i]);
       }
     } else {
-      int size=pointer[0];
+      INTPTR size=pointer[0];
       int i;
       for(i=1; i<=size; i++) {
        unsigned int offset=pointer[i];
-       void * objptr=*((void **)(((int)ptr)+offset));
-       ENQUEUE(objptr, *((void **)(((int)cpy)+offset)));
+       void * objptr=*((void **)(((char *)ptr)+offset));
+       ENQUEUE(objptr, *((void **)(((char *)cpy)+offset)));
       }
     }
   }
@@ -515,88 +619,118 @@ 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;
 #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
 
+#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||size>(memorytop-memorybase)) {
+    int toallocate=(size>MEMORYBLOCK)?size:MEMORYBLOCK;
+    memorybase=helper(stackptr, toallocate);
+    memorytop=memorybase+toallocate;
+  }
+  char *retvalue=memorybase;
+  memorybase+=size;
+  return retvalue;
+}
+
+void * helper(struct garbagelist * stackptr, int size) {
+#else
 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+=(8-(size%8));
+    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.  Garbage collector couldn't get enough memory.  Try changing heap size.\n");
+       exit(-1);
+      }
       bzero(curr_heapbase, INITIALHEAPSIZE);
       curr_heaptop=curr_heapbase+INITIALHEAPSIZE;
       curr_heapgcpoint=((char *) curr_heapbase)+GCPOINT(INITIALHEAPSIZE);
       curr_heapptr=curr_heapbase+size;
 
       to_heapbase=malloc(INITIALHEAPSIZE);
+      if (to_heapbase==NULL) {
+       printf("malloc failed.  Garbage collector couldn't get enough memory.  Try changing heap size.\n");
+       exit(-1);
+      }
       to_heaptop=to_heapbase+INITIALHEAPSIZE;
       to_heapptr=to_heapbase;
       ptr=curr_heapbase;
@@ -608,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)
@@ -640,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 */
     {
@@ -691,9 +832,19 @@ int gc_createcopy(void * orig, void ** copy_ptr) {
     }
     if (type<NUMCLASSES) {
       /* We have a normal object */
+#ifdef STM
+      int size=classsize[type]+sizeof(objheader_t);
+      void *newobj=tomalloc(size);
+      memcpy(newobj,((char *) orig)-sizeof(objheader_t), size);
+      newobj=((char *)newobj)+sizeof(objheader_t);
+#else
       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;
       *copy_ptr=newobj;
@@ -703,9 +854,19 @@ int gc_createcopy(void * orig, void ** copy_ptr) {
       struct ArrayObject *ao=(struct ArrayObject *)orig;
       int elementsize=classsize[type];
       int length=ao->___length___;
+#ifdef STM
+      int size=sizeof(struct ArrayObject)+length*elementsize+sizeof(objheader_t);
+      void *newobj=tomalloc(size);
+      memcpy(newobj, ((char*)orig)-sizeof(objheader_t), size);
+      newobj=((char *)newobj)+sizeof(objheader_t);
+#else
       int size=sizeof(struct ArrayObject)+length*elementsize;
       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;