2 #include "multicoregccompact.h"
3 #include "runtime_arch.h"
4 #include "multicoreruntime.h"
8 INLINE bool gc_checkCoreStatus() {
9 BAMBOO_ENTER_RUNTIME_MODE_FROM_CLIENT();
10 for(int i = 0; i < NUMCORES4GC; ++i) {
11 if(gccorestatus[i] != 0) {
12 BAMBOO_ENTER_CLIENT_MODE_FROM_RUNTIME();
16 BAMBOO_ENTER_CLIENT_MODE_FROM_RUNTIME();
20 INLINE void gc_resetCoreStatus() {
21 BAMBOO_ENTER_RUNTIME_MODE_FROM_CLIENT();
22 for(int i = 0; i < NUMCORES4GC; ++i) {
25 BAMBOO_ENTER_CLIENT_MODE_FROM_RUNTIME();
28 // should be invoked with interrupt closed
29 int assignSpareMem_I(unsigned int sourcecore,
30 unsigned int * requiredmem,
31 unsigned int * tomove,
32 unsigned int * startaddr) {
34 BLOCKINDEX(gcloads[sourcecore], &b);
35 unsigned int boundptr = (b<NUMCORES4GC) ? ((b+1)*BAMBOO_SMEM_SIZE_L)
36 : (BAMBOO_LARGE_SMEM_BOUND+(b-NUMCORES4GC+1)*BAMBOO_SMEM_SIZE);
37 unsigned int remain = boundptr - gcloads[sourcecore];
38 unsigned int memneed = requiredmem + BAMBOO_CACHE_LINE_SIZE;
39 *startaddr = gcloads[sourcecore];
40 *tomove = gcfilledblocks[sourcecore] + 1;
41 if(memneed < remain) {
42 gcloads[sourcecore] += memneed;
45 // next available block
46 gcfilledblocks[sourcecore] += 1;
47 unsigned int newbase = 0;
48 BASEPTR(sourcecore, gcfilledblocks[sourcecore], &newbase);
49 gcloads[sourcecore] = newbase;
50 return requiredmem-remain;
54 int assignSpareMem(unsigned int sourcecore,
55 unsigned int * requiredmem,
56 unsigned int * tomove,
57 unsigned int * startaddr) {
58 BAMBOO_ENTER_RUNTIME_MODE_FROM_CLIENT();
60 BLOCKINDEX(gcloads[sourcecore], &b);
61 unsigned int boundptr = (b<NUMCORES4GC) ? ((b+1)*BAMBOO_SMEM_SIZE_L)
62 : (BAMBOO_LARGE_SMEM_BOUND+(b-NUMCORES4GC+1)*BAMBOO_SMEM_SIZE);
63 unsigned int remain = boundptr - gcloads[sourcecore];
64 unsigned int memneed = requiredmem + BAMBOO_CACHE_LINE_SIZE;
65 *startaddr = gcloads[sourcecore];
66 *tomove = gcfilledblocks[sourcecore] + 1;
67 if(memneed < remain) {
68 gcloads[sourcecore] += memneed;
69 BAMBOO_ENTER_CLIENT_MODE_FROM_RUNTIME();
72 // next available block
73 gcfilledblocks[sourcecore] += 1;
74 unsigned int newbase = 0;
75 BASEPTR(sourcecore, gcfilledblocks[sourcecore], &newbase);
76 gcloads[sourcecore] = newbase;
77 BAMBOO_ENTER_CLIENT_MODE_FROM_RUNTIME();
78 return requiredmem-remain;
82 INLINE void compact2Heaptophelper_I(unsigned int coren,
84 unsigned int* numblocks,
85 unsigned int* remain) {
87 unsigned int memneed = gcrequiredmems[coren] + BAMBOO_CACHE_LINE_SIZE;
88 if(STARTUPCORE == coren) {
91 gcdstcore = gctopcore;
92 gcblock2fill = *numblocks + 1;
94 if(BAMBOO_CHECK_SEND_MODE()) {
95 cache_msg_4_I(coren,GCMOVESTART,gctopcore,*p,(*numblocks)+1);
97 send_msg_4_I(coren,GCMOVESTART,gctopcore,*p,(*numblocks)+1);
100 if(memneed < *remain) {
102 gcrequiredmems[coren] = 0;
103 gcloads[gctopcore] += memneed;
104 *remain = *remain - memneed;
106 // next available block
108 gcfilledblocks[gctopcore] += 1;
109 unsigned int newbase = 0;
110 BASEPTR(gctopcore, gcfilledblocks[gctopcore], &newbase);
111 gcloads[gctopcore] = newbase;
112 gcrequiredmems[coren] -= *remain - BAMBOO_CACHE_LINE_SIZE;
113 gcstopblock[gctopcore]++;
114 gctopcore = NEXTTOPCORE(gctopblock);
116 *numblocks = gcstopblock[gctopcore];
117 *p = gcloads[gctopcore];
119 *remain=GC_BLOCK_REMAIN_SIZE(b, (*p));
124 INLINE void compact2Heaptop() {
125 // no cores with spare mem and some cores are blocked with pending move
126 // find the current heap top and make them move to the heap top
128 unsigned int numblocks = gcfilledblocks[gctopcore];
129 p = gcloads[gctopcore];
132 unsigned int remain=GC_BLOCK_REMAIN_SIZE(b, p);
133 // check if the top core finishes
134 BAMBOO_ENTER_RUNTIME_MODE_FROM_CLIENT();
135 if(gccorestatus[gctopcore] != 0) {
136 // let the top core finishes its own work first
137 compact2Heaptophelper_I(gctopcore, &p, &numblocks, &remain);
138 BAMBOO_ENTER_CLIENT_MODE_FROM_RUNTIME();
141 BAMBOO_ENTER_CLIENT_MODE_FROM_RUNTIME();
143 for(int i = 0; i < NUMCORES4GC; i++) {
144 BAMBOO_ENTER_RUNTIME_MODE_FROM_CLIENT();
145 if((gccorestatus[i] != 0) && (gcrequiredmems[i] > 0)) {
146 compact2Heaptophelper_I(i, &p, &numblocks, &remain);
147 if(gccorestatus[gctopcore] != 0) {
148 BAMBOO_ENTER_CLIENT_MODE_FROM_RUNTIME();
149 // the top core is not free now
153 BAMBOO_ENTER_CLIENT_MODE_FROM_RUNTIME();
157 INLINE void resolvePendingMoveRequest() {
160 bool nosparemem = true;
161 bool haspending = false;
162 bool hasrunning = false;
163 bool noblock = false;
164 unsigned int dstcore = 0; // the core who need spare mem
165 unsigned int sourcecore = 0; // the core who has spare mem
166 for(i = j = 0; (i < NUMCORES4GC) && (j < NUMCORES4GC); ) {
168 // check if there are cores with spare mem
169 if(gccorestatus[i] == 0) {
170 // finished working, check if it still have spare mem
171 if(gcfilledblocks[i] < gcstopblock[i]) {
172 // still have spare mem
180 if(gccorestatus[j] != 0) {
181 // not finished, check if it has pending move requests
182 if((gcfilledblocks[j]==gcstopblock[j])&&(gcrequiredmems[j]>0)) {
191 if(!nosparemem && haspending) {
193 unsigned int tomove = 0;
194 unsigned int startaddr = 0;
195 gcrequiredmems[dstcore] = assignSpareMem(sourcecore,
196 gcrequiredmems[dstcore],
199 if(STARTUPCORE == dstcore) {
200 gcdstcore = sourcecore;
202 gcmovestartaddr = startaddr;
203 gcblock2fill = tomove;
205 send_msg_4(dstcore,GCMOVESTART,sourcecore,startaddr,tomove);
214 if(!hasrunning && !noblock) {
215 gcphase = SUBTLECOMPACTPHASE;
220 // If out of boundary of valid shared memory, return false, else return true
221 INLINE bool nextSBlock(struct moveHelper * orig) {
222 orig->blockbase = orig->blockbound;
224 bool sbchanged = false;
225 unsigned int origptr = orig->ptr;
226 unsigned int blockbase = orig->blockbase;
227 unsigned int blockbound = orig->blockbound;
228 unsigned int bound = orig->bound;
230 // check if across a big block
231 // TODO now do not zero out the whole memory, maybe the last two conditions
233 if((blockbase>=bound)||(origptr>=bound)
234 ||((origptr!=NULL)&&(*((int*)origptr))==0)||((*((int*)blockbase))==0)) {
236 // end of current heap block, jump to next one
238 BASEPTR(BAMBOO_NUM_OF_CORE, orig->numblocks, &(orig->base));
239 if(orig->base >= gcbaseva + BAMBOO_SHARED_MEM_SIZE) {
241 orig->ptr = orig->base; // set current ptr to out of boundary too
244 orig->blockbase = orig->base;
246 (unsigned int)(orig->blockbase-gcbaseva)/BAMBOO_SMEM_SIZE;
248 unsigned int blocknum = 0;
249 BLOCKINDEX(orig->base, &blocknum);
250 if(bamboo_smemtbl[blocknum] == 0) {
252 goto innernextSBlock;
254 // check the bamboo_smemtbl to decide the real bound
255 orig->bound = orig->base + bamboo_smemtbl[blocknum];
256 } else if(0 == (orig->blockbase%BAMBOO_SMEM_SIZE)) {
257 orig->sblockindex += 1;
261 // check if this sblock should be skipped or have special start point
262 int sbstart = gcsbstarttbl[orig->sblockindex];
265 orig->sblockindex += 1;
266 orig->blockbase += BAMBOO_SMEM_SIZE;
267 goto outernextSBlock;
268 } else if((sbstart != 0) && (sbchanged)) {
269 // the first time to access this SBlock
270 // not start from the very beginning
271 orig->blockbase = sbstart;
274 // setup information for this sblock
275 orig->blockbound = orig->blockbase+(unsigned int)*((int*)(orig->blockbase));
276 orig->offset = BAMBOO_CACHE_LINE_SIZE;
277 orig->ptr = orig->blockbase + orig->offset;
278 if(orig->ptr >= orig->bound) {
279 // met a lobj, move to next block
280 goto innernextSBlock;
286 // return false if there are no available data to compact
287 INLINE bool initOrig_Dst(struct moveHelper * orig,
288 struct moveHelper * to) {
291 to->top = to->offset = BAMBOO_CACHE_LINE_SIZE;
292 to->bound = BAMBOO_SMEM_SIZE_L;
293 BASEPTR(BAMBOO_NUM_OF_CORE, to->numblocks, &(to->base));
295 unsigned int tobase = to->base;
296 to->ptr = tobase + to->offset;
301 unsigned int blocknum = 0;
302 BLOCKINDEX(orig->base, &blocknum);
303 unsigned int origbase = orig->base;
304 // check the bamboo_smemtbl to decide the real bound
305 orig->bound = origbase + (unsigned int)bamboo_smemtbl[blocknum];
306 orig->blockbase = origbase;
307 orig->sblockindex = (unsigned int)(origbase - gcbaseva) / BAMBOO_SMEM_SIZE;
309 int sbstart = gcsbstarttbl[orig->sblockindex];
312 orig->blockbound=gcbaseva+BAMBOO_SMEM_SIZE*(orig->sblockindex+1);
313 return nextSBlock(orig);
314 } else if(sbstart != 0) {
315 orig->blockbase = sbstart;
317 orig->blockbound = orig->blockbase + *((int*)(orig->blockbase));
318 orig->offset = BAMBOO_CACHE_LINE_SIZE;
319 orig->ptr = orig->blockbase + orig->offset;
324 INLINE void nextBlock(struct moveHelper * to) {
325 to->top = to->bound + BAMBOO_CACHE_LINE_SIZE; // header!
326 to->bound += BAMBOO_SMEM_SIZE;
328 BASEPTR(BAMBOO_NUM_OF_CORE, to->numblocks, &(to->base));
329 to->offset = BAMBOO_CACHE_LINE_SIZE;
330 to->ptr = to->base + to->offset;
333 INLINE unsigned int findValidObj(struct moveHelper * orig,
334 struct moveHelper * to,
336 unsigned int size = 0;
338 CACHEADAPT_COMPLETE_PAGE_CONVERT(orig, to, to->ptr, false);
339 unsigned int origptr = (unsigned int)(orig->ptr);
340 unsigned int origbound = (unsigned int)orig->bound;
341 unsigned int origblockbound = (unsigned int)orig->blockbound;
342 if((origptr >= origbound) || (origptr == origblockbound)) {
343 if(!nextSBlock(orig)) {
344 // finished, no more data
349 // check the obj's type, size and mark flag
350 *type = ((int *)(origptr))[0];
353 // end of this block, go to next one
354 if(!nextSBlock(orig)) {
355 // finished, no more data
359 } else if(*type < NUMCLASSES) {
361 size = classsize[*type];
364 struct ArrayObject *ao=(struct ArrayObject *)(origptr);
365 unsigned int elementsize=classsize[*type];
366 unsigned int length=ao->___length___;
367 size=(unsigned int)sizeof(struct ArrayObject)
368 +(unsigned int)(length*elementsize);
374 // endaddr does not contain spaces for headers
375 INLINE bool moveobj(struct moveHelper * orig, struct moveHelper * to, unsigned int stopblock) {
381 unsigned int size = findValidObj(orig, to, &type);
382 unsigned int isize = 0;
385 // finished, no more data
388 ALIGNSIZE(size, &isize); // no matter is the obj marked or not
389 // should be able to across
390 unsigned int origptr = (unsigned int)(orig->ptr);
391 if(((struct ___Object___ *)origptr)->marked == MARKED) {
392 unsigned int totop = (unsigned int)to->top;
393 unsigned int tobound = (unsigned int)to->bound;
394 GCPROFILE_RECORD_LIVE_OBJ();
395 // marked obj, copy it to current heap top
396 // check to see if remaining space is enough
397 if((unsigned int)(totop + isize) > tobound) {
398 // fill 0 indicating the end of this block
399 BAMBOO_MEMSET_WH(to->ptr, '\0', tobound - totop);
400 // fill the header of this block and then go to next block
401 to->offset += tobound - totop;
402 CLOSEBLOCK(to->base, to->offset);
403 #ifdef GC_CACHE_ADAPT
404 unsigned int tmp_ptr = to->ptr;
407 #ifdef GC_CACHE_ADAPT
408 CACHEADAPT_COMPLETE_PAGE_CONVERT(orig, to, tmp_ptr, true);
410 if(stopblock == to->numblocks) {
411 // already fulfilled the block
415 // set the mark field to 2, indicating that this obj has been moved
416 // and need to be flushed
417 ((struct ___Object___ *)origptr)->marked = COMPACTED;
418 unsigned int toptr = (unsigned int)to->ptr;
419 if(toptr != origptr) {
420 if((unsigned int)(origptr) < (unsigned int)(toptr+size)) {
421 memmove(toptr, origptr, size);
423 memcpy(toptr, origptr, size);
425 // fill the remaining space with -2
426 BAMBOO_MEMSET_WH((unsigned int)(toptr+size), -2, isize-size);
428 // store mapping info
429 gcmappingtbl[OBJMAPPINGINDEX((unsigned int)origptr)]=(unsigned int)toptr;
430 gccurr_heaptop -= isize;
434 #ifdef GC_CACHE_ADAPT
435 unsigned int tmp_ptr = to->ptr;
436 #endif // GC_CACHE_ADAPT
437 if(to->top == to->bound) {
438 CLOSEBLOCK(to->base, to->offset);
441 #ifdef GC_CACHE_ADAPT
442 CACHEADAPT_COMPLETE_PAGE_CONVERT(orig, to, tmp_ptr, true);
449 return ((((unsigned int)(orig->ptr) > (unsigned int)(orig->bound))
450 || ((unsigned int)(orig->ptr) == (unsigned int)(orig->blockbound)))
451 &&!nextSBlock(orig));
454 // should be invoked with interrupt closed
455 bool gcfindSpareMem_I(unsigned int * startaddr,
456 unsigned int * tomove,
457 unsigned int * dstcore,
458 unsigned int requiredmem,
459 unsigned int requiredcore) {
460 for(int k = 0; k < NUMCORES4GC; k++) {
461 if((gccorestatus[k] == 0) && (gcfilledblocks[k] < gcstopblock[k])) {
462 // check if this stopped core has enough mem
463 assignSpareMem_I(k, requiredmem, tomove, startaddr);
468 // if can not find spare mem right now, hold the request
469 gcrequiredmems[requiredcore] = requiredmem;
474 bool gcfindSpareMem(unsigned int * startaddr,
475 unsigned int * tomove,
476 unsigned int * dstcore,
477 unsigned int requiredmem,
478 unsigned int requiredcore) {
479 BAMBOO_ENTER_RUNTIME_MODE_FROM_CLIENT();
480 for(int k = 0; k < NUMCORES4GC; k++) {
481 if((gccorestatus[k] == 0) && (gcfilledblocks[k] < gcstopblock[k])) {
482 // check if this stopped core has enough mem
483 assignSpareMem_I(k, requiredmem, tomove, startaddr);
485 BAMBOO_ENTER_CLIENT_MODE_FROM_RUNTIME();
489 // if can not find spare mem right now, hold the request
490 gcrequiredmems[requiredcore] = requiredmem;
492 BAMBOO_ENTER_CLIENT_MODE_FROM_RUNTIME();
496 INLINE bool compacthelper(struct moveHelper * orig,
497 struct moveHelper * to,
499 unsigned int * heaptopptr,
500 bool * localcompact) {
501 // scan over all objs in this block, compact the marked objs
502 // loop stop when finishing either scanning all active objs or
503 // fulfilled the gcstopblock
505 while((unsigned int)(orig->ptr) < (unsigned int)gcmarkedptrbound) {
506 if(moveobj(orig, to, gcblock2fill)) {
510 CACHEADAPT_SAMPLING_DATA_CONVERT(to->ptr);
511 // if no objs have been compact, do nothing,
512 // otherwise, fill the header of this block
513 if(to->offset > (unsigned int)BAMBOO_CACHE_LINE_SIZE) {
514 CLOSEBLOCK(to->base, to->offset);
518 to->top -= BAMBOO_CACHE_LINE_SIZE;
521 *heaptopptr = to->ptr;
522 *filledblocks = to->numblocks;
525 // send msgs to core coordinator indicating that the compact is finishing
526 // send compact finish message to core coordinator
527 if(STARTUPCORE == BAMBOO_NUM_OF_CORE) {
528 gcfilledblocks[BAMBOO_NUM_OF_CORE] = *filledblocks;
529 gcloads[BAMBOO_NUM_OF_CORE] = *heaptopptr;
530 if((unsigned int)(orig->ptr) < (unsigned int)gcmarkedptrbound) {
533 if(gcfindSpareMem(&gcmovestartaddr, &gcblock2fill, &gcdstcore,
534 gccurr_heaptop, BAMBOO_NUM_OF_CORE)) {
540 gccorestatus[BAMBOO_NUM_OF_CORE] = 0;
545 if((unsigned int)(orig->ptr) < (unsigned int)gcmarkedptrbound) {
548 send_msg_5(STARTUPCORE,GCFINISHCOMPACT,BAMBOO_NUM_OF_CORE,*filledblocks,*heaptopptr,gccurr_heaptop);
551 send_msg_5(STARTUPCORE,GCFINISHCOMPACT,BAMBOO_NUM_OF_CORE,*filledblocks,*heaptopptr, 0);
555 if(orig->ptr < gcmarkedptrbound) {
556 // still have unpacked obj
561 to->ptr = gcmovestartaddr;
562 to->numblocks = gcblock2fill - 1;
563 to->bound = ((to->numblocks==0)?BAMBOO_SMEM_SIZE_L:BAMBOO_SMEM_SIZE_L)+BAMBOO_SMEM_SIZE*to->numblocks;
564 BASEPTR(gcdstcore, to->numblocks, &(to->base));
565 to->offset = to->ptr - to->base;
566 to->top = (to->numblocks==0)?(to->offset):(to->bound-BAMBOO_SMEM_SIZE+to->offset);
568 to->offset = BAMBOO_CACHE_LINE_SIZE;
569 to->ptr += to->offset; // for header
570 to->top += to->offset;
571 *localcompact = (gcdstcore == BAMBOO_NUM_OF_CORE);
572 CACHEADAPT_SAMPLING_DATA_REVISE_INIT();
579 BAMBOO_ASSERT(COMPACTPHASE == gcphase);
581 // initialize pointers for comapcting
582 struct moveHelper * orig = (struct moveHelper *)RUNMALLOC(sizeof(struct moveHelper));
583 struct moveHelper * to = (struct moveHelper *)RUNMALLOC(sizeof(struct moveHelper));
584 if(!initOrig_Dst(orig, to)) {
585 // no available data to compact
586 // send compact finish msg to STARTUP core
587 send_msg_5(STARTUPCORE,GCFINISHCOMPACT,BAMBOO_NUM_OF_CORE,0,to->base,0);
591 CACHEADAPT_SAMPLING_DATA_REVISE_INIT();
593 unsigned int filledblocks = 0;
594 unsigned int heaptopptr = 0;
595 bool localcompact = true;
596 compacthelper(orig, to, &filledblocks, &heaptopptr, &localcompact);
602 void compact_master(struct moveHelper * orig, struct moveHelper * to) {
603 // initialize pointers for comapcting
604 initOrig_Dst(orig, to);
605 CACHEADAPT_SAMPLING_DATA_REVISE_INIT();
606 int filledblocks = 0;
607 unsigned int heaptopptr = 0;
608 bool finishcompact = false;
609 bool iscontinue = true;
610 bool localcompact = true;
611 while((COMPACTPHASE == gcphase) || (SUBTLECOMPACTPHASE == gcphase)) {
612 if((!finishcompact) && iscontinue) {
613 finishcompact = compacthelper(orig,to,&filledblocks,&heaptopptr,&localcompact);
616 if(gc_checkCoreStatus()) {
617 // all cores have finished compacting restore the gcstatus of all cores
618 gc_resetCoreStatus();
621 // check if there are spare mem for pending move requires
622 if(COMPACTPHASE == gcphase) {
623 resolvePendingMoveRequest();
630 to->ptr = gcmovestartaddr;
631 to->numblocks = gcblock2fill - 1;
632 to->bound = (to->numblocks==0) ? BAMBOO_SMEM_SIZE_L : BAMBOO_SMEM_SIZE_L+BAMBOO_SMEM_SIZE*to->numblocks;
633 BASEPTR(gcdstcore, to->numblocks, &(to->base));
634 to->offset = to->ptr - to->base;
635 to->top = (to->numblocks==0)?(to->offset):(to->bound-BAMBOO_SMEM_SIZE+to->offset);
637 to->offset = BAMBOO_CACHE_LINE_SIZE;
638 to->ptr += to->offset; // for header
639 to->top += to->offset;
640 localcompact = (gcdstcore == BAMBOO_NUM_OF_CORE);
643 } else if(!finishcompact) {
650 #endif // MULTICORE_GC