2 #include "multicoregccompact.h"
3 #include "runtime_arch.h"
4 #include "multicoreruntime.h"
5 #include "multicoregarbage.h"
7 INLINE bool gc_checkCoreStatus() {
8 BAMBOO_ENTER_RUNTIME_MODE_FROM_CLIENT();
9 for(int i = 0; i < NUMCORES4GC; ++i) {
10 if(gccorestatus[i] != 0) {
11 BAMBOO_ENTER_CLIENT_MODE_FROM_RUNTIME();
15 BAMBOO_ENTER_CLIENT_MODE_FROM_RUNTIME();
19 INLINE void gc_resetCoreStatus() {
20 BAMBOO_ENTER_RUNTIME_MODE_FROM_CLIENT();
21 for(int i = 0; i < NUMCORES4GC; ++i) {
24 BAMBOO_ENTER_CLIENT_MODE_FROM_RUNTIME();
27 // should be invoked with interrupt closed
28 INLINE int assignSpareMem_I(unsigned int sourcecore,unsigned int * requiredmem, void ** tomove, void ** startaddr) {
30 BLOCKINDEX(topptrs[sourcecore], b);
31 void * boundptr = BOUNDPTR(b);
32 unsigned INTPTR remain = (unsigned INTPTR) (boundptr - topptrs[sourcecore]);
33 unsigned int memneed = requiredmem + BAMBOO_CACHE_LINE_SIZE;
34 *startaddr = topptrs[sourcecore];
35 *tomove = gcfilledblocks[sourcecore] + 1;
36 if(memneed < remain) {
37 topptrs[sourcecore] += memneed;
40 // next available block
41 gcfilledblocks[sourcecore] += 1;
42 void * newbase = NULL;
43 BASEPTR(sourcecore, gcfilledblocks[sourcecore], &newbase);
44 topptrs[sourcecore] = newbase;
45 return requiredmem-remain;
49 INLINE int assignSpareMem(unsigned int sourcecore,unsigned int * requiredmem,unsigned int * tomove, void ** startaddr) {
50 BAMBOO_ENTER_RUNTIME_MODE_FROM_CLIENT();
51 int retval=assignSpareMem_I(sourcecore, requiredmem, tomove, startaddr);
52 BAMBOO_ENTER_CLIENT_MODE_FROM_RUNTIME();
56 INLINE void compact2Heaptophelper_I(unsigned int coren, void ** p,unsigned int* numblocks,unsigned int* remain) {
58 unsigned int memneed = gcrequiredmems[coren] + BAMBOO_CACHE_LINE_SIZE;
59 if(STARTUPCORE == coren) {
62 gcdstcore = gctopcore;
63 gcblock2fill = *numblocks + 1;
65 if(BAMBOO_CHECK_SEND_MODE()) {
66 cache_msg_4_I(coren,GCMOVESTART,gctopcore,*p,(*numblocks)+1);
68 send_msg_4_I(coren,GCMOVESTART,gctopcore,*p,(*numblocks)+1);
71 if(memneed < *remain) {
73 gcrequiredmems[coren] = 0;
74 topptrs[gctopcore] += memneed;
75 *remain = *remain - memneed;
77 // next available block
79 gcfilledblocks[gctopcore] += 1;
80 void * newbase = NULL;
81 BASEPTR(gctopcore, gcfilledblocks[gctopcore], &newbase);
82 topptrs[gctopcore] = newbase;
83 gcrequiredmems[coren] -= *remain - BAMBOO_CACHE_LINE_SIZE;
84 gcstopblock[gctopcore]++;
85 gctopcore = NEXTTOPCORE(gctopblock);
87 *numblocks = gcstopblock[gctopcore];
88 *p = topptrs[gctopcore];
90 *remain=GC_BLOCK_REMAIN_SIZE(b, (*p));
95 INLINE void compact2Heaptop() {
96 // no cores with spare mem and some cores are blocked with pending move
97 // find the current heap top and make them move to the heap top
98 void * p = topptrs[gctopcore];
99 unsigned int numblocks = gcfilledblocks[gctopcore];
102 unsigned int remain=GC_BLOCK_REMAIN_SIZE(b, p);
103 // check if the top core finishes
104 BAMBOO_ENTER_RUNTIME_MODE_FROM_CLIENT();
105 if(gccorestatus[gctopcore] != 0) {
106 // let the top core finishes its own work first
107 compact2Heaptophelper_I(gctopcore, &p, &numblocks, &remain);
108 BAMBOO_ENTER_CLIENT_MODE_FROM_RUNTIME();
111 BAMBOO_ENTER_CLIENT_MODE_FROM_RUNTIME();
113 for(int i = 0; i < NUMCORES4GC; i++) {
114 BAMBOO_ENTER_RUNTIME_MODE_FROM_CLIENT();
115 if((gccorestatus[i] != 0) && (gcrequiredmems[i] > 0)) {
116 compact2Heaptophelper_I(i, &p, &numblocks, &remain);
117 if(gccorestatus[gctopcore] != 0) {
118 BAMBOO_ENTER_CLIENT_MODE_FROM_RUNTIME();
119 // the top core is not free now
123 BAMBOO_ENTER_CLIENT_MODE_FROM_RUNTIME();
127 INLINE void resolvePendingMoveRequest() {
130 bool nosparemem = true;
131 bool haspending = false;
132 bool hasrunning = false;
133 bool noblock = false;
134 unsigned int dstcore = 0; // the core who need spare mem
135 unsigned int sourcecore = 0; // the core who has spare mem
136 for(i = j = 0; (i < NUMCORES4GC) && (j < NUMCORES4GC); ) {
138 // check if there are cores with spare mem
139 if(gccorestatus[i] == 0) {
140 // finished working, check if it still have spare mem
141 if(gcfilledblocks[i] < gcstopblock[i]) {
142 // still have spare mem
150 if(gccorestatus[j] != 0) {
151 // not finished, check if it has pending move requests
152 if((gcfilledblocks[j]==gcstopblock[j])&&(gcrequiredmems[j]>0)) {
161 if(!nosparemem && haspending) {
163 unsigned int tomove = 0;
164 unsigned int startaddr = 0;
165 gcrequiredmems[dstcore] = assignSpareMem(sourcecore,gcrequiredmems[dstcore],&tomove,&startaddr);
166 if(STARTUPCORE == dstcore) {
167 gcdstcore = sourcecore;
169 gcmovestartaddr = startaddr;
170 gcblock2fill = tomove;
172 send_msg_4(dstcore,GCMOVESTART,sourcecore,startaddr,tomove);
181 if(!hasrunning && !noblock) {
182 gc_status_info.gcphase = SUBTLECOMPACTPHASE;
187 // If out of boundary of valid shared memory, return false, else return true
188 INLINE bool nextSBlock(struct moveHelper * orig) {
189 orig->blockbase = orig->blockbound;
191 bool sbchanged = false;
192 unsigned int origptr = orig->ptr;
193 unsigned int blockbase = orig->blockbase;
194 unsigned int blockbound = orig->blockbound;
195 unsigned int bound = orig->bound;
197 // check if across a big block
198 // TODO now do not zero out the whole memory, maybe the last two conditions
200 if((blockbase>=bound)||(origptr>=bound)||((origptr!=NULL)&&(*((int*)origptr))==0)||((*((int*)blockbase))==0)) {
202 // end of current heap block, jump to next one
204 BASEPTR(BAMBOO_NUM_OF_CORE, orig->numblocks, &(orig->base));
205 if(orig->base >= gcbaseva + BAMBOO_SHARED_MEM_SIZE) {
207 orig->ptr = orig->base; // set current ptr to out of boundary too
210 orig->blockbase = orig->base;
211 orig->sblockindex=(unsigned int)(orig->blockbase-gcbaseva)/BAMBOO_SMEM_SIZE;
213 unsigned int blocknum = 0;
214 BLOCKINDEX(orig->base, blocknum);
215 if(bamboo_smemtbl[blocknum] == 0) {
217 goto innernextSBlock;
219 // check the bamboo_smemtbl to decide the real bound
220 orig->bound = orig->base + bamboo_smemtbl[blocknum];
221 } else if(0 == ((unsigned INTPTR)orig->blockbase)%BAMBOO_SMEM_SIZE) {
222 orig->sblockindex += 1;
226 // check if this sblock should be skipped or have special start point
227 int sbstart = gcsbstarttbl[orig->sblockindex];
230 orig->sblockindex += 1;
231 orig->blockbase += BAMBOO_SMEM_SIZE;
232 goto outernextSBlock;
233 } else if((sbstart != 0) && (sbchanged)) {
234 // the first time to access this SBlock
235 // not start from the very beginning
236 orig->blockbase = sbstart;
239 // setup information for this sblock
240 orig->blockbound = orig->blockbase+(unsigned int)*((int*)(orig->blockbase));
241 orig->offset = BAMBOO_CACHE_LINE_SIZE;
242 orig->ptr = orig->blockbase + orig->offset;
243 if(orig->ptr >= orig->bound) {
244 // met a lobj, move to next block
245 goto innernextSBlock;
251 // return false if there are no available data to compact
252 INLINE bool initOrig_Dst(struct moveHelper * orig,struct moveHelper * to) {
255 to->top = to->offset = BAMBOO_CACHE_LINE_SIZE;
256 to->bound = BAMBOO_SMEM_SIZE_L;
257 BASEPTR(BAMBOO_NUM_OF_CORE, to->numblocks, &(to->base));
259 void * tobase = to->base;
260 to->ptr = tobase + to->offset;
265 unsigned int blocknum = 0;
266 BLOCKINDEX(orig->base, blocknum);
267 void * origbase = orig->base;
268 // check the bamboo_smemtbl to decide the real bound
269 orig->bound = origbase + (unsigned INTPTR)bamboo_smemtbl[blocknum];
270 orig->blockbase = origbase;
271 orig->sblockindex = (unsigned INTPTR)(origbase - gcbaseva) / BAMBOO_SMEM_SIZE;
273 int sbstart = gcsbstarttbl[orig->sblockindex];
276 orig->blockbound=gcbaseva+BAMBOO_SMEM_SIZE*(orig->sblockindex+1);
277 return nextSBlock(orig);
278 } else if(sbstart != 0) {
279 orig->blockbase = sbstart;
281 orig->blockbound = orig->blockbase + *((int*)(orig->blockbase));
282 orig->offset = BAMBOO_CACHE_LINE_SIZE;
283 orig->ptr = orig->blockbase + orig->offset;
288 INLINE void nextBlock(struct moveHelper * to) {
289 to->top = to->bound + BAMBOO_CACHE_LINE_SIZE; // header!
290 to->bound += BAMBOO_SMEM_SIZE;
292 BASEPTR(BAMBOO_NUM_OF_CORE, to->numblocks, &(to->base));
293 to->offset = BAMBOO_CACHE_LINE_SIZE;
294 to->ptr = to->base + to->offset;
297 INLINE unsigned int findValidObj(struct moveHelper * orig,struct moveHelper * to,int * type) {
298 unsigned int size = 0;
300 CACHEADAPT_COMPLETE_PAGE_CONVERT(orig, to, to->ptr, false);
301 unsigned int origptr = (unsigned int)(orig->ptr);
302 unsigned int origbound = (unsigned int)orig->bound;
303 unsigned int origblockbound = (unsigned int)orig->blockbound;
304 if((origptr >= origbound) || (origptr == origblockbound)) {
305 if(!nextSBlock(orig)) {
306 // finished, no more data
311 // check the obj's type, size and mark flag
312 *type = ((int *)(origptr))[0];
315 // end of this block, go to next one
316 if(!nextSBlock(orig)) {
317 // finished, no more data
321 } else if(*type < NUMCLASSES) {
323 size = classsize[*type];
326 struct ArrayObject *ao=(struct ArrayObject *)(origptr);
327 unsigned int elementsize=classsize[*type];
328 unsigned int length=ao->___length___;
329 size=(unsigned int)sizeof(struct ArrayObject)+(unsigned int)(length*elementsize);
335 // endaddr does not contain spaces for headers
336 INLINE bool moveobj(struct moveHelper * orig, struct moveHelper * to, unsigned int stopblock) {
342 unsigned int size = findValidObj(orig, to, &type);
343 unsigned int isize = 0;
346 // finished, no more data
349 ALIGNSIZE(size, &isize); // no matter is the obj marked or not
350 // should be able to across
351 void * origptr = orig->ptr;
353 GETMARKED(markedstatus, origptr);
355 if(markedstatus==MARKEDFIRST) {
356 unsigned int totop = (unsigned int)to->top;
357 unsigned int tobound = (unsigned int)to->bound;
358 BAMBOO_ASSERT(totop<=tobound);
359 GCPROFILE_RECORD_LIVE_OBJ();
360 // marked obj, copy it to current heap top
361 // check to see if remaining space is enough
362 if((unsigned int)(totop + isize) > tobound) {
363 // fill 0 indicating the end of this block
364 BAMBOO_MEMSET_WH(to->ptr, '\0', tobound - totop);
365 // fill the header of this block and then go to next block
366 to->offset += tobound - totop;
367 CLOSEBLOCK(to->base, to->offset);
368 #ifdef GC_CACHE_ADAPT
369 void * tmp_ptr = to->ptr;
372 if((to->top+isize)>(to->bound)) tprintf("%x, %x, %d, %d, %d, %d \n", to->ptr, orig->ptr, to->top, to->bound, isize, size);
373 BAMBOO_ASSERT((to->top+isize)<=(to->bound));
374 #ifdef GC_CACHE_ADAPT
375 CACHEADAPT_COMPLETE_PAGE_CONVERT(orig, to, tmp_ptr, true);
377 if(stopblock == to->numblocks) {
378 // already fulfilled the block
382 BAMBOO_ASSERT((to->top+isize)<=(to->bound));
383 // set the mark field to 2, indicating that this obj has been moved
384 // and need to be flushed
385 void * toptr = to->ptr;
386 if(toptr != origptr) {
387 if((unsigned int)(origptr) < (unsigned int)(toptr+size)) {
388 memmove(toptr, origptr, size);
390 memcpy(toptr, origptr, size);
392 // fill the remaining space with -2
393 BAMBOO_MEMSET_WH((unsigned int)(toptr+size), -2, isize-size);
395 // store mapping info
396 gcmappingtbl[OBJMAPPINGINDEX(origptr)]=(unsigned int)toptr;
397 gccurr_heaptop -= isize;
401 BAMBOO_ASSERT((to->top)<=(to->bound));
402 #ifdef GC_CACHE_ADAPT
403 void * tmp_ptr = to->ptr;
404 #endif // GC_CACHE_ADAPT
405 if(to->top == to->bound) {
406 CLOSEBLOCK(to->base, to->offset);
409 #ifdef GC_CACHE_ADAPT
410 CACHEADAPT_COMPLETE_PAGE_CONVERT(orig, to, tmp_ptr, true);
417 return ((((unsigned int)(orig->ptr) > (unsigned int)(orig->bound))||((unsigned int)(orig->ptr) == (unsigned int)(orig->blockbound)))&&!nextSBlock(orig));
420 // should be invoked with interrupt closed
421 bool gcfindSpareMem_I(unsigned int * startaddr,unsigned int * tomove,unsigned int * dstcore,unsigned int requiredmem,unsigned int requiredcore) {
422 for(int k = 0; k < NUMCORES4GC; k++) {
423 if((gccorestatus[k] == 0) && (gcfilledblocks[k] < gcstopblock[k])) {
424 // check if this stopped core has enough mem
425 assignSpareMem_I(k, requiredmem, tomove, startaddr);
430 // if can not find spare mem right now, hold the request
431 gcrequiredmems[requiredcore] = requiredmem;
436 bool gcfindSpareMem(unsigned int * startaddr,unsigned int * tomove,unsigned int * dstcore,unsigned int requiredmem,unsigned int requiredcore) {
437 BAMBOO_ENTER_RUNTIME_MODE_FROM_CLIENT();
438 bool retval=gcfindSpareMem_I(startaddr, tomove, dstcore, requiredmem, requiredcore);
439 BAMBOO_ENTER_CLIENT_MODE_FROM_RUNTIME();
443 bool compacthelper(struct moveHelper * orig,struct moveHelper * to,int * filledblocks, void ** heaptopptr,bool * localcompact, bool lbmove) {
444 bool loadbalancemove = lbmove;
445 // scan over all objs in this block, compact the marked objs
446 // loop stop when finishing either scanning all active objs or
447 // fulfilled the gcstopblock
449 while((unsigned int)(orig->ptr) < (unsigned int)gcmarkedptrbound) {
450 if(moveobj(orig, to, gcblock2fill)) {
454 CACHEADAPT_SAMPLING_DATA_CONVERT(to->ptr);
455 // if no objs have been compact, do nothing,
456 // otherwise, fill the header of this block
457 if(to->offset > (unsigned int)BAMBOO_CACHE_LINE_SIZE) {
458 CLOSEBLOCK(to->base, to->offset);
462 to->top -= BAMBOO_CACHE_LINE_SIZE;
465 *heaptopptr = to->ptr;
466 *filledblocks = to->numblocks;
469 // send msgs to core coordinator indicating that the compact is finishing
470 // send compact finish message to core coordinator
471 if(STARTUPCORE == BAMBOO_NUM_OF_CORE) {
472 gcfilledblocks[BAMBOO_NUM_OF_CORE] = *filledblocks;
473 topptrs[BAMBOO_NUM_OF_CORE] = *heaptopptr;
474 //tprintf("--finish compact: %d, %d, %d, %x, %x \n", BAMBOO_NUM_OF_CORE, loadbalancemove, *filledblocks, *heaptopptr, gccurr_heaptop);
475 if((unsigned int)(orig->ptr) < (unsigned int)gcmarkedptrbound) {
478 if(gcfindSpareMem(&gcmovestartaddr,&gcblock2fill,&gcdstcore,gccurr_heaptop,BAMBOO_NUM_OF_CORE)) {
484 gccorestatus[BAMBOO_NUM_OF_CORE] = 0;
486 // write back to the Main Memory and release any DTLB entry for the
487 // last block as someone else might later write into it
488 // flush the shared heap
489 //BAMBOO_CACHE_FLUSH_L2();
493 if((unsigned int)(orig->ptr) < (unsigned int)gcmarkedptrbound) {
496 send_msg_6(STARTUPCORE,GCFINISHCOMPACT,BAMBOO_NUM_OF_CORE,loadbalancemove,*filledblocks,*heaptopptr,gccurr_heaptop);
499 send_msg_6(STARTUPCORE,GCFINISHCOMPACT,BAMBOO_NUM_OF_CORE,loadbalancemove,*filledblocks,*heaptopptr, 0);
500 // write back to the Main Memory and release any DTLB entry for the
501 // last block as someone else might later write into it.
502 // flush the shared heap
506 if(orig->ptr < gcmarkedptrbound) {
507 // still have unpacked obj
510 loadbalancemove = true;
513 to->ptr = gcmovestartaddr;
514 to->numblocks = gcblock2fill - 1;
515 to->bound = BLOCKBOUND(to->numblocks);
516 BASEPTR(gcdstcore, to->numblocks, &(to->base));
517 to->offset = to->ptr - to->base;
518 to->top=(to->numblocks==0)?(to->offset):(to->bound-BAMBOO_SMEM_SIZE+to->offset);
520 to->offset = BAMBOO_CACHE_LINE_SIZE;
521 to->ptr += to->offset; // for header
522 to->top += to->offset;
523 *localcompact = (gcdstcore == BAMBOO_NUM_OF_CORE);
524 CACHEADAPT_SAMPLING_DATA_REVISE_INIT(orig, to);
531 BAMBOO_ASSERT(COMPACTPHASE == gc_status_info.gcphase);
534 // initialize pointers for comapcting
535 struct moveHelper * orig = (struct moveHelper *)RUNMALLOC(sizeof(struct moveHelper));
536 struct moveHelper * to = (struct moveHelper *)RUNMALLOC(sizeof(struct moveHelper));
537 if(!initOrig_Dst(orig, to)) {
538 // no available data to compact
539 // send compact finish msg to STARTUP core
540 send_msg_6(STARTUPCORE,GCFINISHCOMPACT,BAMBOO_NUM_OF_CORE,false,0,to->base,0);
544 CACHEADAPT_SAMPLING_DATA_REVISE_INIT(orig, to);
546 unsigned int filledblocks = 0;
547 void * heaptopptr = NULL;
548 bool localcompact = true;
549 compacthelper(orig, to, &filledblocks, &heaptopptr, &localcompact, false);
555 void compact_master(struct moveHelper * orig, struct moveHelper * to) {
556 // initialize pointers for comapcting
557 initOrig_Dst(orig, to);
558 CACHEADAPT_SAMPLING_DATA_REVISE_INIT(orig, to);
559 int filledblocks = 0;
560 void * heaptopptr = NULL;
561 bool finishcompact = false;
562 bool iscontinue = true;
563 bool localcompact = true;
565 while((COMPACTPHASE == gc_status_info.gcphase) || (SUBTLECOMPACTPHASE == gc_status_info.gcphase)) {
566 if((!finishcompact) && iscontinue) {
567 finishcompact = compacthelper(orig,to,&filledblocks,&heaptopptr,&localcompact, lbmove);
570 if(gc_checkCoreStatus()) {
571 // all cores have finished compacting restore the gcstatus of all cores
572 gc_resetCoreStatus();
575 // check if there are spare mem for pending move requires
576 if(COMPACTPHASE == gc_status_info.gcphase) {
577 resolvePendingMoveRequest();
585 to->ptr = gcmovestartaddr;
586 to->numblocks = gcblock2fill - 1;
587 to->bound = BLOCKBOUND(to->numblocks);
588 BASEPTR(gcdstcore, to->numblocks, &(to->base));
589 to->offset = to->ptr - to->base;
590 to->top = (to->numblocks==0)?(to->offset):(to->bound-BAMBOO_SMEM_SIZE+to->offset);
592 to->offset = BAMBOO_CACHE_LINE_SIZE;
593 to->ptr += to->offset; // for header
594 to->top += to->offset;
595 localcompact = (gcdstcore == BAMBOO_NUM_OF_CORE);
599 } else if(!finishcompact) {
607 #endif // MULTICORE_GC