1 /* ---------------------------------------------------------------------------
2 Time-stamp: <Wed Mar 21 2001 16:32:23 Stardate: [-30]6363.44 hwloidl>
3 $Id: Global.c,v 1.4 2001/03/22 03:51:11 hwloidl Exp $
5 (c) The AQUA/Parade Projects, Glasgow University, 1995
6 The GdH/APART 624 Projects, Heriot-Watt University, Edinburgh, 1999
8 Global Address Manipulation.
10 The GALA and LAGA tables for mapping global addresses to local addresses
11 (i.e. heap pointers) are defined here. We use the generic hash tables
13 ------------------------------------------------------------------------- */
15 #ifdef PAR /* whole file */
19 //* Global tables and lists::
20 //* Fcts on GALA tables::
21 //* Interface to taskId-PE table::
22 //* Interface to LAGA table::
23 //* Interface to GALA table::
24 //* GC functions for GALA tables::
29 //@node Includes, Global tables and lists, Global Address Manipulation, Global Address Manipulation
30 //@subsection Includes
38 #include "ParallelRts.h"
41 #include "ParallelDebug.h"
48 @globalAddr@ structures are allocated in chunks to reduce malloc overhead.
51 //@node Global tables and lists, Fcts on GALA tables, Includes, Global Address Manipulation
52 //@subsection Global tables and lists
62 //@node Free lists, Hash tables, Global tables and lists, Global tables and lists
63 //@subsubsection Free lists
65 /* Free list of GALA entries */
66 GALA *freeGALAList = NULL;
68 /* Number of globalAddr cells to allocate in one go */
69 #define GCHUNK (1024 * sizeof(StgWord) / sizeof(GALA))
71 /* Free list of indirections */
73 //@cindex nextIndirection
74 static StgInt nextIndirection = 0;
75 //@cindex freeIndirections
76 GALA *freeIndirections = NULL;
78 /* The list of live indirections has to be marked for GC (see makeGlobal) */
79 //@cindex liveIndirections
80 GALA *liveIndirections = NULL;
82 /* The list of remote indirections has to be marked for GC (see setRemoteGA) */
83 //@cindex liveRemoteGAs
84 GALA *liveRemoteGAs = NULL;
86 //@node Hash tables, , Free lists, Global tables and lists
87 //@subsubsection Hash tables
89 /* Mapping global task ids PEs */
90 //@cindex taskIDtoPEtable
91 HashTable *taskIDtoPEtable = NULL;
93 static int nextPE = 0;
95 /* LAGA table: StgClosure* -> globalAddr*
96 (Remember: globalAddr = (GlobalTaskId, Slot, Weight))
97 Mapping local to global addresses (see interface below)
100 //@cindex LAtoGALAtable
101 HashTable *LAtoGALAtable = NULL;
103 /* GALA table: globalAddr* -> StgClosure*
104 (Remember: globalAddr = (GlobalTaskId, Slot, Weight))
105 Mapping global to local addresses (see interface below)
108 //@cindex pGAtoGALAtable
109 HashTable *pGAtoGALAtable = NULL;
111 //@node Fcts on GALA tables, Interface to taskId-PE table, Global tables and lists, Global Address Manipulation
112 //@subsection Fcts on GALA tables
120 if ((gl = freeGALAList) != NULL) {
122 ASSERT(gl->ga.weight==0xdead0add);
123 ASSERT(gl->la==(StgPtr)0xdead00aa));
124 freeGALAList = gl->next;
126 gl = (GALA *) stgMallocBytes(GCHUNK * sizeof(GALA), "allocGALA");
128 freeGALAList = gl + 1;
129 for (p = freeGALAList; p < gl + GCHUNK - 1; p++) {
132 p->ga.weight=0xdead0add;
133 p->la=(StgPtr)0xdead00aa);
135 /* last elem in the new block has NULL pointer in link field */
138 p->ga.weight=0xdead0add;
139 p->la=(StgPtr)0xdead00aa);
142 gl->ga.weight=0xdead0add;
143 gl->la=(StgPtr)0xdead00aa);
147 //@node Interface to taskId-PE table, Interface to LAGA table, Fcts on GALA tables, Global Address Manipulation
148 //@subsection Interface to taskId-PE table
151 We don't really like GLOBAL_TASK_ID, so we keep a table of TASK_ID to
152 PE mappings. The idea is that a PE identifier will fit in 16 bits, whereas
158 taskIDtoPE(GlobalTaskId gtid)
160 return ((PEs) lookupHashTable(taskIDtoPEtable, gtid));
163 //@cindex registerTask
165 registerTask(GlobalTaskId gtid) {
166 nextPE++; //start counting from 1
170 insertHashTable(taskIDtoPEtable, gtid, (void *) (StgWord) nextPE);
173 //@node Interface to LAGA table, Interface to GALA table, Interface to taskId-PE table, Global Address Manipulation
174 //@subsection Interface to LAGA table
177 The local address to global address mapping returns a globalAddr structure
178 (pe task id, slot, weight) for any closure in the local heap which has a
179 global identity. Such closures may be copies of normal form objects with
180 a remote `master' location, @FetchMe@ nodes referencing remote objects, or
181 globally visible objects in the local heap (for which we are the master).
191 /* We never look for GA's on indirections. -- unknown hacker
192 Well, in fact at the moment we do in the new RTS. -- HWL
193 ToDo: unwind INDs when entering them into the hash table
195 ASSERT(IS_INDIRECTION(addr) == NULL);
197 if ((gala = lookupHashTable(LAtoGALAtable, (StgWord) addr)) == NULL)
203 //@node Interface to GALA table, GC functions for GALA tables, Interface to LAGA table, Global Address Manipulation
204 //@subsection Interface to GALA table
207 We also manage a mapping of global addresses to local addresses, so that
208 we can ``common up'' multiple references to the same object as they arrive
209 in data packets from remote PEs.
211 The global address to local address mapping is actually managed via a
212 ``packed global address'' to GALA hash table. The packed global
213 address takes the interesting part of the @globalAddr@ structure
214 (i.e. the pe and slot fields) and packs them into a single word
215 suitable for hashing.
223 StgWord pga = PackGA(taskIDtoPE(ga->payload.gc.gtid), ga->payload.gc.slot);
226 if ((gala = (GALA *) lookupHashTable(pGAtoGALAtable, pga)) == NULL)
230 * Bypass any indirections when returning a local closure to
231 * the caller. Note that we do not short-circuit the entry in
232 * the GALA tables right now, because we would have to do a
233 * hash table delete and insert in the LAtoGALAtable to keep
234 * that table up-to-date for preferred GALA pairs. That's
235 * probably a bit expensive.
237 return UNWIND_IND((StgClosure *)(gala->la));
241 /* ga becomes non-preferred (e.g. due to CommonUp) */
246 StgWord pga = PackGA(taskIDtoPE(ga->payload.gc.gtid), ga->payload.gc.slot);
249 gala = (GALA *) lookupHashTable(pGAtoGALAtable, pga);
251 ASSERT(gala->preferred==rtsTrue);
252 gala->preferred = rtsFalse;
256 External references to our globally-visible closures are managed through an
257 indirection table. The idea is that the closure may move about as the result
258 of local garbage collections, but its global identity is determined by its
259 slot in the indirection table, which never changes.
261 The indirection table is maintained implicitly as part of the global
262 address to local address table. We need only keep track of the
263 highest numbered indirection index allocated so far, along with a free
264 list of lower numbered indices no longer in use.
268 Allocate an indirection slot for the closure currently at address @addr@.
271 //@cindex allocIndirection
273 allocIndirection(StgClosure *closure)
277 if ((gala = freeIndirections) != NULL) {
279 ASSERT(gala->ga.weight==0xdead0add);
280 ASSERT(gala->la==(StgPtr)0xdead00aa));
281 freeIndirections = gala->next;
285 ASSERT(gala->ga.weight==0xdead0add);
286 ASSERT(gala->la==(StgPtr)0xdead00aa));
287 gala->ga.payload.gc.gtid = mytid;
288 gala->ga.payload.gc.slot = nextIndirection++;
290 if (nextIndirection>=MAX_SLOTS)
291 barf("Cannot handle more than %d slots for GA in a sanity-checking setup (this is no error)"));
293 gala->ga.weight = MAX_GA_WEIGHT;
294 gala->la = (StgPtr)closure;
296 gala->next=(struct gala *)0xcccccccc);
301 This is only used for sanity checking (see LOOKS_LIKE_SLOT)
304 highest_slot (void) { return nextIndirection; }
307 Make a local closure globally visible.
309 Called from: GlobaliseAndPackGA
311 closure ... closure to be made visible
312 preferred ... should the new GA become the preferred one (normalle=y true)
314 Allocate a GALA structure and add it to the (logical) Indirections table,
315 by inserting it into the LAtoGALAtable hash table and putting it onto the
316 liveIndirections list (only if it is preferred).
318 We have to allocate an indirection slot for it, and update both the local
319 address to global address and global address to local address maps.
324 makeGlobal(closure, preferred)
328 /* check whether we already have a GA for this local closure */
329 GALA *oldGALA = lookupHashTable(LAtoGALAtable, (StgWord) closure);
330 /* create an entry in the LAGA table */
331 GALA *newGALA = allocIndirection(closure);
332 StgWord pga = PackGA(thisPE, newGALA->ga.payload.gc.slot);
335 ASSERT(newGALA->next==(struct gala *)0xcccccccc););
336 // ASSERT(HEAP_ALLOCED(closure)); // check that closure might point into the heap; might be static, though
337 ASSERT(GALAlookup(&(newGALA->ga)) == NULL);
339 /* global statistics gathering */
340 if (RtsFlags.ParFlags.ParStats.Global &&
341 RtsFlags.GcFlags.giveStats > NO_GC_STATS) {
342 globalParStats.local_alloc_GA++;
345 newGALA->la = (StgPtr)closure;
346 newGALA->preferred = preferred;
349 /* The new GA is now the preferred GA for the LA */
350 if (oldGALA != NULL) {
351 oldGALA->preferred = rtsFalse;
352 (void) removeHashTable(LAtoGALAtable, (StgWord) closure, (void *) oldGALA);
354 insertHashTable(LAtoGALAtable, (StgWord) closure, (void *) newGALA);
357 ASSERT(!isOnLiveIndTable(&(newGALA->ga)));
358 /* put the new GALA entry on the list of live indirections */
359 newGALA->next = liveIndirections;
360 liveIndirections = newGALA;
362 insertHashTable(pGAtoGALAtable, pga, (void *) newGALA);
364 return &(newGALA->ga);
368 Assign an existing remote global address to an existing closure.
370 Called from: Unpack in Pack.c
372 local_closure ... a closure that has just been unpacked
373 remote_ga ... the GA that came with it, ie. the name under which the
374 closure is known while being transferred
375 preferred ... should the new GA become the preferred one (normalle=y true)
377 Allocate a GALA structure and add it to the (logical) RemoteGA table,
378 by inserting it into the LAtoGALAtable hash table and putting it onto the
379 liveRemoteGAs list (only if it is preferred).
381 We do not retain the @globalAddr@ structure that's passed in as an argument,
382 so it can be a static in the calling routine.
385 //@cindex setRemoteGA
387 setRemoteGA(local_closure, remote_ga, preferred)
388 StgClosure *local_closure;
389 globalAddr *remote_ga;
392 /* old entry ie the one with the GA generated when sending off the closure */
393 GALA *oldGALA = lookupHashTable(LAtoGALAtable, (StgWord) local_closure);
394 /* alloc new entry and fill it with contents of the newly arrives GA */
395 GALA *newGALA = allocGALA();
396 StgWord pga = PackGA(taskIDtoPE(remote_ga->payload.gc.gtid),
397 remote_ga->payload.gc.slot);
399 ASSERT(remote_ga->payload.gc.gtid != mytid);
400 ASSERT(remote_ga->weight > 0);
401 ASSERT(GALAlookup(remote_ga) == NULL);
403 newGALA->ga = *remote_ga;
404 newGALA->la = (StgPtr)local_closure;
405 newGALA->preferred = preferred;
408 /* The new GA is now the preferred GA for the LA */
409 if (oldGALA != NULL) {
410 oldGALA->preferred = rtsFalse;
411 (void) removeHashTable(LAtoGALAtable, (StgWord) local_closure, (void *) oldGALA);
413 insertHashTable(LAtoGALAtable, (StgWord) local_closure, (void *) newGALA);
416 ASSERT(!isOnRemoteGATable(&(newGALA->ga)));
417 /* add new entry to the (logical) RemoteGA table */
418 newGALA->next = liveRemoteGAs;
419 liveRemoteGAs = newGALA;
421 insertHashTable(pGAtoGALAtable, pga, (void *) newGALA);
424 The weight carried by the incoming closure is transferred to the newGALA
425 entry (via the structure assign above). Therefore, we have to give back
426 the weight to the GA on the other processor, because that indirection is
429 remote_ga->weight = 0;
430 return &(newGALA->ga);
434 Give me a bit of weight to give away on a new reference to a particular
435 global address. If we run down to nothing, we have to assign a new GA.
438 //@cindex splitWeight
441 splitWeight(to, from)
442 globalAddr *to, *from;
444 /* Make sure we have enough weight to split */
445 if (from->weight!=MAX_GA_WEIGHT && from->weight<=3) // fixed by UK in Eden implementation
446 from = makeGlobal(GALAlookup(from), rtsTrue);
448 to->payload = from->payload;
450 if (from->weight == MAX_GA_WEIGHT)
451 to->weight = 1L << (BITS_IN(unsigned) - 1);
453 to->weight = from->weight / 2;
455 from->weight -= to->weight;
459 splitWeight(to, from)
460 globalAddr *to, *from;
462 /* Make sure we have enough weight to split */
463 /* Splitting at 2 needed, as weight 1 is not legal in packets (UK+KH) */
465 if (from->weight / 2 <= 2) /* old: weight== 1 (UK) */
466 from = makeGlobal(GALAlookup(from), rtsTrue);
468 to->payload = from->payload;
470 if (from->weight <= 1) /* old == 0 (UK) */
471 to->weight = 1L << (BITS_IN(unsigned) - 1);
473 to->weight = from->weight / 2;
475 from->weight -= to->weight;
479 Here, I am returning a bit of weight that a remote PE no longer needs.
490 ASSERT(LOOKS_LIKE_GA(ga));
492 pga = PackGA(taskIDtoPE(ga->payload.gc.gtid), ga->payload.gc.slot);
493 gala = (GALA *) lookupHashTable(pGAtoGALAtable, pga);
496 fprintf(stderr, "@* Adding weight %x to ", ga->weight);
497 printGA(&(gala->ga));
498 fputc('\n', stderr));
500 gala->ga.weight += ga->weight;
507 Initialize all of the global address structures: the task ID to PE id
508 map, the local address to global address map, the global address to
509 local address map, and the indirection table.
512 //@cindex initGAtables
516 taskIDtoPEtable = allocHashTable();
517 LAtoGALAtable = allocHashTable();
518 pGAtoGALAtable = allocHashTable();
527 int pe_shift = (BITS_IN(StgWord)*3)/4;
528 int pe_bits = BITS_IN(StgWord) - pe_shift;
530 if ( pe_bits < 8 || slot >= (1L << pe_shift) ) { /* big trouble */
532 fprintf(stderr, "PackGA: slot# too big (%d) or not enough pe_bits (%d)\n",
534 stg_exit(EXIT_FAILURE);
537 return((((StgWord)(pe)) << pe_shift) | ((StgWord)(slot)));
539 /* the idea is to use 3/4 of the bits (e.g., 24) for indirection-
540 table "slot", and 1/4 for the pe# (e.g., 8).
542 We check for too many bits in "slot", and double-check (at
543 compile-time?) that we have enough bits for "pe". We *don't*
544 check for too many bits in "pe", because SysMan enforces a
545 MAX_PEs limit at the very very beginning.
551 //@node GC functions for GALA tables, Debugging routines, Interface to GALA table, Global Address Manipulation
552 //@subsection GC functions for GALA tables
555 When we do a copying collection, we want to evacuate all of the local
556 entries in the GALA table for which there are outstanding remote
557 pointers (i.e. for which the weight is not MAX_GA_WEIGHT.)
558 This routine has to be run BEFORE doing the GC proper (it's a
559 ``mark roots'' thing).
561 //@cindex markLocalGAs
563 markLocalGAs(rtsBool full)
565 GALA *gala, *next, *prev = NULL;
566 StgPtr old_la, new_la;
567 nat n=0, m=0; // debugging only
568 double start_time_GA; // stats only
571 belch("@@%%%% markLocalGAs (full=%d): Marking LIVE INDIRECTIONS in GALA table starting with GALA at %p\n",
572 full, liveIndirections);
575 PAR_TICKY_MARK_LOCAL_GAS_START();
577 for (gala = liveIndirections, m=0; gala != NULL; gala = next, m++) {
580 printGA(&(gala->ga));
581 fprintf(stderr, ";@ %d: LA: %p (%s) ",
582 m, (void*)gala->la, info_type((StgClosure*)gala->la)));
585 ASSERT(gala->ga.payload.gc.gtid == mytid); /* it's supposed to be local */
586 if (gala->ga.weight != MAX_GA_WEIGHT) {
587 /* Remote references exist, so we must evacuate the local closure */
588 if (get_itbl((StgClosure *)old_la)->type == EVACUATED) {
589 /* somebody else already evacuated this closure */
590 new_la = (StgPtr)((StgEvacuated *)old_la)->evacuee;
592 belch(" already evacuated to %p", new_la));
595 /* unwind any indirections we find */
596 StgClosure *foo = UNWIND_IND((StgClosure *)old_la) ; // debugging only
597 //ASSERT(HEAP_ALLOCED(foo));
600 new_la = (StgPtr) MarkRoot(foo);
602 belch(" evacuated %p to %p", foo, new_la));
603 /* ToDo: is this the right assertion to check that new_la is in to-space?
604 ASSERT(!HEAP_ALLOCED(new_la) || Bdescr(new_la)->evacuated);
607 new_la = MarkRoot(old_la); // or just evacuate(old_ga)
609 belch(" evacuated %p to %p", old_la, new_la));
614 /* remove old LA and replace with new LA */
615 if (/* !full && */ gala->preferred && new_la != old_la) {
617 ASSERT(lookupHashTable(LAtoGALAtable, (StgWord)old_la));
618 (void) removeHashTable(LAtoGALAtable, (StgWord) old_la, (void *) gala);
619 if ((q = lookupHashTable(LAtoGALAtable, (StgWord) new_la))!=NULL) {
620 if (q->preferred && gala->preferred) {
621 q->preferred = rtsFalse;
623 fprintf(stderr, "@@## found hash entry for closure %p (%s): deprecated GA ",
624 new_la, info_type((StgClosure*)new_la));
626 fputc('\n', stderr));
629 insertHashTable(LAtoGALAtable, (StgWord) new_la, (void *) gala);
632 belch("__## Hash table update (%p --> %p): ",
638 } else if(LOOKS_LIKE_STATIC_CLOSURE(gala->la)) {
639 /* to handle the CAFs, is this all?*/
642 belch(" processed static closure"));
647 /* Since we have all of the weight, this GA is no longer needed */
648 StgWord pga = PackGA(thisPE, gala->ga.payload.gc.slot);
651 belch("@@!! Freeing slot %d",
652 gala->ga.payload.gc.slot));
653 /* put gala on free indirections list */
654 gala->next = freeIndirections;
655 freeIndirections = gala;
656 (void) removeHashTable(pGAtoGALAtable, pga, (void *) gala);
657 if (/* !full && */ gala->preferred)
658 (void) removeHashTable(LAtoGALAtable, (W_) gala->la, (void *) gala);
661 gala->ga.weight = 0xdead0add;
662 gala->la = (StgPtr) 0xdead00aa);
665 liveIndirections = prev; /* list has been reversed during the marking */
668 PAR_TICKY_MARK_LOCAL_GAS_END(n);
671 belch("@@%%%% markLocalGAs: %d of %d GALAs marked on PE %x",
676 Traverse the GALA table: for every live remote GA check whether it has been
677 touched during GC; if not it is not needed locally and we can free the
678 closure (i.e. let go of its heap space and send a free message to the
680 This routine has to be run AFTER doing the GC proper.
683 rebuildGAtables(rtsBool full)
685 GALA *gala, *next, *prev;
687 nat n = 0, size_GA = 0; // stats only (no. of GAs, and their heap size in bytes)
690 belch("@@%%%% rebuildGAtables (full=%d): rebuilding LIVE REMOTE GAs in GALA table starting with GALA at %p\n",
691 full, liveRemoteGAs));
693 PAR_TICKY_REBUILD_GA_TABLES_START();
695 prepareFreeMsgBuffers();
697 for (gala = liveRemoteGAs, prev = NULL; gala != NULL; gala = next) {
699 printGA(&(gala->ga)));
701 ASSERT(gala->ga.payload.gc.gtid != mytid); /* it's supposed to be remote */
703 closure = (StgClosure *) (gala->la);
705 fprintf(stderr, " %p (%s) ",
706 (StgClosure *)closure, info_type(closure)));
708 if (/* !full && */ gala->preferred)
709 (void) removeHashTable(LAtoGALAtable, (StgWord) gala->la, (void *) gala);
711 /* Follow indirection chains to the end, just in case */
712 // should conform with unwinding in markLocalGAs
713 closure = UNWIND_IND(closure);
716 If closure has been evacuated it is live; otherwise it's dead and we
717 can nuke the GA attached to it in the LAGA table.
718 This approach also drops global aliases for PLCs.
721 //ASSERT(!HEAP_ALLOCED(closure) || !(Bdescr((StgPtr)closure)->evacuated));
722 if (get_itbl(closure)->type == EVACUATED) {
723 closure = ((StgEvacuated *)closure)->evacuee;
725 fprintf(stderr, " EVAC %p (%s)\n",
726 closure, info_type(closure)));
728 /* closure is not alive any more, thus remove GA and send free msg */
729 int pe = taskIDtoPE(gala->ga.payload.gc.gtid);
730 StgWord pga = PackGA(pe, gala->ga.payload.gc.slot);
732 /* check that the block containing this closure is not in to-space */
734 fprintf(stderr, " !EVAC %p (%s); sending free to PE %d\n",
735 closure, info_type(closure), pe));
737 (void) removeHashTable(pGAtoGALAtable, pga, (void *) gala);
738 freeRemoteGA(pe-1, &(gala->ga)); //-1 cause ids start at 1... not 0
739 gala->next = freeGALAList;
742 gala->ga.weight = 0xdead0add;
743 gala->la = (StgPtr)0xdead00aa);
746 gala->la = (StgPtr)closure;
747 if (/* !full && */ gala->preferred) {
749 if ((q = lookupHashTable(LAtoGALAtable, (StgWord) gala->la))!=NULL) {
750 if (q->preferred && gala->preferred) {
751 q->preferred = rtsFalse;
753 fprintf(stderr, "@@## found hash entry for closure %p (%s): deprecated GA ",
754 gala->la, info_type((StgClosure*)gala->la));
756 fputc('\n', stderr));
759 insertHashTable(LAtoGALAtable, (StgWord) gala->la, (void *) gala);
764 /* Global statistics: count GAs and total size
765 if (RtsFlags.ParFlags.ParStats.Global &&
766 RtsFlags.GcFlags.giveStats > NO_GC_STATS) {
768 nat size, ptrs, nonptrs, vhs, i;
771 info = get_closure_info(closure, &size, &ptrs, &nonptrs, &vhs, str);
774 n++; // stats: count number of GAs we add to the new table
778 liveRemoteGAs = prev; /* list is reversed during marking */
780 /* If we have any remaining FREE messages to send off, do so now */
783 PAR_TICKY_CNT_FREE_GA();
787 checkFreeIndirectionsList());
791 #if defined(PAR_TICKY)
792 getLAGAtableSize(&n, &size_GA); // determine no of GAs and global heap
793 PAR_TICKY_REBUILD_GA_TABLES_END(n, size_GA); // record these values
797 belch("@#%%%% rebuildGAtables: After ReBuilding GALA table starting with GALA at %p",
803 Rebuild the LA->GA table, assuming that the addresses in the GALAs are
805 A word on the lookupHashTable check in both loops:
806 After GC we may end up with 2 preferred GAs for the same LA! For example,
807 if we received a closure whose GA already exists on this PE we CommonUp
808 both closures, making one an indirection to the other. Before GC everything
809 is fine: one preferred GA refers to the IND, the other preferred GA refers
810 to the closure it points to. After GC, however, we have short cutted the
811 IND and suddenly we have 2 preferred GAs for the same closure. We detect
812 this case in the loop below and deprecate one GA, so that we always just
813 have one preferred GA per LA.
816 //@cindex rebuildLAGAtable
818 rebuildLAGAtable(void)
821 nat n=0, m=0; // debugging
823 /* The old LA->GA table is worthless */
824 freeHashTable(LAtoGALAtable, NULL);
825 LAtoGALAtable = allocHashTable();
828 belch("@@%%%% rebuildLAGAtable: new LAGA table at %p",
831 for (gala = liveIndirections; gala != NULL; gala = gala->next) {
833 if (gala->preferred) {
835 if ((q = lookupHashTable(LAtoGALAtable, (StgWord) gala->la))!=NULL) {
836 if (q->preferred && gala->preferred) {
837 /* this deprecates q (see also GALAdeprecate) */
838 q->preferred = rtsFalse;
839 (void) removeHashTable(LAtoGALAtable, (StgWord) gala->la, (void *)q);
841 fprintf(stderr, "@@## found hash entry for closure %p (%s): deprecated GA ",
842 gala->la, info_type((StgClosure*)gala->la));
844 fputc('\n', stderr));
847 insertHashTable(LAtoGALAtable, (StgWord) gala->la, (void *) gala);
851 for (gala = liveRemoteGAs; gala != NULL; gala = gala->next) {
853 if (gala->preferred) {
855 if ((q = lookupHashTable(LAtoGALAtable, (StgWord) gala->la))!=NULL) {
856 if (q->preferred && gala->preferred) {
857 /* this deprecates q (see also GALAdeprecate) */
858 q->preferred = rtsFalse;
859 (void) removeHashTable(LAtoGALAtable, (StgWord) gala->la, (void *)q);
861 fprintf(stderr, "@@## found hash entry for closure %p (%s): deprecated GA ",
862 (StgClosure*)gala->la, info_type((StgClosure*)gala->la));
864 fputc('\n', stderr));
867 insertHashTable(LAtoGALAtable, (StgWord) gala->la, (void *) gala);
872 belch("@@%%%% rebuildLAGAtable: inserted %d entries from liveIndirections and %d entries from liveRemoteGAs",
877 Determine the size of the LAGA and GALA tables.
878 Has to be done after rebuilding the tables.
879 Only used for global statistics gathering.
882 //@cindex getLAGAtableSize
884 getLAGAtableSize(nat *nP, nat *sizeP)
887 // nat n=0, tot_size=0;
890 nat size, ptrs, nonptrs, vhs, i;
892 /* IN order to avoid counting closures twice we maintain a hash table
893 of all closures seen so far.
894 ToDo: collect this data while rebuilding the GALA table and make use
895 of the existing hash tables;
897 HashTable *closureTable; // hash table for closures encountered already
899 closureTable = allocHashTable();
901 (*nP) = (*sizeP) = 0;
902 for (gala = liveIndirections; gala != NULL; gala = gala->next) {
903 closure = (StgClosure*) gala->la;
904 if (lookupHashTable(closureTable, (StgWord)closure)==NULL) { // not seen yet
905 insertHashTable(closureTable, (StgWord)closure, (void *)1);
906 info = get_closure_info(closure, &size, &ptrs, &nonptrs, &vhs, str);
907 (*sizeP) += size ; // stats: measure total heap size of global closures
908 (*nP)++; // stats: count number of GAs
912 for (gala = liveRemoteGAs; gala != NULL; gala = gala->next) {
913 closure = (StgClosure*) gala->la;
914 if (lookupHashTable(closureTable, (StgWord)closure)==NULL) { // not seen yet
915 insertHashTable(closureTable, (StgWord)closure, (void *)1);
916 info = get_closure_info(closure, &size, &ptrs, &nonptrs, &vhs, str);
917 (*sizeP) += size ; // stats: measure total heap size of global closures
918 (*nP)++; // stats: count number of GAs
922 freeHashTable(closureTable, NULL);
925 //@node Debugging routines, Index, GC functions for GALA tables, Global Address Manipulation
926 //@subsection Debugging routines
930 printGA (globalAddr *ga)
932 fprintf(stderr, "((%x, %d, %x))",
940 printGALA (GALA *gala)
942 printGA(&(gala->ga));
943 fprintf(stderr, " -> %p (%s)",
944 (StgClosure*)gala->la, info_type((StgClosure*)gala->la));
945 fprintf(stderr, " %s",
946 (gala->preferred) ? "PREF" : "____");
950 Printing the LA->GA table.
953 //@cindex printLiveIndTable
955 printLiveIndTable(void)
958 nat n=0; // debugging
960 belch("@@%%%%:: logical LiveIndTable (%p) (liveIndirections=%p):",
961 LAtoGALAtable, liveIndirections);
963 for (gala = liveIndirections; gala != NULL; gala = gala->next) {
966 /* check whether this gala->la is hashed into the LAGA table */
967 q = lookupHashTable(LAtoGALAtable, (StgWord)(gala->la));
968 fprintf(stderr, "\t%s\n", (q==NULL) ? "...." : (q==gala) ? "====" : "####");
969 //ASSERT(lookupHashTable(LAtoGALAtable, (StgWord)(gala->la)));
971 belch("@@%%%%:: %d live indirections",
976 printRemoteGATable(void)
979 nat m=0; // debugging
981 belch("@@%%%%:: logical RemoteGATable (%p) (liveRemoteGAs=%p):",
982 LAtoGALAtable, liveRemoteGAs);
984 for (gala = liveRemoteGAs; gala != NULL; gala = gala->next) {
987 /* check whether this gala->la is hashed into the LAGA table */
988 q = lookupHashTable(LAtoGALAtable, (StgWord)(gala->la));
989 fprintf(stderr, "\t%s\n", (q==NULL) ? "...." : (q==gala) ? "====" : "####");
990 // ASSERT(lookupHashTable(LAtoGALAtable, (StgWord)(gala->la)));
992 belch("@@%%%%:: %d remote GAs",
996 //@cindex printLAGAtable
1000 belch("@@%%: LAGAtable (%p) with liveIndirections=%p, liveRemoteGAs=%p:",
1001 LAtoGALAtable, liveIndirections, liveRemoteGAs);
1003 printLiveIndTable();
1004 printRemoteGATable();
1008 Check whether a GA is already in a list.
1011 isOnLiveIndTable(globalAddr *ga)
1015 for (gala = liveIndirections; gala != NULL; gala = gala->next)
1016 if (gala->ga.weight==ga->weight &&
1017 gala->ga.payload.gc.slot==ga->payload.gc.slot &&
1018 gala->ga.payload.gc.gtid==ga->payload.gc.gtid)
1025 isOnRemoteGATable(globalAddr *ga)
1029 for (gala = liveRemoteGAs; gala != NULL; gala = gala->next)
1030 if (gala->ga.weight==ga->weight &&
1031 gala->ga.payload.gc.slot==ga->payload.gc.slot &&
1032 gala->ga.payload.gc.gtid==ga->payload.gc.gtid)
1039 Sanity check for free lists.
1042 checkFreeGALAList(void) {
1045 for (gl=freeGALAList; gl != NULL; gl=gl->next) {
1046 ASSERT(gl->ga.weight==0xdead0add);
1047 ASSERT(gl->la==(StgPtr)0xdead00aa);
1052 checkFreeIndirectionsList(void) {
1055 for (gl=freeIndirections; gl != NULL; gl=gl->next) {
1056 ASSERT(gl->ga.weight==0xdead0add);
1057 ASSERT(gl->la==(StgPtr)0xdead00aa);
1060 #endif /* PAR -- whole file */
1062 //@node Index, , Debugging routines, Global Address Manipulation
1066 //* DebugPrintLAGAtable:: @cindex\s-+DebugPrintLAGAtable
1067 //* GALAlookup:: @cindex\s-+GALAlookup
1068 //* LAGAlookup:: @cindex\s-+LAGAlookup
1069 //* LAtoGALAtable:: @cindex\s-+LAtoGALAtable
1070 //* PackGA:: @cindex\s-+PackGA
1071 //* addWeight:: @cindex\s-+addWeight
1072 //* allocGALA:: @cindex\s-+allocGALA
1073 //* allocIndirection:: @cindex\s-+allocIndirection
1074 //* freeIndirections:: @cindex\s-+freeIndirections
1075 //* initGAtables:: @cindex\s-+initGAtables
1076 //* liveIndirections:: @cindex\s-+liveIndirections
1077 //* liveRemoteGAs:: @cindex\s-+liveRemoteGAs
1078 //* makeGlobal:: @cindex\s-+makeGlobal
1079 //* markLocalGAs:: @cindex\s-+markLocalGAs
1080 //* nextIndirection:: @cindex\s-+nextIndirection
1081 //* pGAtoGALAtable:: @cindex\s-+pGAtoGALAtable
1082 //* printGA:: @cindex\s-+printGA
1083 //* printGALA:: @cindex\s-+printGALA
1084 //* rebuildLAGAtable:: @cindex\s-+rebuildLAGAtable
1085 //* registerTask:: @cindex\s-+registerTask
1086 //* setRemoteGA:: @cindex\s-+setRemoteGA
1087 //* splitWeight:: @cindex\s-+splitWeight
1088 //* taskIDtoPE:: @cindex\s-+taskIDtoPE
1089 //* taskIDtoPEtable:: @cindex\s-+taskIDtoPEtable
1090 //* thisPE:: @cindex\s-+thisPE