Add gcprofile to PMC garbage collector and compute the size of allocated obj instead...
[IRC.git] / Robust / src / Runtime / bamboo / multicoregccompact.c
1 #ifdef MULTICORE_GC
2 #include "structdefs.h"
3 #include "multicoregccompact.h"
4 #include "runtime_arch.h"
5 #include "multicoreruntime.h"
6 #include "multicoregarbage.h"
7 #include "markbit.h"
8 #include "multicoremem_helper.h"
9 #include "gcqueue.h"
10
11 int gc_countRunningCores() {
12   int count=0;
13   for(int i = 0; i < NUMCORES4GC; i++) {
14     if(returnedmem[i]) {
15       count++;
16     }
17   }
18   return count;
19 }
20
21 void initOrig_Dst(struct moveHelper * orig,struct moveHelper * to) {
22   // init the dst ptr
23   to->localblocknum = 0;
24   BASEPTR(to->base, BAMBOO_NUM_OF_CORE, to->localblocknum);
25   to->ptr = to->base;
26   to->bound=to->base+BLOCKSIZE(to->localblocknum);
27   
28   // init the orig ptr
29   orig->localblocknum = 0;
30   orig->ptr=orig->base = to->base;
31   orig->bound=orig->base+BLOCKSIZE(orig->localblocknum);
32 #ifdef GC_CACHE_ADAPT
33   to->pagebound=to->base+BAMBOO_PAGE_SIZE;
34   orig->pagebound=orig->base+BAMBOO_PAGE_SIZE;
35 #endif
36 }
37
38 void getSpaceLocally(struct moveHelper *to) {
39   //we have space on our core...just keep going
40   to->localblocknum++;
41   BASEPTR(to->base,BAMBOO_NUM_OF_CORE, to->localblocknum);
42   to->ptr=to->base;
43   to->bound=to->base+BLOCKSIZE(to->localblocknum);
44 #ifdef GC_CACHE_ADAPT
45   to->pagebound=to->base+BAMBOO_PAGE_SIZE;
46 #endif
47 }
48
49 //This function is called on the master core only...and typically by
50 //the message interrupt handler
51
52 void handleReturnMem_I(unsigned int cnum, void *heaptop) {
53   unsigned int blockindex;
54   BLOCKINDEX(blockindex, heaptop);
55   unsigned INTPTR localblocknum=GLOBALBLOCK2LOCAL(blockindex);
56   //this core is done as far as memory usage is concerned
57   returnedmem[cnum]=0;
58
59   struct blockrecord * blockrecord=&allocationinfo.blocktable[blockindex];
60
61   blockrecord->status=BS_FREE;
62   blockrecord->usedspace=(unsigned INTPTR)(heaptop-OFFSET2BASEVA(blockindex)-gcbaseva);
63   blockrecord->freespace=BLOCKSIZE(localblocknum)-blockrecord->usedspace;
64   /* Update the lowest free block */
65   if (blockindex < allocationinfo.lowestfreeblock) {
66     allocationinfo.lowestfreeblock=blockindex;
67   }
68
69   /* This is our own block...means we should mark other blocks above us as free*/
70   
71   if (cnum==blockrecord->corenum) {
72     unsigned INTPTR nextlocalblocknum=localblocknum+1;
73     for(;nextlocalblocknum<numblockspercore;nextlocalblocknum++) {
74       unsigned INTPTR blocknum=BLOCKINDEX2(cnum, nextlocalblocknum);
75       struct blockrecord * nextblockrecord=&allocationinfo.blocktable[blocknum];
76       nextblockrecord->status=BS_FREE;
77       nextblockrecord->usedspace=0;
78       //this is true because this cannot be the lowest block
79       nextblockrecord->freespace=BLOCKSIZE(1);
80     }
81   }
82
83   //this could be the last one....
84   int count=gc_countRunningCores();
85   if (gcmovepending==count) {
86     // All cores have stopped...hand out memory as necessary to handle all requests
87     handleMemoryRequests_I();
88   } else {
89     //see if returned memory blocks let us resolve requests
90     useReturnedMem(cnum, allocationinfo.lowestfreeblock);
91   }
92 }
93
94 void useReturnedMem(unsigned int retcorenum, block_t localblockindex) {
95   for(int i=0;i<NUMCORES4GC;i++) {
96     unsigned INTPTR requiredmem=gcrequiredmems[i];
97     if (requiredmem) {
98       unsigned INTPTR desiredmem=maxusefulmems[i];
99       unsigned INTPTR threshold=(desiredmem<MINMEMORYCHUNKSIZE)? desiredmem: MINMEMORYCHUNKSIZE;
100       unsigned INTPTR memcheck=requiredmem>threshold?requiredmem:threshold;
101
102
103       for(block_t nextlocalblocknum=localblockindex;nextlocalblocknum<numblockspercore;nextlocalblocknum++) {
104         unsigned INTPTR blocknum=BLOCKINDEX2(retcorenum, nextlocalblocknum);
105         struct blockrecord * nextblockrecord=&allocationinfo.blocktable[blocknum];
106         if (nextblockrecord->status==BS_FREE) {
107           unsigned INTPTR freespace=nextblockrecord->freespace&~BAMBOO_CACHE_LINE_MASK;
108           if (freespace>=memcheck) {
109             nextblockrecord->status=BS_USED;
110             void *blockptr=OFFSET2BASEVA(blocknum)+gcbaseva;
111             unsigned INTPTR usedspace=((nextblockrecord->usedspace-1)&~BAMBOO_CACHE_LINE_MASK)+BAMBOO_CACHE_LINE_SIZE;
112             //taken care of one block
113             gcmovepending--;
114             void *startaddr=blockptr+usedspace;
115             gcrequiredmems[i]=0;
116             maxusefulmems[i]=0;
117             if (i==STARTUPCORE) {
118               gctomove = true;
119               gcmovestartaddr = startaddr;
120             } else if(BAMBOO_CHECK_SEND_MODE()) {
121               cache_msg_2_I(i,GCMOVESTART,startaddr);
122             } else {
123               send_msg_2_I(i,GCMOVESTART,startaddr);
124             }
125           }
126         }
127       }
128     }
129   }
130 }
131
132 void handleReturnMem(unsigned int cnum, void *heaptop) {
133   BAMBOO_ENTER_RUNTIME_MODE_FROM_CLIENT();
134   handleReturnMem_I(cnum, heaptop);
135   BAMBOO_ENTER_CLIENT_MODE_FROM_RUNTIME();
136 }
137
138 void getSpaceRemotely(struct moveHelper *to, unsigned int minimumbytes) {
139   //need to get another block from elsewhere
140   //set flag to wait for memory
141
142   if (BAMBOO_NUM_OF_CORE==STARTUPCORE) {
143     gctomove=false;
144     BAMBOO_ENTER_RUNTIME_MODE_FROM_CLIENT();
145     void *startaddr=handlegcfinishcompact_I(BAMBOO_NUM_OF_CORE, minimumbytes, gccurr_heaptop);
146     BAMBOO_ENTER_CLIENT_MODE_FROM_RUNTIME();
147
148     if (startaddr) {
149       gcmovestartaddr=startaddr;
150     } else {
151       while(!gctomove) ;
152     }
153   } else {
154     gctomove=false;
155     //send request for memory
156     send_msg_4(STARTUPCORE,GCFINISHCOMPACT,BAMBOO_NUM_OF_CORE, minimumbytes, gccurr_heaptop);
157     //wait for flag to be set that we received message
158     while(!gctomove)
159       ;
160   }
161
162   //store pointer
163   to->ptr = gcmovestartaddr;
164
165   //set localblock number to high number to indicate this block isn't local
166   to->localblocknum = MAXBLOCK;
167   unsigned int globalblocknum;
168   BLOCKINDEX(globalblocknum, to->ptr);
169   to->base = gcbaseva + OFFSET2BASEVA(globalblocknum);
170   to->bound=gcbaseva+BOUNDPTR(globalblocknum);
171 #ifdef GC_CACHE_ADAPT
172   to->pagebound=(void *)((int)((int)(to->ptr)&(~(BAMBOO_PAGE_SIZE-1)))+BAMBOO_PAGE_SIZE);
173 #endif
174 }
175
176 void getSpace(struct moveHelper *to, unsigned int minimumbytes) {
177   //need more space to compact into
178   if ((to->localblocknum+1) < gcblock2fill) {
179     getSpaceLocally(to);
180   } else {
181     getSpaceRemotely(to, minimumbytes);
182   }
183 }
184
185 void compacthelper(struct moveHelper * orig,struct moveHelper * to) {
186   bool senttopmessage=false;
187   while(true) {
188     if ((gccurr_heaptop <= ((unsigned INTPTR)(to->bound-to->ptr)))&&!senttopmessage) {
189       //This block is the last for this core...let the startup know
190       if (BAMBOO_NUM_OF_CORE==STARTUPCORE) {
191         handleReturnMem(BAMBOO_NUM_OF_CORE, to->ptr+gccurr_heaptop);
192       } else {
193         send_msg_3(STARTUPCORE, GCRETURNMEM, BAMBOO_NUM_OF_CORE, to->ptr+gccurr_heaptop);
194       }
195       //Only send the message once
196       senttopmessage=true;
197     }
198     unsigned int minimumbytes=COMPACTUNITS(orig, to);
199     if (orig->ptr==orig->bound) {
200       //need more data to compact
201       //increment the core
202       orig->localblocknum++;
203       BASEPTR(orig->base,BAMBOO_NUM_OF_CORE, orig->localblocknum);
204       orig->ptr=orig->base;
205       orig->bound=orig->base+BLOCKSIZE(orig->localblocknum);
206 #ifdef GC_CACHE_ADAPT
207       orig->pagebound=orig->base+BAMBOO_PAGE_SIZE;
208 #endif
209       if (orig->base >= gcbaseva+BAMBOO_SHARED_MEM_SIZE) {
210         CACHEADAPT_FINISH_COMPACT(to->ptr);
211         break;
212       }
213     }
214     if (minimumbytes!=0) {
215       getSpace(to, minimumbytes);
216     }
217   }
218   if (BAMBOO_NUM_OF_CORE==STARTUPCORE) {
219     BAMBOO_ENTER_RUNTIME_MODE_FROM_CLIENT();
220     handlegcfinishcompact_I(BAMBOO_NUM_OF_CORE, 0, 0);
221     BAMBOO_ENTER_CLIENT_MODE_FROM_RUNTIME();
222   } else {
223     send_msg_4(STARTUPCORE,GCFINISHCOMPACT,BAMBOO_NUM_OF_CORE, 0, 0);
224   }
225 }
226
227 void * checkNeighbors_I(int ncorenum, unsigned INTPTR requiredmem, unsigned INTPTR desiredmem) {
228   int minblockindex=allocationinfo.lowestfreeblock/NUMCORES4GC;
229   unsigned INTPTR threshold=(desiredmem<MINMEMORYCHUNKSIZE)? desiredmem: MINMEMORYCHUNKSIZE;
230   unsigned INTPTR memcheck=requiredmem>threshold?requiredmem:threshold;
231
232   for(block_t lblock=minblockindex;lblock<numblockspercore;lblock++) {
233     for(int i=0;i<NUM_CORES2TEST;i++) {
234       int neighborcore=core2test[ncorenum][i];
235       if (neighborcore!=-1) {
236         block_t globalblockindex=BLOCKINDEX2(neighborcore, lblock);
237         struct blockrecord * block=&allocationinfo.blocktable[globalblockindex];
238         if (block->status==BS_FREE) {
239           unsigned INTPTR freespace=block->freespace&~BAMBOO_CACHE_LINE_MASK;
240           if (memcheck<=freespace) {
241             //we have a block
242             //mark block as used
243             block->status=BS_USED;
244             void *blockptr=OFFSET2BASEVA(globalblockindex)+gcbaseva;
245             unsigned INTPTR usedspace=((block->usedspace-1)&~BAMBOO_CACHE_LINE_MASK)+BAMBOO_CACHE_LINE_SIZE;
246             return blockptr+usedspace;
247           }
248         }
249       }
250     }
251   }
252   return NULL;
253 }
254
255 void * globalSearch_I(unsigned int topblock, unsigned INTPTR requiredmem, unsigned INTPTR desiredmem) {
256   unsigned int firstfree=NOFREEBLOCK;
257   unsigned INTPTR threshold=(desiredmem<MINMEMORYCHUNKSIZE)? desiredmem: MINMEMORYCHUNKSIZE;
258   unsigned INTPTR memcheck=requiredmem>threshold?requiredmem:threshold;
259
260   for(block_t i=allocationinfo.lowestfreeblock;i<topblock;i++) {
261     struct blockrecord * block=&allocationinfo.blocktable[i];
262     if (block->status==BS_FREE) {
263       if(firstfree==NOFREEBLOCK)
264         firstfree=i;
265       unsigned INTPTR freespace=block->freespace&~BAMBOO_CACHE_LINE_MASK;
266       if (memcheck<=freespace) {
267         //we have a block
268         //mark block as used
269         block->status=BS_USED;
270         void *blockptr=OFFSET2BASEVA(i)+gcbaseva;
271         unsigned INTPTR usedspace=((block->usedspace-1)&~BAMBOO_CACHE_LINE_MASK)+BAMBOO_CACHE_LINE_SIZE;
272         allocationinfo.lowestfreeblock=firstfree;
273         return blockptr+usedspace;
274       }
275     }
276   }
277   allocationinfo.lowestfreeblock=firstfree;
278   return NULL;
279 }
280
281 void handleOneMemoryRequest(int core, unsigned int lowestblock) {
282   unsigned INTPTR requiredmem=gcrequiredmems[core];
283   unsigned INTPTR desiredmem=maxusefulmems[core];
284   block_t firstfree=NOFREEBLOCK;
285   unsigned INTPTR threshold=(desiredmem<MINMEMORYCHUNKSIZE)? desiredmem: MINMEMORYCHUNKSIZE;
286   unsigned INTPTR memcheck=requiredmem>threshold?requiredmem:threshold;
287
288   for(block_t searchblock=lowestblock;searchblock<GCNUMBLOCK;searchblock++) {
289     struct blockrecord * block=&allocationinfo.blocktable[searchblock];
290     if (block->status==BS_FREE) {
291       if(firstfree==NOFREEBLOCK)
292         firstfree=searchblock;
293       //don't take a block from another core that hasn't returned its memory yet
294       if (block->corenum!=core&&returnedmem[block->corenum])
295         continue;
296       
297       unsigned INTPTR freespace=block->freespace&~BAMBOO_CACHE_LINE_MASK;
298       if (freespace>=memcheck) {
299         //TODO: should check memory block at same level on our own core...if that works, use it to preserve locality
300
301         //we have a block
302         //mark block as used
303         block->status=BS_USED;
304         void *blockptr=OFFSET2BASEVA(searchblock)+gcbaseva;
305         unsigned INTPTR usedspace=((block->usedspace-1)&~BAMBOO_CACHE_LINE_MASK)+BAMBOO_CACHE_LINE_SIZE;
306         allocationinfo.lowestfreeblock=firstfree;
307         //taken care of one block
308         gcmovepending--;
309         void *startaddr=blockptr+usedspace;
310         if (core==STARTUPCORE) {
311           gctomove=true;
312           gcmovestartaddr=startaddr;
313         } else if(BAMBOO_CHECK_SEND_MODE()) {
314           cache_msg_2_I(core,GCMOVESTART,startaddr);
315         } else {
316           send_msg_2_I(core,GCMOVESTART,startaddr);
317         }
318         return;
319       }
320     }
321   }
322   //this is bad...ran out of memory
323   printf("Out of memory.  Was trying for %u bytes\n", threshold);
324   BAMBOO_EXIT();
325 }
326
327 void handleMemoryRequests_I() {
328   unsigned int lowestblock=allocationinfo.lowestfreeblock;
329   if (lowestblock==NOFREEBLOCK) {
330     lowestblock=numblockspercore*NUMCORES4GC;
331   }
332   
333   for(int i=0;i < NUMCORES4GC; i++) {
334     if (gcrequiredmems[i]) {
335       handleOneMemoryRequest(i, lowestblock);
336       lowestblock=allocationinfo.lowestfreeblock;
337     }
338   }
339 }
340
341 /* should be invoked with interrupt turned off */
342
343 void * gcfindSpareMem_I(unsigned INTPTR requiredmem, unsigned INTPTR desiredmem,unsigned int requiredcore) {
344   if (allocationinfo.lowestfreeblock!=NOFREEBLOCK) {
345     //There are spare blocks
346     unsigned int topblock=numblockspercore*NUMCORES4GC;
347     void *memblock;
348     
349     if (memblock=checkNeighbors_I(requiredcore, requiredmem, desiredmem)) {
350       return memblock;
351     } else if (memblock=globalSearch_I(topblock, requiredmem, desiredmem)) {
352       return memblock;
353     }
354   }
355   
356   // If we cannot find spare mem right now, hold the request
357   gcrequiredmems[requiredcore] = requiredmem;
358   maxusefulmems[requiredcore]=desiredmem;
359   gcmovepending++;
360
361   int count=gc_countRunningCores();
362   if (gcmovepending==count) {
363     // All cores have stopped...hand out memory as necessary to handle all requests
364     handleMemoryRequests_I();
365   }
366
367   return NULL;
368
369
370 #ifdef GC_CACHE_ADAPT
371 unsigned int compactblockshelper(struct moveHelper * orig, struct moveHelper * to) {
372   unsigned int minimumbytes=0;
373   void *origptr=orig->ptr;
374   void *origbound=orig->bound;
375   void * tmporig=orig->ptr;
376   void * tmpto=to->ptr;
377
378   while(true) {
379     //call compactblocks using the page boundaries at the current bounds
380     minimumbytes=compactblocks(orig, to);
381     if(minimumbytes == 0) {
382       //bump the orig page bound...
383       //use old orig pointer to make sure we get correct block
384       CACHEADAPT_FINISH_SRC_PAGE(tmporig, tmpto, to->ptr);
385       if (orig->ptr<origbound) {
386         tmporig=orig->ptr;
387         tmpto=to->ptr;
388         orig->pagebound=orig->pagebound+BAMBOO_PAGE_SIZE;
389       } else {
390         return 0;
391       }
392     } else {
393       // require more memory
394       void *endtoptr=to->ptr+minimumbytes;
395       if (endtoptr>to->bound) {
396         CACHEADAPT_FINISH_DST_PAGE(orig->ptr, tmpto, to->ptr, 0);
397         return minimumbytes;
398       } else {
399         CACHEADAPT_FINISH_DST_PAGE(orig->ptr, tmpto, to->ptr, minimumbytes);
400         to->pagebound=((((unsigned INTPTR)endtoptr)-1)&~(BAMBOO_PAGE_SIZE-1))+BAMBOO_PAGE_SIZE;
401         //update pointers to avoid double counting the stuff we already added in
402         tmporig=orig->ptr+minimumbytes;
403         tmpto=to->ptr+minimumbytes;
404       }
405     }
406   }
407 }
408 #endif
409
410 /* This function is performance critical...  spend more time optimizing it */
411
412 unsigned int compactblocks(struct moveHelper * orig, struct moveHelper * to) {
413   void *toptrinit=to->ptr;
414   void *toptr=toptrinit;
415   void *origptr=orig->ptr;
416 #ifdef GC_CACHE_ADAPT
417   void *origbound=orig->pagebound;
418   void *tobound=to->pagebound;
419   //set to the first line so we don't need conditions
420   void *lastflush=(void *)(((unsigned INTPTR)&gcmappingtbl[OBJMAPPINGINDEX(origptr)])&~(BAMBOO_CACHE_LINE_MASK));
421 #else
422   void *origbound=orig->bound;
423   void *tobound=to->bound;
424 #endif
425   unsigned INTPTR origendoffset=ALIGNTOTABLEINDEX((unsigned INTPTR)(origbound-gcbaseva));
426   unsigned int objlength;
427
428   while(origptr<origbound) {
429     //Try to skip over stuff fast first
430     unsigned INTPTR offset=(unsigned INTPTR) (origptr-gcbaseva);
431     unsigned INTPTR arrayoffset=ALIGNTOTABLEINDEX(offset);
432     if (!gcmarktbl[arrayoffset]) {
433       do {
434         arrayoffset++;
435         if (arrayoffset>=origendoffset) {
436           //finished with block(a page in CACHE_ADAPT version)...
437           to->ptr=toptr;
438           orig->ptr=origbound;
439           gccurr_heaptop-=(unsigned INTPTR)(toptr-toptrinit);
440 #ifdef GC_CACHE_ADAPT
441           BAMBOO_CACHE_FLUSH_LINE(lastflush);
442 #endif
443           return 0;
444         }
445       } while(!gcmarktbl[arrayoffset]);
446       origptr=CONVERTTABLEINDEXTOPTR(arrayoffset);
447     }
448     
449     //Scan more carefully next
450     objlength=getMarkedLength(origptr);
451
452     if (objlength!=NOTMARKED) {
453       unsigned int length=ALIGNSIZETOBYTES(objlength);
454
455       //code between this and next comment should be removed
456 #ifdef GC_DEBUG
457       unsigned int size;
458       unsigned int type;
459       gettype_size(origptr, &type, &size);
460       size=((size-1)&(~(ALIGNMENTSIZE-1)))+ALIGNMENTSIZE;
461       
462       if (size!=length) {
463         tprintf("BAD SIZE IN BITMAP: type=%u object=%x size=%u length=%u\n", type, origptr, size, length);
464         unsigned INTPTR alignsize=ALIGNOBJSIZE((unsigned INTPTR)(origptr-gcbaseva));
465         unsigned INTPTR hibits=alignsize>>4;
466         unsigned INTPTR lobits=(alignsize&15)<<1;
467         tprintf("hibits=%x lobits=%x\n", hibits, lobits);
468         tprintf("hi=%x lo=%x\n", gcmarktbl[hibits], gcmarktbl[hibits+1]);
469       }
470 #endif
471       //end of code to remove
472
473       void *endtoptr=toptr+length;
474       if (endtoptr>tobound) {
475         gccurr_heaptop-=(unsigned INTPTR)(toptr-toptrinit);
476         to->ptr=toptr;
477         orig->ptr=origptr;
478 #ifdef GC_CACHE_ADAPT
479         BAMBOO_CACHE_FLUSH_LINE(lastflush);
480 #endif
481         return length;
482       }
483       //good to move objects and update pointers
484       
485       void ** mapptr=&gcmappingtbl[OBJMAPPINGINDEX(origptr)];
486       *mapptr=toptr;
487
488 #ifdef GC_CACHE_ADAPT
489       void *maskmapptr=(void *)(((unsigned INTPTR)mapptr)&~(BAMBOO_CACHE_LINE_MASK));
490
491       if (lastflush!=maskmapptr) {
492         BAMBOO_CACHE_FLUSH_LINE(lastflush);
493         lastflush=maskmapptr;
494       }
495 #endif
496
497       origptr+=length;
498       toptr=endtoptr;
499     } else
500       origptr+=ALIGNMENTSIZE;
501   }
502   to->ptr=toptr;
503   orig->ptr=origptr;
504   gccurr_heaptop-=(unsigned INTPTR)(toptr-toptrinit);
505 #ifdef GC_CACHE_ADAPT
506   BAMBOO_CACHE_FLUSH_LINE(lastflush);
507 #endif
508   return 0;
509 }
510
511 void compact() {
512   BAMBOO_ASSERT(COMPACTPHASE == gc_status_info.gcphase);
513   
514   // initialize structs for compacting
515   struct moveHelper orig;
516   struct moveHelper to;
517   initOrig_Dst(&orig, &to);
518
519   compacthelper(&orig, &to);
520 #ifdef GC_CACHE_ADAPT
521   BAMBOO_CACHE_MF();
522 #endif
523
524
525 void master_compact() {
526   // predict number of blocks to fill for each core
527   numblockspercore = loadbalance()+1;
528   
529   GC_PRINTF("mark phase finished \n");
530   
531   gc_resetCoreStatus();
532   //initialize local data structures first....we don't want remote requests messing data up
533   unsigned int initblocks=numblockspercore*NUMCORES4GC;
534   allocationinfo.lowestfreeblock=NOFREEBLOCK;
535
536   //assigned blocks
537   for(int i=0;i<initblocks;i++) {
538     allocationinfo.blocktable[i].status=BS_USED;
539   }
540
541   //free blocks
542   for(int i=initblocks;i<GCNUMBLOCK;i++) {
543     allocationinfo.blocktable[i].status=BS_FREE;
544     allocationinfo.blocktable[i].usedspace=0;
545     //this is true because all cores have at least one block already...
546     allocationinfo.blocktable[i].freespace=BLOCKSIZE(1);
547   }
548
549   //start all of the cores
550   for(int i = 0; i < NUMCORES4GC; i++) {
551     // init some data strutures for compact phase
552     gcrequiredmems[i] = 0;
553     gccorestatus[i] = 1;
554     returnedmem[i] = 1;
555     //send start compact messages to all cores
556     if(i != STARTUPCORE) {
557       send_msg_2(i, GCSTARTCOMPACT, numblockspercore);
558     } else {
559       gcblock2fill = numblockspercore;
560     }
561   }
562   GCPROFILE_ITEM_MASTER();
563   // compact phase
564   compact();
565   /* wait for all cores to finish compacting */
566   GC_PRINTF("master finished\n");
567
568   while(!gc_checkCoreStatus())
569     ;
570
571 #ifdef GC_DEBUG
572   void *nextvalid=gcbaseva;
573   for(void *tmp=gcbaseva; tmp<gcbaseva+BAMBOO_SHARED_MEM_SIZE;tmp+=ALIGNMENTSIZE) {
574     unsigned int objlength=getMarkedLength(tmp);
575     void *forwarding=gcmappingtbl[OBJMAPPINGINDEX(tmp)];
576     if (tmp>=nextvalid&&((objlength!=0)!=(forwarding!=NULL))) {
577       tprintf("Maps disagree tmp=%x olength=%u forwarding=%x\n",tmp, objlength, forwarding);
578     }
579     if (tmp<nextvalid&&forwarding!=NULL) {
580       tprintf("Weird forwarding pointer\n");
581     }
582     if (tmp>=nextvalid&&(objlength!=0||forwarding!=NULL)) {
583       unsigned int length=ALIGNSIZETOBYTES(objlength);
584       unsigned int size;
585       unsigned int type;
586       nextvalid=tmp+length;
587       gettype_size(tmp, &type, &size);
588       size=((size-1)&(~(ALIGNMENTSIZE-1)))+ALIGNMENTSIZE;
589       if (size!=length) {
590         tprintf("Bad size in bitmap: tmp=%x length=%u size=%u type=%u\n", tmp, length, size, type);
591       }
592       block_t blockindex;
593       BLOCKINDEX(blockindex, forwarding);
594       struct blockrecord * block=&allocationinfo.blocktable[blockindex];
595       void *blockptr=OFFSET2BASEVA(blockindex)+gcbaseva;
596
597       if (block->status==BS_FREE) {
598         if (forwarding>(blockptr+block->usedspace)) {
599           tprintf("Pointer references free space forwarding=%x tmp=%x length=%u type=%u blockindex=%u, baseptr=%x, usedspace=%u, status=%u\n", forwarding, tmp, length, type,blockindex, blockptr, block->usedspace, block->status);
600         }
601       }
602     }
603   }
604 #endif
605
606   GCPROFILE_ITEM_MASTER();
607
608   //just in case we didn't get blocks back...
609   if (allocationinfo.lowestfreeblock==NOFREEBLOCK)
610     allocationinfo.lowestfreeblock=numblockspercore*NUMCORES4GC;
611
612   // compute live object space
613   GCPROFILE_RECORD_SPACE_MASTER();
614   GC_PRINTF("compact phase finished \n");
615 }
616
617 #endif // MULTICORE_GC