2 #include "multicoregarbage.h"
3 #include "multicoreruntime.h"
4 #include "runtime_arch.h"
5 #include "SimpleHash.h"
6 #include "GenericHashtable.h"
8 extern struct genhashtable * activetasks;
9 extern struct parameterwrapper ** objectqueues[][NUMCLASSES];
10 extern struct taskparamdescriptor *currtpdo;
13 struct largeObjItem * head;
14 struct largeObjItem * tail;
17 struct largeObjList lObjList;
21 void gc_enqueue(void *ptr) {
22 if (gcheadindex==NUMPTRS) {
23 struct pointerblock * tmp;
28 tmp=malloc(sizeof(struct pointerblock));
33 gchead->ptrs[gcheadindex++]=ptr;
36 // dequeue and destroy the queue
38 if (gctailindex==NUMPTRS) {
39 struct pointerblock *tmp=tail;
47 return gctail->ptrs[gctailindex++];
50 // dequeue and do not destroy the queue
51 void * gc_dequeue2() {
52 if (gctailindex2==NUMPTRS) {
53 struct pointerblock *tmp=tail;
54 gctail2=gctail2->next;
57 return gctail2->ptrs[gctailindex2++];
61 if ((gchead==gctail)&&(gctailindex==gcheadindex))
67 if ((gchead==gctail2)&&(gctailindex2==gcheadindex))
72 INTPTR curr_heaptop = 0;
74 bool isLarge(void * ptr, int * ttype, int * tsize) {
75 // check if a pointer is referring to a large object
76 int type = ((int *)ptr)[0];
78 if(type < NUMCLASSES) {
80 size = classsize[type];
83 struct ArrayObject *ao=(struct ArrayObject *)ptr;
84 int elementsize=classsize[type];
85 int length=ao->___length___;
86 size=sizeof(struct ArrayObject)+length*elementsize;
90 return(!isLocal(ptr + size));
93 int hostcore(void * ptr) {
94 // check the host core of ptr
98 RESIDECORE(ptr, &x, &y);
99 host = (x == 0)?(x * bamboo_height + y) : (x * bamboo_height + y - 2);
103 bool isLocal(void * ptr) {
104 // check if a pointer is in shared heap on this core
105 return hostcore(ptr) == BAMBOO_NUM_OF_CORE;
108 void transferMarkResults() {
109 // TODO, need distiguish between send and cache
110 // invoked inside interruptiong handler
113 void checkMarkStatue() {
114 if((!gcwaitconfirm) ||
115 (waitconfirm && (numconfirm == 0))) {
116 BAMBOO_START_CRITICAL_SECTION_STATUS();
117 gccorestatus[BAMBOO_NUM_OF_CORE] = 0;
118 gcnumsendobjs[BAMBOO_NUM_OF_CORE] = gcself_numsendobjs;
119 gcnumreceiveobjs[BAMBOO_NUM_OF_CORE] = gcself_numreceiveobjs;
120 // check the status of all cores
121 bool allStall = true;
122 for(i = 0; i < NUMCORES; ++i) {
123 if(gccorestatus[i] != 0) {
129 // check if the sum of send objs and receive obj are the same
130 // yes->check if the info is the latest; no->go on executing
132 for(i = 0; i < NUMCORES; ++i) {
133 sumsendobj += gcnumsendobjs[i];
135 for(i = 0; i < NUMCORES; ++i) {
136 sumsendobj -= gcnumreceiveobjs[i];
138 if(0 == sumsendobj) {
140 // the first time found all cores stall
141 // send out status confirm msg to all other cores
142 // reset the corestatus array too
143 gccorestatus[BAMBOO_NUM_OF_CORE] = 1;
145 numconfirm = NUMCORES - 1;
146 for(i = 1; i < NUMCORES; ++i) {
148 // send mark phase finish confirm request msg to core i
149 send_msg_1(i, GCMARKCONFIRM);
152 // all the core status info are the latest
154 gcphase = COMPACTPHASE;
155 // restore the gcstatus for all cores
156 for(i = 0; i < NUMCORES; ++i) {
159 } // if(!gcwautconfirm) else()
160 } // if(0 == sumsendobj)
162 BAMBOO_CLOSE_CRITICAL_SECTION_STATUS();
163 } // if((!gcwaitconfirm)...
167 // preparation for gc
168 // make sure to clear all incoming msgs espacially transfer obj msgs
171 (waitconfirm && (numconfirm == 0))) {
172 // send out status confirm msgs to all cores to check if there are
173 // transfer obj msgs on-the-fly
175 numconfirm = NUMCORES - 1;
176 for(i = 1; i < NUMCORES; ++i) {
178 // send status confirm msg to core i
179 send_msg_1(i, STATUSCONFIRM);
182 while(numconfirm != 0) {} // wait for confirmations
183 numsendobjs[BAMBOO_NUM_OF_CORE] = self_numsendobjs;
184 numreceiveobjs[BAMBOO_NUM_OF_CORE] = self_numreceiveobjs;
186 for(i = 0; i < NUMCORES; ++i) {
187 sumsendobj += numsendobjs[i];
189 for(i = 0; i < NUMCORES; ++i) {
190 sumsendobj -= numreceiveobjs[i];
192 if(0 == sumsendobj) {
195 // still have some transfer obj msgs on-the-fly, can not start gc
199 // previously asked for status confirmation and do not have all the
200 // confirmations yet, can not start gc
205 // compute load balance for all cores
207 // compute load balance
208 // initialize the deltas
210 int delta = 1 << 32 -1;
211 int deltanew = 1 << 32 - 1;
215 for(i = 0; i < NUMCORES; i++) {
216 gcdeltal[i] = gcdeltar[i] = 0;
217 gcreloads[i] = gcloads[i];
222 // compute load balance
223 for(i = 0; i < NUMCORES; i++) {
224 if(gcreloads[i] > BAMBOO_SMEM_SIZE_L) {
225 // too much load, try to redirect some of it to its neighbours
226 LEFTNEIGHBOUR(i, &lcore);
227 RIGHTNEIGHBOUR(i, &rcore);
229 int tmp = (gcreloads[lcore] - gcreloads[i]) / 2;
231 gcdeltar[lcore] = 0-tmp;
232 deltanew += abs(gcreloads[lcore] - gcreloads[i]);
235 int tmp = (gcreloads[rcore] - gcreloads[i]) / 2;
237 gcdeltal[rcore] = 0-tmp;
238 deltanew += abs(gcreloads[rcore] - gcreloads[i]);
243 if((deltanew == 0) || (delta == deltanew)) {
246 // flush for new loads
247 for(i = 0; i < NUMCORES; i++) {
248 if((gcdeltal[i] != 0) || (gcdeltar[i] != 0)) {
250 gcreloads[i] += gcdeltal[i] + gcdeltar[i];
251 gcdeltal[i] = gcdeltar[i] = 0;
255 for(i = 0; i < NUMCORES; i++) {
256 gcdeltal[i] = gcdeltar[i] = 0;
258 // decide how to do load balance
259 for(i = 0; i < NUMCORES; i++) {
260 int tomove = (gcloads[i] - gcreloads[i]);
262 LEFTNEIGHBOUR(i, &lcore);
263 RIGHTNEIGHBOUR(i, &rcore);
267 lmove = (gcreloads[lcore] - gcloads[lcore] - gcdeltal[lcore]);
273 rmove = (gcreloads[rcore] - gcloads[rcore] - gcdeltar[rcore]);
278 // the one with bigger gap has higher priority
280 int ltomove = (lmove > tomove)? tomove:lmove;
281 gcdeltar[lcore] = ltomove;
282 gcdeltal[i] = 0-ltomove;
283 gcdeltal[rcore] = tomove - ltomove;
284 gcdeltar[i] = ltomove - tomove;
286 int rtomove = (rmove > tomove)? tomove:rmove;
287 gcdeltal[rcore] = rtomove;
288 gcdeltar[i] = 0-rtomove;
289 gcdeltar[lcore] = tomove - rtomove;
290 gcdeltal[i] = rtomove - tomove;
296 void gc(struct garbagelist * stackptr) {
302 // core coordinator routine
303 if(0 == BAMBOO_NUM_OF_CORE) {
305 // not ready to do gc
311 gcwaitconfirm = false;
314 for(i = 1; i < NUMCORES - 1; i++) {
315 // send GC start messages to all cores
316 send_msg_1(i, GCSTART);
319 bool allStall = false;
322 while(MARKPHASE == gcphase) {
323 mark(isfirst, stackptr);
330 } // while(MARKPHASE == gcphase)
331 // send msgs to all cores requiring large objs info
332 numconfirm = NUMCORES - 1;
333 for(i = 1; i < NUMCORES; ++i) {
334 send_msg_1(i, GCLOBJREQUEST);
336 while(numconfirm != 0) {} // wait for responses
338 // TODO need to decide where to put large objects
340 // TODO cache all large objects
342 for(i = 1; i < NUMCORES; ++i) {
343 //TODO send start compact messages to all cores
349 gccorestatus[BAMBOO_NUM_OF_CORE] = 0;
350 while(COMPACTPHASE == gcphase) {
351 // check the status of all cores
353 for(i = 0; i < NUMCORES; ++i) {
354 if(gccorestatus[i] != 0) {
360 // restore the gcstatus of all cores
361 for(i = 0; i < NUMCORES; ++i) {
366 } // while(COMPACTPHASE == gcphase)
367 // TODO merge all mapping information
369 gcphase = FLUSHPHASE;
370 for(i = 1; i < NUMCORES; ++i) {
371 // send start flush messages to all cores
372 send_msg_1(i, GCSTARTFLUSH);
377 gccorestatus[BAMBOO_NUM_OF_CORE] = 0;
378 while(FLUSHPHASE == gcphase) {
379 // check the status of all cores
381 for(i = 0; i < NUMCORES; ++i) {
382 if(gccorestatus[i] != 0) {
390 } // while(FLUSHPHASE == gcphase)
391 gcphase = FINISHPHASE;
392 for(i = 1; i < NUMCORES; ++i) {
393 // send gc finish messages to all cores
394 send_msg_1(i, GCFINISH);
398 gc_collect(stackptr);
404 void tomark(struct garbagelist * stackptr) {
405 if(MARKPHASE != gcphase) {
414 gchead=gctail=gctail2=malloc(sizeof(struct pointerblock));
417 // enqueue current stack
418 while(stackptr!=NULL) {
419 for(i=0; i<stackptr->size; i++) {
420 gc_enqueue(stackptr->array[i]);
422 stackptr=stackptr->next;
424 // enqueue objectsets
425 for(i=0; i<NUMCLASSES; i++) {
426 struct parameterwrapper ** queues=objectqueues[BAMBOO_NUM_OF_CORE][i];
427 int length = numqueues[BAMBOO_NUM_OF_CORE][i];
428 for(j = 0; j < length; ++j) {
429 struct parameterwrapper * parameter = queues[j];
430 struct ObjectHash * set=parameter->objectset;
431 struct ObjectNode * ptr=set->listhead;
433 gc_enqueue((void *)ptr->key);
438 // euqueue current task descriptor
439 for(i=0; i<currtpd->numParameters; i++) {
440 gc_enqueue(currtpd->parameterArray[i]);
442 // euqueue active tasks
443 struct genpointerlist * ptr=activetasks->list;
445 struct taskparamdescriptor *tpd=ptr->src;
447 for(i=0; i<tpd->numParameters; i++) {
448 gc_enqueue(tpd->parameterArray[i]);
452 // enqueue cached transferred obj
453 struct QueueItem * tmpobjptr = getHead(&objqueue);
454 while(tmpobjptr != NULL) {
455 struct transObjInfo * objInfo = (struct transObjInfo *)(tmpobjptr->objectptr);
456 gc_enqueue(objInfo->objptr);
457 getNextQueueItem(tmpobjptr);
461 void mark(bool isfirst, struct garbagelist * stackptr) {
468 while(MARKPHASE == gcphase) {
469 while(gc_moreItems2()) {
470 voit * ptr = gc_dequeue2();
473 if(isLarge(ptr, &type, &size)) {
474 // ptr is a large object
475 struct largeObjItem * loi =
476 (struct largeObjItem *)RUNMALLOC(sizeof(struct largeObjItem));
477 loi->orig = (INTPTR)ptr;
478 loi->dst = (INTPTR)0;
480 if(lObjList.head == NULL) {
481 lObjList.head = lObjList.tail = loi;
483 lObjList.tail->next = loi;
486 } else if (isLocal(ptr)) {
487 // ptr is an active object on this core
491 curr_heaptop += size;
495 // scan all pointers in ptr
496 unsigned INTPTR * pointer;
497 pointer=pointerarray[type];
499 /* Array of primitives */
501 } else if (((INTPTR)pointer)==1) {
502 /* Array of pointers */
503 struct ArrayObject *ao=(struct ArrayObject *) ptr;
504 int length=ao->___length___;
506 for(j=0; j<length; j++) {
507 void *objptr=((void **)(((char *)&ao->___length___)+sizeof(int)))[j];
508 int host = hostcore(objptr);
509 if(BAMBOO_NUM_OF_CORE == host) {
513 // send a msg to host informing that objptr is active
514 send_msg_2(host, GCMARKEDOBJ, objptr);
515 gcself_numsendobjs++;
519 INTPTR size=pointer[0];
521 for(i=1; i<=size; i++) {
522 unsigned int offset=pointer[i];
523 void * objptr=*((void **)(((char *)ptr)+offset));
524 int host = hostcore(objptr);
525 if(BAMBOO_NUM_OF_CORE == host) {
529 // send a msg to host informing that objptr is active
530 send_msg_2(host, GCMARKEDOBJ, objptr);
531 gcself_numsendobjs++;
535 } // while(!isEmpty(gctomark))
536 gcbusystatus = false;
537 // send mark finish msg to core coordinator
538 send_msg_4(STARTUPCORE, GCFINISHMARK, BAMBOO_NUM_OF_CORE,
539 gcself_numsendobjs, gcself_numreceiveobjs);
541 if(BAMBOO_NUM_OF_CORE == 0) {
544 } // while(MARKPHASE == gcphase)
548 if(COMPACTPHASE != gcphase) {
552 struct markedObjItem * moi = mObjList.head;
555 if((cinstruction == NULL) || (cinstruction->tomoveobjs == NULL)
556 || (curr_heaptop < cinstruction->tomoveobjs->starts[0])) {
558 int type = ((int *)(moi->orig))[0];
563 if(type < NUMCLASSES) {
565 size = classsize[type];
566 moi->dst = curr_heaptop;
567 curr_heaptop += size;
569 memcpy(moi->dst, moi->orig, size);
570 genputtable(pointertbl, moi->orig, moi->dst);
574 struct ArrayObject *ao=(struct ArrayObject *)ptr;
575 int elementsize=classsize[type];
576 int length=ao->___length___;
577 size=sizeof(struct ArrayObject)+length*elementsize;
578 moi->dst = curr_heaptop;
579 curr_heaptop += size;
581 memcpy(moi->dst, moi->orig, size);
582 genputtable(pointertbl, moi->orig, moi->dst);
589 } // while(moi != NULL)
591 if(cinstruction->incomingobjs != NULL) {
592 for(int j = 0; j < cinstruction->incomingobjs->length; j++) {
593 // send messages to corresponding cores to start moving
594 send_msg_2(cinstruction->incomingobjs->dsts[j], GCMOVESTART,
599 int num_dsts = cinstruction->tomoveobjs->length;
600 while(num_dsts > 0) {
602 // start moving objects to other cores
604 while(!isEmpty(gcdsts)) {
605 int dst = (int)(getItem(gcdsts));
608 for(j = 0; j < cinstruction->tomoveobjs->length; j++) {
609 if(dst == cinstruction->tomoveobjs->dsts[j]) {
613 INTPTR top = cinstruction->tomoveobjs->dststarts[j];
614 INTPTR start = cinstruction->tomoveobjs->starts[j];
615 INTPTR end = cinstruction->tomoveobjs->ends[j];
616 struct markedObjItem * tomove = getStartItem(moi, start);
618 int type = ((int *)(tomove->orig))[0];
623 if(type < NUMCLASSES) {
625 size = classsize[type];
628 memcpy(moi->dst, moi->orig, size);
629 genputtable(pointertbl, moi->orig, moi->dst);
632 struct ArrayObject *ao=(struct ArrayObject *)ptr;
633 int elementsize=classsize[type];
634 int length=ao->___length___;
635 size=sizeof(struct ArrayObject)+length*elementsize;
638 memcpy(moi->dst, moi->orig, size);
639 genputtable(pointertbl, moi->orig, moi->dst);
641 tomove = tomove->next;
642 } while(tomove->orig < end);
643 } // while(!isEmpty(gcdsts))
644 } // while(num_dsts > 0)
645 } // if(moi == NULL) else()
646 if((cinstruction != NULL) && (cinstruction->largeobjs != NULL)) {
647 // move all large objects
649 // dequeue the first large obj
650 struct largeObjItem * loi = cinstruction->largeobjs;
651 cinstruction->largeobjs = loi->next;
652 // move this large obj
653 memcpy(loi->dst, loi->orig, loi->length);
654 genputtable(pointertbl, loi->orig, loi->dst);
656 }while(cinstruction->largeobjs != NULL);
658 // send compact finish message to core coordinator
659 send_msg_2(STARTUPCORE, GCFINISHCOMPACT, BAMBOO_NUM_OF_CORE);
664 struct markedObjItem * moi = mObjList.head;
666 void * ptr = moi->dst;
667 int type = ((int *)(ptr))[0];
668 // scan all pointers in ptr
669 unsigned INTPTR * pointer;
670 pointer=pointerarray[type];
672 /* Array of primitives */
674 } else if (((INTPTR)pointer)==1) {
675 /* Array of pointers */
676 struct ArrayObject *ao=(struct ArrayObject *) ptr;
677 int length=ao->___length___;
679 for(j=0; j<length; j++) {
680 void *objptr=((void **)(((char *)&ao->___length___)+sizeof(int)))[j];
681 // change to new address
682 void *dstptr = gengettable(pointertbl, objptr);
684 // send msg to host core for the mapping info
685 obj2map = (int)objptr;
688 send_msg_3(hostcore(objptr), GCMAPREQUEST, (int)objptr,
693 ((void **)(((char *)&ao->___length___)+sizeof(int)))[j] = dstptr;
696 INTPTR size=pointer[0];
698 for(i=1; i<=size; i++) {
699 unsigned int offset=pointer[i];
700 void * objptr=*((void **)(((char *)ptr)+offset));
701 // change to new address
702 void *dstptr = gengettable(pointertbl, objptr);
704 // send msg to host core for the mapping info
705 obj2map = (int)objptr;
708 send_msg_3(hostcore(objptr), GCMAPREQUEST, (int)objptr,
713 *((void **)(((char *)ptr)+offset)) = dstptr;
717 } // while(moi != NULL)
718 // send flush finish message to core coordinator
719 send_msg_2(STARTUPCORE, GCFINISHFLUSH, BAMBOO_NUM_OF_CORE);
723 void gc_collect(struct garbagelist * stackptr) {
724 // core collector routine
725 mark(true, stackptr);
727 while(FLUSHPHASE != gcphase) {}
731 if(FINISHPHASE == gcphase) {