From 9733b088013301a7c7b6891d8f2ca9bdd2724886 Mon Sep 17 00:00:00 2001 From: jzhou Date: Thu, 24 Jun 2010 23:50:43 +0000 Subject: [PATCH] Capture the version with shared hash table for pointer mapping info required in the flush phase --- Robust/src/Runtime/GCSharedHash.c | 433 ++++++++++++++++++++++++++ Robust/src/Runtime/GCSharedHash.h | 93 ++++++ Robust/src/Runtime/MGCHash.h | 2 +- Robust/src/Runtime/mem.c | 56 +++- Robust/src/Runtime/mem.h | 8 + Robust/src/Runtime/multicoregarbage.c | 170 +++++----- Robust/src/Runtime/multicoregarbage.h | 56 ++-- Robust/src/Runtime/multicoreruntime.h | 19 +- Robust/src/Runtime/multicoretask.c | 149 ++------- Robust/src/buildscript | 2 + 10 files changed, 743 insertions(+), 245 deletions(-) create mode 100755 Robust/src/Runtime/GCSharedHash.c create mode 100755 Robust/src/Runtime/GCSharedHash.h diff --git a/Robust/src/Runtime/GCSharedHash.c b/Robust/src/Runtime/GCSharedHash.c new file mode 100755 index 00000000..c56a1da4 --- /dev/null +++ b/Robust/src/Runtime/GCSharedHash.c @@ -0,0 +1,433 @@ +#ifdef MULTICORE_GC + +#include "GCSharedHash.h" +#ifdef MULTICORE +#include "runtime_arch.h" +#else +#include +#endif + +#ifndef INTPTR +#ifdef BIT64 +#define INTPTR long +#define INTPTRSHIFT 3 +#else +#define INTPTR int +#define INTPTRSHIFT 2 +#endif +#endif + +#ifndef INLINE +#define INLINE inline __attribute__((always_inline)) +#endif // #ifndef INLINE + +/* GCSHARED HASH ********************************************************/ + +// params: startaddr -- the start addr of the shared memory +// rsize -- remaining size of the available shared memory +struct GCSharedHash * noargallocateGCSharedHash() { + return allocateGCSharedHash(100); +} + +struct GCSharedHash * allocateGCSharedHash(int size) { + struct GCSharedHash *thisvar; + if (size <= 0) { +#ifdef MULTICORE + BAMBOO_EXIT(0xf201); +#else + printf("Negative Hashtable size Exception\n"); + exit(-1); +#endif + } + thisvar=(struct GCSharedHash *)FREEMALLOC_NGC(sizeof(struct GCSharedHash)); + if(thisvar == NULL) { + return NULL; + } + thisvar->size = size; + thisvar->bucket = + (struct GCSharedNode **)FREEMALLOC_NGC(sizeof(struct GCSharedNode *)*size); + if(thisvar->bucket == NULL) { + FREE_NGC(thisvar); + return NULL; + } + /* Set allocation blocks*/ + thisvar->listhead=NULL; + thisvar->listtail=NULL; + /*Set data counts*/ + thisvar->numelements = 0; + return thisvar; +} + +void freeGCSharedHash(struct GCSharedHash *thisvar) { + struct GCSharedNode *ptr=thisvar->listhead; + FREE_NGC(thisvar->bucket); + while(ptr) { + struct GCSharedNode *next=ptr->lnext; + FREE_NGC(ptr); + ptr=next; + } + FREE_NGC(thisvar); +} + +bool GCSharedHashrehash(struct GCSharedHash * thisvar) { + int newsize=thisvar->size; + struct GCSharedNode ** newbucket = (struct GCSharedNode **) + FREEMALLOC_NGC(sizeof(struct GCSharedNode *)*newsize); + if(newbucket == NULL) { + return false; + } + int i; + for(i=thisvar->size-1; i>=0; i--) { + struct GCSharedNode *ptr; + for(ptr=thisvar->bucket[i]; ptr!=NULL;) { + struct GCSharedNode * nextptr=ptr->next; + unsigned int newhashkey=(unsigned int)ptr->key % newsize; + ptr->next=newbucket[newhashkey]; + newbucket[newhashkey]=ptr; + ptr=nextptr; + } + } + thisvar->size=newsize; + FREE_NGC(thisvar->bucket); + thisvar->bucket=newbucket; + return true; +} + +int GCSharedHashadd(struct GCSharedHash * thisvar,int key, int data) { + /* Rehash code */ + unsigned int hashkey; + struct GCSharedNode **ptr; + + if (thisvar->numelements>=thisvar->size) { + int newsize=2*thisvar->size+1; + struct GCSharedNode ** newbucket = + (struct GCSharedNode **)FREEMALLOC_NGC( + sizeof(struct GCSharedNode *)*newsize); + if(newbucket == NULL) { + return -1; + } + int i; + for(i=thisvar->size-1; i>=0; i--) { + struct GCSharedNode *ptr; + for(ptr=thisvar->bucket[i]; ptr!=NULL;) { + struct GCSharedNode * nextptr=ptr->next; + unsigned int newhashkey=(unsigned int)ptr->key % newsize; + ptr->next=newbucket[newhashkey]; + newbucket[newhashkey]=ptr; + ptr=nextptr; + } + } + thisvar->size=newsize; + FREE_NGC(thisvar->bucket); + thisvar->bucket=newbucket; + } + + hashkey = (unsigned int)key % thisvar->size; + ptr = &thisvar->bucket[hashkey]; + + /* check that thisvar key/object pair isn't already here */ + /* TBD can be optimized for set v. relation */ + + while (*ptr) { + if ((*ptr)->key == key && (*ptr)->data == data) { + return 0; + } + ptr = &((*ptr)->next); + } + + { + struct GCSharedNode *node=FREEMALLOC_NGC(sizeof(struct GCSharedNode)); + if(node == NULL) { + return -1; + } + node->data=data; + node->key=key; + node->next=(*ptr); + *ptr=node; + if (thisvar->listhead==NULL) { + thisvar->listhead=node; + thisvar->listtail=node; + node->lnext=NULL; + node->lprev=NULL; + } else { + node->lprev=NULL; + node->lnext=thisvar->listhead; + thisvar->listhead->lprev=node; + thisvar->listhead=node; + } + } + + thisvar->numelements++; + return 1; +} + +#ifdef MULTICORE +struct GCSharedHash * allocateGCSharedHash_I(int size) { + struct GCSharedHash *thisvar; + if (size <= 0) { +#ifdef MULTICORE + BAMBOO_EXIT(0xf203); +#else + printf("Negative Hashtable size Exception\n"); + exit(-1); +#endif + } + thisvar=(struct GCSharedHash *)FREEMALLOC_NGC_I(sizeof(struct GCSharedHash)); + if(thisvar == NULL) { + return NULL; + } + thisvar->size = size; + thisvar->bucket = + (struct GCSharedNode **)FREEMALLOC_NGC_I( + sizeof(struct GCSharedNode *)*size); + if(thisvar->bucket == NULL) { + FREE_NGC_I(thisvar); + return NULL; + } + /* Set allocation blocks*/ + thisvar->listhead=NULL; + thisvar->listtail=NULL; + /*Set data counts*/ + thisvar->numelements = 0; + return thisvar; +} + +int GCSharedHashadd_I(struct GCSharedHash * thisvar,int key, int data) { + /* Rehash code */ + unsigned int hashkey; + struct GCSharedNode **ptr; + + if (thisvar->numelements>=thisvar->size) { + int newsize=2*thisvar->size+1; + struct GCSharedNode ** newbucket = + (struct GCSharedNode **)FREEMALLOC_NGC_I( + sizeof(struct GCSharedNode *)*newsize); + if(newbucket == NULL) { + return -1; + } + int i; + for(i=thisvar->size-1; i>=0; i--) { + struct GCSharedNode *ptr; + for(ptr=thisvar->bucket[i]; ptr!=NULL;) { + struct GCSharedNode * nextptr=ptr->next; + unsigned int newhashkey=(unsigned int)ptr->key % newsize; + ptr->next=newbucket[newhashkey]; + newbucket[newhashkey]=ptr; + ptr=nextptr; + } + } + thisvar->size=newsize; + FREE_NGC_I(thisvar->bucket); + thisvar->bucket=newbucket; + } + + hashkey = (unsigned int)key % thisvar->size; + ptr = &thisvar->bucket[hashkey]; + + /* check that thisvar key/object pair isn't already here */ + /* TBD can be optimized for set v. relation */ + + while (*ptr) { + if ((*ptr)->key == key && (*ptr)->data == data) { + return 0; + } + ptr = &((*ptr)->next); + } + + { + struct GCSharedNode *node=FREEMALLOC_NGC_I(sizeof(struct GCSharedNode)); + if(node == NULL) { + return -1; + } + node->data=data; + node->key=key; + node->next=(*ptr); + *ptr=node; + if (thisvar->listhead==NULL) { + thisvar->listhead=node; + thisvar->listtail=node; + node->lnext=NULL; + node->lprev=NULL; + } else { + node->lprev=NULL; + node->lnext=thisvar->listhead; + thisvar->listhead->lprev=node; + thisvar->listhead=node; + } + } + + thisvar->numelements++; + return 1; +} +#endif + +int GCSharedHashget(struct GCSharedHash *thisvar, int key, int *data) { + unsigned int hashkey = (unsigned int)key % thisvar->size; + + struct GCSharedNode *ptr = thisvar->bucket[hashkey]; + while (ptr) { + if (ptr->key == key) { + *data = ptr->data; + return 1; /* success */ + } + ptr = ptr->next; + } + + return 0; /* failure */ +} + +/* MGCSHAREDHASH ********************************************************/ + +mgcsharedhashtbl_t * mgcsharedhashCreate(unsigned int size, + double loadfactor) { + mgcsharedhashtbl_t * ctable; + mgcsharedhashlistnode_t * nodes; + int i; + + ctable = (mgcsharedhashtbl_t *)FREEMALLOC_NGC(sizeof(mgcsharedhashtbl_t)); + if(ctable == NULL) { + // TODO + BAMBOO_EXIT(0xeeee); + return NULL; + } + // Allocate space for the hash table + ctable->table = (mgcsharedhashlistnode_t *)FREEMALLOC_NGC( + size*sizeof(mgcsharedhashlistnode_t)); + if(ctable->table == NULL) { + BAMBOO_EXIT(0xffff); // TODO + return NULL; + } + ctable->size = size; + ctable->loadfactor = loadfactor; + ctable->threshold = size*loadfactor; + + ctable->mask = (size << 7)-1; + + ctable->structs = NULL ; //FREEMALLOC_NGC(1*sizeof(mgcliststruct_t)); + ctable->numelements = 0; // Initial number of elements in the hash + ctable->list = NULL; + + return ctable; +} + +void mgcsharedhashReset(mgcsharedhashtbl_t * tbl) { + mgcsharedhashlistnode_t * ptr = tbl->table; + + if ((tbl->numelements) < (tbl->size>>6)) { + mgcsharedhashlistnode_t * list = tbl->list; + while(list != NULL) { + mgcsharedhashlistnode_t *top = &ptr[tbl->size]; + mgcsharedhashlistnode_t * next = list->next; + if ((list >= ptr) && (list < top)) { + //zero in list + list->key=NULL; + list->next=NULL; + } + list = next; + } + } else { + BAMBOO_MEMSET_WH(tbl->table, '\0', + sizeof(mgcsharedhashlistnode_t)*tbl->size); + } + + mgcsharedliststruct_t * structs = tbl->structs; + while(structs != NULL) { + mgcsharedliststruct_t * next = structs->next; + BAMBOO_MEMSET_WH(structs->array, '\0', + structs->num * sizeof(mgcsharedhashlistnode_t)); + structs->num = 0; + structs = next; + } + tbl->numelements = 0; +} + +//Store objects and their pointers into hash +//Using open addressing +int mgcsharedhashInsert(mgcsharedhashtbl_t * tbl, void * key, void * val) { + mgcsharedhashlistnode_t * ptr; + + if(tbl->numelements > (tbl->threshold)) { + //Never resize, simply don't insert any more + return -1; + } + + ptr=&tbl->table[(((unsigned INTPTR)key)&tbl->mask)>>7]; + //printf("%x \n", (((unsigned INTPTR)key)&tbl->mask)>>7); // TODO + + if(ptr->key==0) { + // the first time insert a value for the key + ptr->key=key; + ptr->val=val; + } else { // Insert to the next empty place + mgcsharedhashlistnode_t *top = &tbl->table[tbl->size]; + do { + ptr++; + } while((ptr < top) && (ptr->key != NULL)); + if(ptr >= top) { + return -1; + } else { + ptr->key = key; + ptr->val = val; + } + } + tbl->numelements++; + return 1; +} + +int mgcsharedhashInsert_I(mgcsharedhashtbl_t * tbl, void * key, void * val) { + mgcsharedhashlistnode_t * ptr; + + if(tbl->numelements > (tbl->threshold)) { + //Never resize, simply don't insert any more + return -1; + } + + ptr=&tbl->table[(((unsigned INTPTR)key)&tbl->mask)>>7]; + //printf("%x \n", (((unsigned INTPTR)key)&tbl->mask)>>7); // TODO + + if(ptr->key==0) { + // the first time insert a value for the key + ptr->key=key; + ptr->val=val; + } else { // Insert to the next empty place + mgcsharedhashlistnode_t * top = &tbl->table[tbl->size]; + mgcsharedhashlistnode_t * start = ptr; + do { + ptr++; + if(ptr->key == 0) { + break; + } + } while(ptr < top); + if(ptr >= top) { + return -1; + } else { + ptr->key = key; + ptr->val = val; + } + } + tbl->numelements++; + return 1; +} + +// Search for an address for a given oid +INLINE void * mgcsharedhashSearch(mgcsharedhashtbl_t * tbl, void * key) { + //REMOVE HASH FUNCTION CALL TO MAKE SURE IT IS INLINED HERE] + mgcsharedhashlistnode_t * node = + &tbl->table[(((unsigned INTPTR)key)&tbl->mask)>>6]; + mgcsharedhashlistnode_t *top = &tbl->table[tbl->size]; + + int i = 0; + do { + i++; + if(node->key == key) { + // TODO + printf("%x \n", 0xe000+i); + return node->val; + } + node++; + } while(node < top); + + return NULL; +} + +#endif diff --git a/Robust/src/Runtime/GCSharedHash.h b/Robust/src/Runtime/GCSharedHash.h new file mode 100755 index 00000000..375e693f --- /dev/null +++ b/Robust/src/Runtime/GCSharedHash.h @@ -0,0 +1,93 @@ +#ifdef MULTICORE_GC + +#ifndef GCSHAREDHASH_H +#define GCSHAREDHASH_H + +#ifndef bool +#define bool int +#endif + +#ifndef true +#define true 1 +#endif + +#ifndef false +#define false 0 +#endif + +#include "mem.h" + +/* GCSharedHash *********************************************************/ + +struct GCSharedHash * noargallocateGCSharedHash(); +struct GCSharedHash * allocateGCSharedHash(int size); +void freeGCSharedHash(struct GCSharedHash *); + +bool GCSharedHashrehash(struct GCSharedHash * thisvar); +int GCSharedHashadd(struct GCSharedHash *, int key, int data); +#ifdef MULTICORE +struct GCSharedHash * allocateGCSharedHash_I(int size); +int GCSharedHashadd_I(struct GCSharedHash *, int key, int data); +#endif +int GCSharedHashget(struct GCSharedHash *,int key, int* data); + +struct GCSharedHash { + int numelements; + int size; + struct GCSharedNode **bucket; + struct GCSharedNode *listhead; + struct GCSharedNode *listtail; +}; + +inline int GCSharedHashcountset(struct GCSharedHash * thisvar); + +/* RuntimeHashException *************************************************/ + + +/* RuntimeIterator *****************************************************/ +struct GCSharedNode { + struct GCSharedNode *next; + struct GCSharedNode *lnext; + struct GCSharedNode *lprev; + int data; + int key; +}; + +/* MGCSharedHash *********************************************************/ +typedef struct mgcsharedhashlistnode { + void * key; + void * val; //this can be cast to another type or used to point to a + //larger structure + struct mgcsharedhashlistnode * next; +} mgcsharedhashlistnode_t; + +#define NUMMGCSHAREDLIST 250 +typedef struct mgcsharedlist { + struct mgcsharedhashlistnode array[NUMMGCSHAREDLIST]; + int num; + struct mgcsharedlist *next; +} mgcsharedliststruct_t; + +typedef struct mgcsharedhashtbl { + mgcsharedhashlistnode_t * table; // points to beginning of hash table + mgcsharedhashlistnode_t * list; + mgcsharedliststruct_t * structs; + unsigned int size; + unsigned int mask; + unsigned int numelements; + unsigned int threshold; + double loadfactor; +} mgcsharedhashtbl_t; + +mgcsharedhashtbl_t * mgcsharedhashCreate(unsigned int size, double loadfactor); +int mgcsharedhashInsert(mgcsharedhashtbl_t * tbl, void * key, void * val); +void * mgcsharedhashSearch(mgcsharedhashtbl_t * tbl, void * key); +//unsigned int mgchashResize(unsigned int newsize); +int mgcsharedhashInsert_I(mgcsharedhashtbl_t * tbl, void * key, void * val); +//unsigned int mgchashResize_I(unsigned int newsize); +//void mgcsharedhashDelete(mgcsharedhashtbl_t * tbl); +void mgcsharedhashReset(mgcsharedhashtbl_t * tbl); + +#endif + +#endif diff --git a/Robust/src/Runtime/MGCHash.h b/Robust/src/Runtime/MGCHash.h index 021bfeb7..9a855145 100755 --- a/Robust/src/Runtime/MGCHash.h +++ b/Robust/src/Runtime/MGCHash.h @@ -23,7 +23,7 @@ typedef struct mgchashlistnode { void * key; void * val; //this can be cast to another type or used to point to a - //larger structure + //larger structure struct mgchashlistnode *next; } mgchashlistnode_t; diff --git a/Robust/src/Runtime/mem.c b/Robust/src/Runtime/mem.c index 1df82bae..0277ab7b 100644 --- a/Robust/src/Runtime/mem.c +++ b/Robust/src/Runtime/mem.c @@ -5,7 +5,7 @@ #include "runtime_arch.h" void * mycalloc(int m, - int size) { + int size) { void * p = NULL; int isize = size; BAMBOO_ENTER_RUNTIME_MODE_FROM_CLIENT(); @@ -19,8 +19,8 @@ void * mycalloc(int m, #ifdef MULTICORE_GC void * mycalloc_share(struct garbagelist * stackptr, - int m, - int size) { + int m, + int size) { void * p = NULL; int isize = 2*BAMBOO_CACHE_LINE_SIZE-4+(size-1)&(~BAMBOO_CACHE_LINE_MASK); bool hasgc = false; @@ -55,6 +55,44 @@ memalloc: BAMBOO_MEMSET_WH(alignedp + size, -2, p + isize - alignedp - size); return alignedp; } + +void * mycalloc_share_ngc(int m, + int size) { + void * p = NULL; + BAMBOO_ENTER_RUNTIME_MODE_FROM_CLIENT(); +#ifdef DEBUG + tprintf("ask for shared mem: %x \n", size); +#endif + p = BAMBOO_SHARED_MEM_CALLOC_NGC_I(m, size); // calloc(m, isize); +#ifdef DEBUG + printf("new obj in shared mem: %x, %x \n", p, size); +#endif + BAMBOO_ENTER_CLIENT_MODE_FROM_RUNTIME(); + return p; +} + +void * mycalloc_share_ngc_I(int m, + int size) { + void * p = NULL; +#ifdef DEBUG + tprintf("ask for shared mem: %x \n", size); +#endif + p = BAMBOO_SHARED_MEM_CALLOC_NGC_I(m, size); // calloc(m, isize); +#ifdef DEBUG + printf("new obj in shared mem: %x, %x \n", p, size); +#endif + return p; +} + +void mycalloc_free_ngc(void * ptr) { + BAMBOO_ENTER_RUNTIME_MODE_FROM_CLIENT(); + BAMBOO_SHARED_MEM_FREE_NGC_I(ptr); + BAMBOO_ENTER_CLIENT_MODE_FROM_RUNTIME(); +} + +void mycalloc_free_ngc_I(void * ptr) { + BAMBOO_SHARED_MEM_FREE_NGC_I(ptr); +} #else void * mycalloc_share(int m, int size) { @@ -73,18 +111,18 @@ void * mycalloc_share(int m, #endif void * mycalloc_i(int m, - int size) { + int size) { void * p = NULL; int isize = size; #ifdef DEBUG - tprintf("ask for local mem: %x \n", isize); + tprintf("ask for local mem: %x \n", isize); #endif - p = BAMBOO_LOCAL_MEM_CALLOC(m, isize); // calloc(m, isize); + p = BAMBOO_LOCAL_MEM_CALLOC(m, isize); // calloc(m, isize); #ifdef DEBUG - tprintf("new obj in local mem: %x, %x \n", p, isize); + tprintf("new obj in local mem: %x, %x \n", p, isize); #endif - if(p == NULL) { - BAMBOO_EXIT(0xc004); + if(p == NULL) { + BAMBOO_EXIT(0xc004); } return p; } diff --git a/Robust/src/Runtime/mem.h b/Robust/src/Runtime/mem.h index 7982fe16..fb0cc0a9 100644 --- a/Robust/src/Runtime/mem.h +++ b/Robust/src/Runtime/mem.h @@ -26,7 +26,15 @@ void myfree(void * ptr); #ifdef MULTICORE_GC #include "multicoregc.h" void * mycalloc_share(struct garbagelist * stackptr, int m, int size); +void * mycalloc_share_ngc(int m, int size); +void * mycalloc_share_ngc_I(int m, int size); +void mycalloc_free_ngc(void * ptr); +void mycalloc_free_ngc_I(void * ptr); #define FREEMALLOC(s, x) mycalloc_share((s),1,(x)) +#define FREEMALLOC_NGC(x) mycalloc_share_ngc(1, (x)) +#define FREEMALLOC_NGC_I(x) mycalloc_share_ngc_I(1, (x)) +#define FREE_NGC(x) mycalloc_free_ngc(x) +#define FREE_NGC_I(x) mycalloc_free_ngc_I(x) #else void * mycalloc_share(int m, int size); #define FREEMALLOC(x) mycalloc_share(1,x) diff --git a/Robust/src/Runtime/multicoregarbage.c b/Robust/src/Runtime/multicoregarbage.c index 854bb3f1..f3a93c63 100644 --- a/Robust/src/Runtime/multicoregarbage.c +++ b/Robust/src/Runtime/multicoregarbage.c @@ -6,6 +6,7 @@ #include "SimpleHash.h" #include "GenericHashtable.h" #include "ObjectHash.h" +#include "GCSharedHash.h" // TODO for profiling the flush phase #ifdef GC_PROFILE @@ -637,10 +638,14 @@ inline void initGC() { gcforwardobjtbl = allocateMGCHash(20, 3); // initialize the mapping info related structures - freeRuntimeHash(gcrcoretbl); - gcrcoretbl = allocateRuntimeHash(20); - BAMBOO_MEMSET_WH(gcmappingtbl, 0, - sizeof(void *)*NUMCORESACTIVE*NUM_MAPPING); + if((BAMBOO_NUM_OF_CORE < NUMCORES4GC) && (gcsharedptbl != NULL)) { + // Never free the shared hash table, just reset it + /*freeGCSharedHash(gcsharedptbl); + gcsharedptbl = allocateGCSharedHash(20);*/ + mgcsharedhashReset(gcsharedptbl); + } + // the shared hash tables are never changed + //BAMBOO_MEMSET_WH(gcrpointertbls,0,sizeof(struct RuntimeHash *)*NUMCORES4GC); #ifdef GC_PROFILE // TODO num_mapinforequest = 0; @@ -760,7 +765,7 @@ inline bool cacheLObjs() { BAMBOO_DEBUGPRINT_REG(gcheaptop); #endif - gcheaptop = dst; // Note: record the start of cached lobjs with gcheaptop + gcheaptop = dst; // Note: record the start of cached lobjs with gcheaptop // cache the largeObjs to the top of the shared heap //gclobjtail2 = gclobjtail; //gclobjtailindex2 = gclobjtailindex; @@ -1136,14 +1141,8 @@ inline void markObj(void * objptr) { if(((int *)objptr)[6] == INIT) { // this is the first time that this object is discovered, // set the flag as DISCOVERED - ((int *)objptr)[6] = DISCOVERED; + ((int *)objptr)[6] |= DISCOVERED; gc_enqueue_I(objptr); - // insert the obj and request core info into mapping hashtable - /*struct nodemappinginfo * nodeinfo = - (struct nodemappinginfo *)RUNMALLOC_I(sizeof(struct nodemappinginfo)); - nodeinfo->ptr = NULL; - nodeinfo->cores = NULL; - RuntimeHashadd_I(gcpointertbl, (int)objptr, (int)nodeinfo);*/ } BAMBOO_ENTER_CLIENT_MODE_FROM_RUNTIME(); } else { @@ -1158,7 +1157,7 @@ inline void markObj(void * objptr) { // TODO unsigned long long ttime = BAMBOO_GET_EXE_TIME(); #endif // send a msg to host informing that objptr is active - send_msg_3(host, GCMARKEDOBJ, objptr, BAMBOO_NUM_OF_CORE, false); + send_msg_2(host, GCMARKEDOBJ, objptr, /*BAMBOO_NUM_OF_CORE,*/ false); #ifdef GC_PROFILE // TODO /* @@ -1299,8 +1298,8 @@ inline void mark(bool isfirst, #endif // enqueue root objs tomark(stackptr); - gccurr_heaptop = 0; // record the size of all active objs in this core - // aligned but does not consider block boundaries + gccurr_heaptop = 0; // record the size of all active objs in this core + // aligned but does not consider block boundaries gcmarkedptrbound = 0; } #ifdef DEBUG @@ -1341,7 +1340,7 @@ inline void mark(bool isfirst, int host = hostcore(ptr); bool islocal = (host == BAMBOO_NUM_OF_CORE); if(islocal) { - bool isnotmarked = (((int *)ptr)[6] == DISCOVERED); + bool isnotmarked = ((((int *)ptr)[6] & DISCOVERED) != 0); if(isLarge(ptr, &type, &size) && isnotmarked) { // ptr is a large object and not marked or enqueued #ifdef DEBUG @@ -1354,7 +1353,7 @@ inline void mark(bool isfirst, gcnumlobjs++; BAMBOO_ENTER_CLIENT_MODE_FROM_RUNTIME(); // mark this obj - ((int *)ptr)[6] = MARKED; + ((int *)ptr)[6] = ((int *)ptr)[6] & (~DISCOVERED) | MARKED; } else if(isnotmarked) { // ptr is an unmarked active object on this core ALIGNSIZE(size, &isize); @@ -1366,15 +1365,15 @@ inline void mark(bool isfirst, BAMBOO_DEBUGPRINT(((int *)(ptr))[0]); #endif // mark this obj - ((int *)ptr)[6] = MARKED; - - if(ptr + size > gcmarkedptrbound) { + ((int *)ptr)[6] = ((int *)ptr)[6] & (~DISCOVERED) | MARKED; + + if(ptr + size > gcmarkedptrbound) { gcmarkedptrbound = ptr + size; - } // if(ptr + size > gcmarkedptrbound) + } // if(ptr + size > gcmarkedptrbound) } else { // ptr is not an active obj or has been marked checkfield = false; - } // if(isLarge(ptr, &type, &size)) else ... + } // if(isLarge(ptr, &type, &size)) else ... } /* can never reach here else { #ifdef DEBUG @@ -1387,7 +1386,7 @@ inline void mark(bool isfirst, // check if this obj has been forwarded if(!MGCHashcontains(gcforwardobjtbl, (int)ptr)) { // send a msg to host informing that ptr is active - send_msg_3(host, GCMARKEDOBJ, ptr, BAMBOO_NUM_OF_CORE, false); + send_msg_2(host, GCMARKEDOBJ, ptr, false); gcself_numsendobjs++; MGCHashadd(gcforwardobjtbl, (int)ptr); } @@ -1423,9 +1422,9 @@ inline void mark(bool isfirst, void * objptr=*((void **)(((char *)ptr)+offset)); markObj(objptr); } - } // if (pointer==0) else if ... else ... - } // if(checkfield) - } // while(gc_moreItems2()) + } // if (pointer==0) else if ... else ... + } // if(checkfield) + } // while(gc_moreItems2()) #ifdef DEBUG BAMBOO_DEBUGPRINT(0xed07); #endif @@ -1897,6 +1896,7 @@ innermoveobj: size=sizeof(struct ArrayObject)+length*elementsize; } mark = ((int *)(orig->ptr))[6]; + bool isremote = ((((int *)(orig->ptr))[6] & REMOTEM) != 0); #ifdef DEBUG BAMBOO_DEBUGPRINT(0xe203); BAMBOO_DEBUGPRINT_REG(orig->ptr); @@ -1904,7 +1904,7 @@ innermoveobj: #endif ALIGNSIZE(size, &isize); // no matter is the obj marked or not // should be able to across it - if(mark == MARKED) { + if((mark & MARKED) != 0) { #ifdef DEBUG BAMBOO_DEBUGPRINT(0xe204); #endif @@ -1940,9 +1940,13 @@ innermoveobj: BAMBOO_ENTER_RUNTIME_MODE_FROM_CLIENT(); //mgchashInsert_I(orig->ptr, to->ptr); RuntimeHashadd_I(gcpointertbl, orig->ptr, to->ptr); - /*struct nodemappinginfo * nodeinfo = NULL; - RuntimeHashget(gcpointertbl, orig->ptr, &nodeinfo); - nodeinfo->ptr = to->ptr;*/ + if(isremote) { + // add to the sharedptbl + if(gcsharedptbl != NULL) { + //GCSharedHashadd_I(gcsharedptbl, orig->ptr, to->ptr); + mgcsharedhashInsert_I(gcsharedptbl, orig->ptr, to->ptr); + } + } //MGCHashadd_I(gcpointertbl, orig->ptr, to->ptr); BAMBOO_ENTER_CLIENT_MODE_FROM_RUNTIME(); //} @@ -2233,20 +2237,6 @@ inline void * flushObj(void * objptr) { #endif //dstptr = mgchashSearch(objptr); RuntimeHashget(gcpointertbl, objptr, &dstptr); - /*struct nodemappinginfo * nodeinfo = NULL; - RuntimeHashget(gcpointertbl, objptr, &nodeinfo); - if(nodeinfo == NULL) { - // currenly the mapping info is not ready TODO - // busy waiting until we get the mapping info - while(true) { - BAMBOO_WAITING_FOR_LOCK(0); - RuntimeHashget(gcpointertbl, objptr, &nodeinfo); - if(nodeinfo != NULL) { - break; - } - } - } - dstptr = nodeinfo->ptr;*/ #ifdef GC_PROFILE // TODO flushstalltime += BAMBOO_GET_EXE_TIME()-ttime; #endif @@ -2270,43 +2260,57 @@ inline void * flushObj(void * objptr) { // assume that the obj has not been moved, use the original address //dstptr = objptr; } else { - // send msg to host core for the mapping info - gcobj2map = (int)objptr; - gcismapped = false; - gcmappedobj = NULL; + int hostc = hostcore(objptr); + // check the corresponsing sharedptbl + BAMBOO_ENTER_RUNTIME_MODE_FROM_CLIENT(); + //struct GCSharedHash * sptbl = gcrpointertbls[hostcore(objptr)]; + mgcsharedhashtbl_t * sptbl = gcrpointertbls[hostc]; + if(sptbl != NULL) { + //GCSharedHashget(sptbl, (int)objptr, &dstptr); + dstptr = mgcsharedhashSearch(sptbl, (int)objptr); + if(dstptr != NULL) { + RuntimeHashadd_I(gcpointertbl, (int)objptr, (int)dstptr); + } + } + BAMBOO_ENTER_CLIENT_MODE_FROM_RUNTIME(); + + if(dstptr == NULL) { + // still can not get the mapping info, + // send msg to host core for the mapping info + gcobj2map = (int)objptr; + gcismapped = false; + gcmappedobj = NULL; #ifdef GC_PROFILE // TODO - //num_mapinforequest++; + num_mapinforequest++; //unsigned long long ttime = BAMBOO_GET_EXE_TIME(); #endif #ifdef GC_PROFILE - // TODO unsigned long long ttimet = BAMBOO_GET_EXE_TIME(); -#endif - // the first time require the mapping, send msg to the hostcore - // for the mapping info - send_msg_3(hostcore(objptr), GCMAPREQUEST, (int)objptr, - BAMBOO_NUM_OF_CORE, false); - while(true) { - if(gcismapped) { - break; - } - } + unsigned long long ttimet = BAMBOO_GET_EXE_TIME(); +#endif + // the first time require the mapping, send msg to the hostcore + // for the mapping info + send_msg_3(hostc, GCMAPREQUEST, (int)objptr, + BAMBOO_NUM_OF_CORE, false); + while(true) { + if(gcismapped) { + break; + } + } #ifdef GC_PROFILE - // TODO flushstalltime_i += BAMBOO_GET_EXE_TIME()-ttimet; + flushstalltime_i += BAMBOO_GET_EXE_TIME()-ttimet; #endif #ifdef GC_PROFILE // TODO //flushstalltime += BAMBOO_GET_EXE_TIME() - ttime; #endif - BAMBOO_ENTER_RUNTIME_MODE_FROM_CLIENT(); - //dstptr = mgchashSearch(objptr); - RuntimeHashget(gcpointertbl, objptr, &dstptr); - /*struct nodemappinginfo * nodeinfo = NULL; - RuntimeHashget(gcpointertbl, objptr, &nodeinfo); - dstptr = nodeinfo->ptr;*/ - //MGCHashget(gcpointertbl, objptr, &dstptr); - BAMBOO_ENTER_CLIENT_MODE_FROM_RUNTIME(); - } // if(hostcore(objptr) == BAMBOO_NUM_OF_CORE) else ... + BAMBOO_ENTER_RUNTIME_MODE_FROM_CLIENT(); + //dstptr = mgchashSearch(objptr); + RuntimeHashget(gcpointertbl, objptr, &dstptr); + //MGCHashget(gcpointertbl, objptr, &dstptr); + BAMBOO_ENTER_CLIENT_MODE_FROM_RUNTIME(); + } // if(dstptr == NULL) + } // if(hostcore(objptr) == BAMBOO_NUM_OF_CORE) else ... #ifdef DEBUG BAMBOO_DEBUGPRINT_REG(dstptr); #endif @@ -2442,7 +2446,7 @@ inline void transmappinginfo() { RUNFREE(tmp); // release the node } }*/ - int core = (BAMBOO_NUM_OF_CORE + 1) % NUMCORESACTIVE; +/* int core = (BAMBOO_NUM_OF_CORE + 1) % NUMCORESACTIVE; for(int i = 0; i < NUMCORESACTIVE - 1; i++) { for(int j = 1; j < gcmappingtbl[core][0]+1; j++) { int obj = gcmappingtbl[core][j]; @@ -2456,6 +2460,14 @@ inline void transmappinginfo() { //tprintf("send mapping to core %d \n", core); core = (core + 1) % NUMCORESACTIVE; } +*/ + + // broadcast the sharedptbl pointer + for(int i = 0; i < NUMCORESACTIVE; i++) { + if(i != BAMBOO_NUM_OF_CORE) { + send_msg_3(i, GCMAPTBL, gcsharedptbl, BAMBOO_NUM_OF_CORE, false); + } + } // TODO //BAMBOO_DEBUGPRINT(0xeeee); @@ -2504,7 +2516,7 @@ inline void flush(struct garbagelist * stackptr) { if(ptr == NULL) { BAMBOO_EXIT(0xb105); } - } // if(ISSHAREDOBJ(ptr)) + } // if(ISSHAREDOBJ(ptr)) if((!ISSHAREDOBJ(ptr)) || (((int *)(ptr))[6] == COMPACTED)) { int type = ((int *)(ptr))[0]; // scan all pointers in ptr @@ -2568,7 +2580,7 @@ inline void flush(struct garbagelist * stackptr) { if(ISSHAREDOBJ(ptr)) { ((int *)(ptr))[6] = INIT; } - } // if((!ISSHAREDOBJ(ptr)) || (((int *)(ptr))[6] == COMPACTED)) + } // if((!ISSHAREDOBJ(ptr)) || (((int *)(ptr))[6] == COMPACTED)) } // while(gc_moreItems()) #ifdef DEBUG BAMBOO_DEBUGPRINT(0xe308); @@ -2654,8 +2666,8 @@ inline void flush(struct garbagelist * stackptr) { } } } // for(i=1; i<=size; i++) - } // if (pointer==0) else if (((INTPTR)pointer)==1) else () - // restore the mark field, indicating that this obj has been flushed + } // if (pointer==0) else if (((INTPTR)pointer)==1) else () + // restore the mark field, indicating that this obj has been flushed ((int *)(ptr))[6] = INIT; } // if(((int *)(ptr))[6] == COMPACTED) } // while(gc_lobjmoreItems()) @@ -2674,13 +2686,13 @@ inline void flush(struct garbagelist * stackptr) { } #ifdef GC_PROFILE // TODO - /*if(BAMBOO_NUM_OF_CORE == 0) { + if(BAMBOO_NUM_OF_CORE == 0) { BAMBOO_DEBUGPRINT(0xffff); - //BAMBOO_DEBUGPRINT_REG(num_mapinforequest); + BAMBOO_DEBUGPRINT_REG(num_mapinforequest); //BAMBOO_DEBUGPRINT_REG(flushstalltime); //BAMBOO_DEBUGPRINT_REG(num_mapinforequest_i); - //BAMBOO_DEBUGPRINT_REG(flushstalltime_i); - }*/ + BAMBOO_DEBUGPRINT_REG(flushstalltime_i); + } //BAMBOO_DEBUGPRINT_REG(flushstalltime); #endif #ifdef DEBUG diff --git a/Robust/src/Runtime/multicoregarbage.h b/Robust/src/Runtime/multicoregarbage.h index 96685262..0cbab6e0 100644 --- a/Robust/src/Runtime/multicoregarbage.h +++ b/Robust/src/Runtime/multicoregarbage.h @@ -4,6 +4,7 @@ #include "multicorehelper.h" // for mappins between core # and block # #include "structdefs.h" #include "MGCHash.h" +#include "GCSharedHash.h" #ifndef bool #define bool int @@ -42,11 +43,12 @@ int num_mapinforequest_i; typedef enum { INIT = 0, // 0 - DISCOVERED, // 1 - MARKED, // 2 - COMPACTED, // 3 - FLUSHED, // 4 - END // 5 + DISCOVERED = 2, // 2 + REMOTEM = 4, // 4 + MARKED = 8, // 8 + COMPACTED = 16, // 16 + FLUSHED = 32, // 32 + END = 33 // 33 } GCOBJFLAG; typedef enum { @@ -96,39 +98,31 @@ volatile bool gctomove; int gcrequiredmems[NUMCORES4GC]; //record pending mem requests volatile int gcmovepending; -/*struct flushlist { - void * key; - struct flushnode * val; - struct flushlist * next; -}; - -struct flushnode { - void ** ptr; - struct flushnode * next; -};*/ -//volatile struct flushlist * gcflushlist; // list of (key, list of reference -// to be flushed) -//volatile int gcnumflush; - -// mapping of old address to new address -/*struct requestcoreinfo { - int core; - struct requestcoreinfo * next; -}; - -struct nodemappinginfo { - void * ptr; - struct requestcoreinfo * cores; -};*/ // data structures to record remote cores that transferred the marked // objs in the mark phase -struct rcoreinfo{ +/*struct rcoreinfo{ int high; int low; }; struct RuntimeHash * gcrcoretbl; #define NUM_MAPPING 40 -void * gcmappingtbl[NUMCORESACTIVE][NUM_MAPPING]; +void * gcmappingtbl[NUMCORESACTIVE][NUM_MAPPING];*/ + +// shared memory pointer for shared pointer mapping tbls +// In GC version, this block of memory is located at the bottom of the +// shared memory, right on the top of the smem tbl. +// The bottom of the shared memory = sbstart tbl + smemtbl +// + NUMCORES4GC bamboo_rmsp +// These three types of table are always reside at the bottom of the shared +// memory and will never be moved or garbage collected +#define BAMBOO_RMSP_SIZE (BAMBOO_SMEM_SIZE * 64) +mspace bamboo_rmsp; +// shared pointer mapping tbl +//volatile struct GCSharedHash * gcsharedptbl; +mgcsharedhashtbl_t * gcsharedptbl; +// remote shared pointer tbls +//struct GCSharedHash * gcrpointertbls[NUMCORES4GC]; +mgcsharedhashtbl_t * gcrpointertbls[NUMCORES4GC]; volatile struct RuntimeHash * gcpointertbl; //struct MGCHash * gcpointertbl; diff --git a/Robust/src/Runtime/multicoreruntime.h b/Robust/src/Runtime/multicoreruntime.h index e806567e..e3a49174 100644 --- a/Robust/src/Runtime/multicoreruntime.h +++ b/Robust/src/Runtime/multicoreruntime.h @@ -209,9 +209,10 @@ typedef enum { GCMOVESTART, // 0xF0 GCMAPREQUEST, // 0xF1 GCMAPINFO, // 0xF2 - GCLOBJREQUEST, // 0xF3 - GCLOBJINFO, // 0xF4 - GCLOBJMAPPING, // 0xF5 + GCMAPTBL, // 0xF3 + GCLOBJREQUEST, // 0xF4 + GCLOBJINFO, // 0xF5 + GCLOBJMAPPING, // 0xF6 #endif MSGEND } MSGTYPE; @@ -292,11 +293,11 @@ struct Queue * totransobjqueue; // queue to hold objs to be transferred #include "multicoregarbage.h" typedef enum { - SMEMLOCAL = 0x0, // 0x0, using local mem only - SMEMFIXED, // 0x1, use local mem in lower address space(1 block only) - // and global mem in higher address space - SMEMMIXED, // 0x2, like FIXED mode but use a threshold to control - SMEMGLOBAL, // 0x3, using global mem only + SMEMLOCAL = 0x0,// 0x0, using local mem only + SMEMFIXED, // 0x1, use local mem in lower address space(1 block only) + // and global mem in higher address space + SMEMMIXED, // 0x2, like FIXED mode but use a threshold to control + SMEMGLOBAL, // 0x3, using global mem only SMEMEND } SMEMSTRATEGY; @@ -314,7 +315,7 @@ struct freeMemItem { struct freeMemList { struct freeMemItem * head; struct freeMemItem * backuplist; // hold removed freeMemItem for reuse; - // only maintain 1 fremmMemItem + // only maintain 1 freemMemItem }; // table recording the number of allocated bytes on each block diff --git a/Robust/src/Runtime/multicoretask.c b/Robust/src/Runtime/multicoretask.c index b70095d0..829ac1d9 100644 --- a/Robust/src/Runtime/multicoretask.c +++ b/Robust/src/Runtime/multicoretask.c @@ -133,10 +133,15 @@ void initruntimedata() { gcsbstarttbl = BAMBOO_BASE_VA; bamboo_smemtbl = (void *)gcsbstarttbl + (BAMBOO_SHARED_MEM_SIZE/BAMBOO_SMEM_SIZE)*sizeof(INTPTR); - // for mapping info structures - gcrcoretbl = allocateRuntimeHash_I(20); - BAMBOO_MEMSET_WH(gcmappingtbl, 0, - sizeof(void *)*NUMCORESACTIVE*NUM_MAPPING); + if(BAMBOO_NUM_OF_CORE < NUMCORES4GC) { + int t_size = ((BAMBOO_RMSP_SIZE)-sizeof(mgcsharedhashtbl_t)*2 + -128*sizeof(size_t))/sizeof(mgcsharedhashlistnode_t)-2; + gcsharedptbl = mgcsharedhashCreate(t_size,0.30);//allocateGCSharedHash_I(20); + } else { + gcsharedptbl = NULL; + } + BAMBOO_MEMSET_WH(gcrpointertbls,0,sizeof(mgcsharedhashtbl_t *)*NUMCORES4GC); + //sizeof(struct RuntimeHash *)*NUMCORES4GC); #else // create the lock table, lockresult table and obj queue locktable.size = 20; @@ -189,7 +194,7 @@ void disruntimedata() { //freeMGCHash(gcpointertbl); freeMGCHash(gcforwardobjtbl); // for mapping info structures - freeRuntimeHash(gcrcoretbl); + //freeRuntimeHash(gcrcoretbl); #else freeRuntimeHash(lockRedirectTbl); freeRuntimeHash(objRedirectLockTbl); @@ -1509,6 +1514,7 @@ INLINE int checkMsgLength_I(int size) { case PROFILEFINISH: #ifdef MULTICORE_GC case GCSTARTCOMPACT: + case GCMARKEDOBJ: case GCFINISHINIT: case GCFINISHMAPINFO: case GCFINISHFLUSH: @@ -1521,9 +1527,9 @@ INLINE int checkMsgLength_I(int size) { case MEMREQUEST: case MEMRESPONSE: #ifdef MULTICORE_GC - case GCMARKEDOBJ: case GCMAPREQUEST: case GCMAPINFO: + case GCMAPTBL: case GCLOBJMAPPING: #endif { @@ -2318,113 +2324,15 @@ INLINE void processmsg_gcmarkreport_I() { INLINE void processmsg_gcmarkedobj_I() { int data1 = msgdata[msgdataindex]; MSG_INDEXINC_I(); - int data2 = msgdata[msgdataindex]; - MSG_INDEXINC_I(); // received a markedObj msg if(((int *)data1)[6] == INIT) { // this is the first time that this object is discovered, // set the flag as DISCOVERED - ((int *)data1)[6] = DISCOVERED; + ((int *)data1)[6] |= DISCOVERED; gc_enqueue_I(data1); - // insert the obj and request core info into mapping hashtable - /*struct requestcoreinfo * coreinfo = - (struct requestcoreinfo *)RUNMALLOC_I(sizeof(struct requestcoreinfo)); - coreinfo->core = data2; - coreinfo->next = NULL; - struct nodemappinginfo * nodeinfo = - (struct nodemappinginfo *)RUNMALLOC_I(sizeof(struct nodemappinginfo)); - nodeinfo->ptr = NULL; - nodeinfo->cores = coreinfo; - RuntimeHashadd_I(gcpointertbl, data1, (int)nodeinfo);*/ - struct rcoreinfo * coreinfo = - (struct rcoreinfo *)RUNMALLOC_I(sizeof(struct rcoreinfo)); - coreinfo->high = coreinfo->low = 0; - if(data2 > 31) { - coreinfo->high |= 1<<(data2-32); - } else { - coreinfo->low |= 1<cores; - if(coreinfo == NULL) { - nodeinfo->cores = - (struct requestcoreinfo *)RUNMALLOC_I( - sizeof(struct requestcoreinfo)); - nodeinfo->cores->core = data2; - nodeinfo->cores->next = NULL; - } else { - while(true) { - if(coreinfo->core == data2) { - break; - } else if ((coreinfo->core > data2) || - (coreinfo->next == NULL)) { - // insert here - struct requestcoreinfo * toinsert = - (struct requestcoreinfo *)RUNMALLOC_I( - sizeof(struct requestcoreinfo)); - if(coreinfo->core > data2) { - toinsert->next = coreinfo->next; - toinsert->core = coreinfo->core; - coreinfo->core = data2; - } else { - toinsert->core = data2; - } - coreinfo->next = toinsert; - break; - } else { - coreinfo = coreinfo->next; - } - } - } - }*/ - struct rcoreinfo * coreinfo = NULL; - RuntimeHashget(gcrcoretbl, data1, &coreinfo); - if(coreinfo == NULL) { - coreinfo = - (struct rcoreinfo *)RUNMALLOC_I(sizeof(struct rcoreinfo)); - coreinfo->high = coreinfo->low = 0; - if(data2 > 31) { - coreinfo->high |= 1<<(data2-32); - } else { - coreinfo->low |= 1< 31) { - if((coreinfo->high)&(1<<(data2-32))==0) { - toadd = true; - coreinfo->high |= 1<<(data2-32); - } - } else { - if((coreinfo->low)&(1<low |= 1<ptr = (void *)data2; - nodeinfo->cores = NULL; - RuntimeHashadd_I(gcpointertbl, data1, (int)nodeinfo);*/ + mgcsharedhashInsert_I(gcsharedptbl, data1, data2); + //GCSharedHashadd_I(gcsharedptbl, data1, data2); //MGCHashadd_I(gcpointertbl, msgdata[1], msgdata[2]); } #endif // #ifdef MULTICORE_GC @@ -2823,7 +2734,13 @@ processmsg: break; } // case GCMAPINFO - case GCLOBJREQUEST: { + case GCMAPTBL: { + // received a mapping tbl response msg + processmsg_gcmaptbl_I(); + break; + } // case GCMAPTBL + + case GCLOBJREQUEST: { // received a large objs info request msg transferMarkResults_I(); break; diff --git a/Robust/src/buildscript b/Robust/src/buildscript index 12a37085..fb03f76a 100755 --- a/Robust/src/buildscript +++ b/Robust/src/buildscript @@ -736,6 +736,7 @@ cp ../Runtime/math.c ./ cp ../Runtime/object.c ./ cp ../Runtime/GenericHashtable.c ./ cp ../Runtime/SimpleHash.c ./ +cp ../Runtime/GCSharedHash.c ./ cp ../Runtime/ObjectHash.c ./ cp ../Runtime/socket.c ./ cp ../Runtime/mem.c ./ @@ -749,6 +750,7 @@ cp ../Runtime/ObjectHash.h ./ cp ../Runtime/Queue.h ./ cp ../Runtime/runtime.h ./ cp ../Runtime/SimpleHash.h ./ +cp ../Runtime/GCSharedHash.h ./ cp ../Runtime/multicoregc.h ./ cp ../Runtime/multicoregarbage.h ./ cp ../Runtime/multicorehelper.h ./ -- 2.34.1