+++ /dev/null
-/* ---------------------------------------------------------------------------
- Time-stamp: <Wed Mar 21 2001 16:32:23 Stardate: [-30]6363.44 hwloidl>
-
- (c) The AQUA/Parade Projects, Glasgow University, 1995
- The GdH/APART 624 Projects, Heriot-Watt University, Edinburgh, 1999
-
- Global Address Manipulation.
-
- The GALA and LAGA tables for mapping global addresses to local addresses
- (i.e. heap pointers) are defined here. We use the generic hash tables
- defined in Hash.c.
- ------------------------------------------------------------------------- */
-
-#ifdef PAR /* whole file */
-
-//@menu
-//* Includes::
-//* Global tables and lists::
-//* Fcts on GALA tables::
-//* Interface to taskId-PE table::
-//* Interface to LAGA table::
-//* Interface to GALA table::
-//* GC functions for GALA tables::
-//* Index::
-//@end menu
-//*/
-
-//@node Includes, Global tables and lists, Global Address Manipulation, Global Address Manipulation
-//@subsection Includes
-
-#include "Rts.h"
-#include "RtsFlags.h"
-#include "RtsUtils.h"
-#include "Storage.h"
-#include "Hash.h"
-#include "HLC.h"
-#include "ParallelRts.h"
-#if defined(DEBUG)
-# include "Sanity.h"
-#include "ParallelDebug.h"
-#endif
-#if defined(DIST)
-# include "Dist.h"
-#endif
-
-/*
- @globalAddr@ structures are allocated in chunks to reduce malloc overhead.
-*/
-
-//@node Global tables and lists, Fcts on GALA tables, Includes, Global Address Manipulation
-//@subsection Global tables and lists
-
-//@cindex thisPE
-nat thisPE;
-
-//@menu
-//* Free lists::
-//* Hash tables::
-//@end menu
-
-//@node Free lists, Hash tables, Global tables and lists, Global tables and lists
-//@subsubsection Free lists
-
-/* Free list of GALA entries */
-GALA *freeGALAList = NULL;
-
-/* Number of globalAddr cells to allocate in one go */
-#define GCHUNK (1024 * sizeof(StgWord) / sizeof(GALA))
-
-/* Free list of indirections */
-
-//@cindex nextIndirection
-static StgInt nextIndirection = 0;
-//@cindex freeIndirections
-GALA *freeIndirections = NULL;
-
-/* The list of live indirections has to be marked for GC (see makeGlobal) */
-//@cindex liveIndirections
-GALA *liveIndirections = NULL;
-
-/* The list of remote indirections has to be marked for GC (see setRemoteGA) */
-//@cindex liveRemoteGAs
-GALA *liveRemoteGAs = NULL;
-
-//@node Hash tables, , Free lists, Global tables and lists
-//@subsubsection Hash tables
-
-/* Mapping global task ids PEs */
-//@cindex taskIDtoPEtable
-HashTable *taskIDtoPEtable = NULL;
-
-static int nextPE = 0;
-
-/* LAGA table: StgClosure* -> globalAddr*
- (Remember: globalAddr = (GlobalTaskId, Slot, Weight))
- Mapping local to global addresses (see interface below)
-*/
-
-//@cindex LAtoGALAtable
-HashTable *LAtoGALAtable = NULL;
-
-/* GALA table: globalAddr* -> StgClosure*
- (Remember: globalAddr = (GlobalTaskId, Slot, Weight))
- Mapping global to local addresses (see interface below)
-*/
-
-//@cindex pGAtoGALAtable
-HashTable *pGAtoGALAtable = NULL;
-
-//@node Fcts on GALA tables, Interface to taskId-PE table, Global tables and lists, Global Address Manipulation
-//@subsection Fcts on GALA tables
-
-//@cindex allocGALA
-static GALA *
-allocGALA(void)
-{
- GALA *gl, *p;
-
- if ((gl = freeGALAList) != NULL) {
- IF_DEBUG(sanity,
- ASSERT(gl->ga.weight==0xdead0add);
- ASSERT(gl->la==(StgPtr)0xdead00aa));
- freeGALAList = gl->next;
- } else {
- gl = (GALA *) stgMallocBytes(GCHUNK * sizeof(GALA), "allocGALA");
-
- freeGALAList = gl + 1;
- for (p = freeGALAList; p < gl + GCHUNK - 1; p++) {
- p->next = p + 1;
- IF_DEBUG(sanity,
- p->ga.weight=0xdead0add;
- p->la=(StgPtr)0xdead00aa);
- }
- /* last elem in the new block has NULL pointer in link field */
- p->next = NULL;
- IF_DEBUG(sanity,
- p->ga.weight=0xdead0add;
- p->la=(StgPtr)0xdead00aa);
- }
- IF_DEBUG(sanity,
- gl->ga.weight=0xdead0add;
- gl->la=(StgPtr)0xdead00aa);
- return gl;
-}
-
-//@node Interface to taskId-PE table, Interface to LAGA table, Fcts on GALA tables, Global Address Manipulation
-//@subsection Interface to taskId-PE table
-
-/*
- We don't really like GLOBAL_TASK_ID, so we keep a table of TASK_ID to
- PE mappings. The idea is that a PE identifier will fit in 16 bits, whereas
- a TASK_ID may not.
-*/
-
-//@cindex taskIDtoPE
-PEs
-taskIDtoPE(GlobalTaskId gtid)
-{
- return ((PEs) lookupHashTable(taskIDtoPEtable, gtid));
-}
-
-//@cindex registerTask
-void
-registerTask(GlobalTaskId gtid) {
- nextPE++; //start counting from 1
- if (gtid == mytid)
- thisPE = nextPE;
-
- insertHashTable(taskIDtoPEtable, gtid, (void *) (StgWord) nextPE);
-}
-
-//@node Interface to LAGA table, Interface to GALA table, Interface to taskId-PE table, Global Address Manipulation
-//@subsection Interface to LAGA table
-
-/*
- The local address to global address mapping returns a globalAddr structure
- (pe task id, slot, weight) for any closure in the local heap which has a
- global identity. Such closures may be copies of normal form objects with
- a remote `master' location, @FetchMe@ nodes referencing remote objects, or
- globally visible objects in the local heap (for which we are the master).
-*/
-
-//@cindex LAGAlookup
-globalAddr *
-LAGAlookup(addr)
-StgClosure *addr;
-{
- GALA *gala;
-
- /* We never look for GA's on indirections. -- unknown hacker
- Well, in fact at the moment we do in the new RTS. -- HWL
- ToDo: unwind INDs when entering them into the hash table
-
- ASSERT(IS_INDIRECTION(addr) == NULL);
- */
- if ((gala = lookupHashTable(LAtoGALAtable, (StgWord) addr)) == NULL)
- return NULL;
- else
- return &(gala->ga);
-}
-
-//@node Interface to GALA table, GC functions for GALA tables, Interface to LAGA table, Global Address Manipulation
-//@subsection Interface to GALA table
-
-/*
- We also manage a mapping of global addresses to local addresses, so that
- we can ``common up'' multiple references to the same object as they arrive
- in data packets from remote PEs.
-
- The global address to local address mapping is actually managed via a
- ``packed global address'' to GALA hash table. The packed global
- address takes the interesting part of the @globalAddr@ structure
- (i.e. the pe and slot fields) and packs them into a single word
- suitable for hashing.
-*/
-
-//@cindex GALAlookup
-StgClosure *
-GALAlookup(ga)
-globalAddr *ga;
-{
- StgWord pga = PackGA(taskIDtoPE(ga->payload.gc.gtid), ga->payload.gc.slot);
- GALA *gala;
-
- if ((gala = (GALA *) lookupHashTable(pGAtoGALAtable, pga)) == NULL)
- return NULL;
- else {
- /*
- * Bypass any indirections when returning a local closure to
- * the caller. Note that we do not short-circuit the entry in
- * the GALA tables right now, because we would have to do a
- * hash table delete and insert in the LAtoGALAtable to keep
- * that table up-to-date for preferred GALA pairs. That's
- * probably a bit expensive.
- */
- return UNWIND_IND((StgClosure *)(gala->la));
- }
-}
-
-/* ga becomes non-preferred (e.g. due to CommonUp) */
-void
-GALAdeprecate(ga)
-globalAddr *ga;
-{
- StgWord pga = PackGA(taskIDtoPE(ga->payload.gc.gtid), ga->payload.gc.slot);
- GALA *gala;
-
- gala = (GALA *) lookupHashTable(pGAtoGALAtable, pga);
- ASSERT(gala!=NULL);
- ASSERT(gala->preferred==rtsTrue);
- gala->preferred = rtsFalse;
-}
-
-/*
- External references to our globally-visible closures are managed through an
- indirection table. The idea is that the closure may move about as the result
- of local garbage collections, but its global identity is determined by its
- slot in the indirection table, which never changes.
-
- The indirection table is maintained implicitly as part of the global
- address to local address table. We need only keep track of the
- highest numbered indirection index allocated so far, along with a free
- list of lower numbered indices no longer in use.
-*/
-
-/*
- Allocate an indirection slot for the closure currently at address @addr@.
-*/
-
-//@cindex allocIndirection
-static GALA *
-allocIndirection(StgClosure *closure)
-{
- GALA *gala;
-
- if ((gala = freeIndirections) != NULL) {
- IF_DEBUG(sanity,
- ASSERT(gala->ga.weight==0xdead0add);
- ASSERT(gala->la==(StgPtr)0xdead00aa));
- freeIndirections = gala->next;
- } else {
- gala = allocGALA();
- IF_DEBUG(sanity,
- ASSERT(gala->ga.weight==0xdead0add);
- ASSERT(gala->la==(StgPtr)0xdead00aa));
- gala->ga.payload.gc.gtid = mytid;
- gala->ga.payload.gc.slot = nextIndirection++;
- IF_DEBUG(sanity,
- if (nextIndirection>=MAX_SLOTS)
- barf("Cannot handle more than %d slots for GA in a sanity-checking setup (this is no error)"));
- }
- gala->ga.weight = MAX_GA_WEIGHT;
- gala->la = (StgPtr)closure;
- IF_DEBUG(sanity,
- gala->next=(struct gala *)0xcccccccc);
- return gala;
-}
-
-/*
- This is only used for sanity checking (see LOOKS_LIKE_SLOT)
-*/
-StgInt
-highest_slot (void) { return nextIndirection; }
-
-/*
- Make a local closure globally visible.
-
- Called from: GlobaliseAndPackGA
- Args:
- closure ... closure to be made visible
- preferred ... should the new GA become the preferred one (normalle=y true)
-
- Allocate a GALA structure and add it to the (logical) Indirections table,
- by inserting it into the LAtoGALAtable hash table and putting it onto the
- liveIndirections list (only if it is preferred).
-
- We have to allocate an indirection slot for it, and update both the local
- address to global address and global address to local address maps.
-*/
-
-//@cindex makeGlobal
-globalAddr *
-makeGlobal(closure, preferred)
-StgClosure *closure;
-rtsBool preferred;
-{
- /* check whether we already have a GA for this local closure */
- GALA *oldGALA = lookupHashTable(LAtoGALAtable, (StgWord) closure);
- /* create an entry in the LAGA table */
- GALA *newGALA = allocIndirection(closure);
- StgWord pga = PackGA(thisPE, newGALA->ga.payload.gc.slot);
-
- IF_DEBUG(sanity,
- ASSERT(newGALA->next==(struct gala *)0xcccccccc););
- // ASSERT(HEAP_ALLOCED(closure)); // check that closure might point into the heap; might be static, though
- ASSERT(GALAlookup(&(newGALA->ga)) == NULL);
-
- /* global statistics gathering */
- if (RtsFlags.ParFlags.ParStats.Global &&
- RtsFlags.GcFlags.giveStats > NO_GC_STATS) {
- globalParStats.local_alloc_GA++;
- }
-
- newGALA->la = (StgPtr)closure;
- newGALA->preferred = preferred;
-
- if (preferred) {
- /* The new GA is now the preferred GA for the LA */
- if (oldGALA != NULL) {
- oldGALA->preferred = rtsFalse;
- (void) removeHashTable(LAtoGALAtable, (StgWord) closure, (void *) oldGALA);
- }
- insertHashTable(LAtoGALAtable, (StgWord) closure, (void *) newGALA);
- }
-
- ASSERT(!isOnLiveIndTable(&(newGALA->ga)));
- /* put the new GALA entry on the list of live indirections */
- newGALA->next = liveIndirections;
- liveIndirections = newGALA;
-
- insertHashTable(pGAtoGALAtable, pga, (void *) newGALA);
-
- return &(newGALA->ga);
-}
-
-/*
- Assign an existing remote global address to an existing closure.
-
- Called from: Unpack in Pack.c
- Args:
- local_closure ... a closure that has just been unpacked
- remote_ga ... the GA that came with it, ie. the name under which the
- closure is known while being transferred
- preferred ... should the new GA become the preferred one (normalle=y true)
-
- Allocate a GALA structure and add it to the (logical) RemoteGA table,
- by inserting it into the LAtoGALAtable hash table and putting it onto the
- liveRemoteGAs list (only if it is preferred).
-
- We do not retain the @globalAddr@ structure that's passed in as an argument,
- so it can be a static in the calling routine.
-*/
-
-//@cindex setRemoteGA
-globalAddr *
-setRemoteGA(local_closure, remote_ga, preferred)
-StgClosure *local_closure;
-globalAddr *remote_ga;
-rtsBool preferred;
-{
- /* old entry ie the one with the GA generated when sending off the closure */
- GALA *oldGALA = lookupHashTable(LAtoGALAtable, (StgWord) local_closure);
- /* alloc new entry and fill it with contents of the newly arrives GA */
- GALA *newGALA = allocGALA();
- StgWord pga = PackGA(taskIDtoPE(remote_ga->payload.gc.gtid),
- remote_ga->payload.gc.slot);
-
- ASSERT(remote_ga->payload.gc.gtid != mytid);
- ASSERT(remote_ga->weight > 0);
- ASSERT(GALAlookup(remote_ga) == NULL);
-
- newGALA->ga = *remote_ga;
- newGALA->la = (StgPtr)local_closure;
- newGALA->preferred = preferred;
-
- if (preferred) {
- /* The new GA is now the preferred GA for the LA */
- if (oldGALA != NULL) {
- oldGALA->preferred = rtsFalse;
- (void) removeHashTable(LAtoGALAtable, (StgWord) local_closure, (void *) oldGALA);
- }
- insertHashTable(LAtoGALAtable, (StgWord) local_closure, (void *) newGALA);
- }
-
- ASSERT(!isOnRemoteGATable(&(newGALA->ga)));
- /* add new entry to the (logical) RemoteGA table */
- newGALA->next = liveRemoteGAs;
- liveRemoteGAs = newGALA;
-
- insertHashTable(pGAtoGALAtable, pga, (void *) newGALA);
-
- /*
- The weight carried by the incoming closure is transferred to the newGALA
- entry (via the structure assign above). Therefore, we have to give back
- the weight to the GA on the other processor, because that indirection is
- no longer needed.
- */
- remote_ga->weight = 0;
- return &(newGALA->ga);
-}
-
-/*
- Give me a bit of weight to give away on a new reference to a particular
- global address. If we run down to nothing, we have to assign a new GA.
-*/
-
-//@cindex splitWeight
-#if 0
-void
-splitWeight(to, from)
-globalAddr *to, *from;
-{
- /* Make sure we have enough weight to split */
- if (from->weight!=MAX_GA_WEIGHT && from->weight<=3) // fixed by UK in Eden implementation
- from = makeGlobal(GALAlookup(from), rtsTrue);
-
- to->payload = from->payload;
-
- if (from->weight == MAX_GA_WEIGHT)
- to->weight = 1L << (BITS_IN(unsigned) - 1);
- else
- to->weight = from->weight / 2;
-
- from->weight -= to->weight;
-}
-#else
-void
-splitWeight(to, from)
-globalAddr *to, *from;
-{
- /* Make sure we have enough weight to split */
- /* Splitting at 2 needed, as weight 1 is not legal in packets (UK+KH) */
-
- if (from->weight / 2 <= 2) /* old: weight== 1 (UK) */
- from = makeGlobal(GALAlookup(from), rtsTrue);
-
- to->payload = from->payload;
-
- if (from->weight <= 1) /* old == 0 (UK) */
- to->weight = 1L << (BITS_IN(unsigned) - 1);
- else
- to->weight = from->weight / 2;
-
- from->weight -= to->weight;
-}
-#endif
-/*
- Here, I am returning a bit of weight that a remote PE no longer needs.
-*/
-
-//@cindex addWeight
-globalAddr *
-addWeight(ga)
-globalAddr *ga;
-{
- StgWord pga;
- GALA *gala;
-
- ASSERT(LOOKS_LIKE_GA(ga));
-
- pga = PackGA(taskIDtoPE(ga->payload.gc.gtid), ga->payload.gc.slot);
- gala = (GALA *) lookupHashTable(pGAtoGALAtable, pga);
-
- IF_PAR_DEBUG(weight,
- fprintf(stderr, "@* Adding weight %x to ", ga->weight);
- printGA(&(gala->ga));
- fputc('\n', stderr));
-
- gala->ga.weight += ga->weight;
- ga->weight = 0;
-
- return &(gala->ga);
-}
-
-/*
- Initialize all of the global address structures: the task ID to PE id
- map, the local address to global address map, the global address to
- local address map, and the indirection table.
-*/
-
-//@cindex initGAtables
-void
-initGAtables(void)
-{
- taskIDtoPEtable = allocHashTable();
- LAtoGALAtable = allocHashTable();
- pGAtoGALAtable = allocHashTable();
-}
-
-//@cindex PackGA
-StgWord
-PackGA (pe, slot)
-StgWord pe;
-int slot;
-{
- int pe_shift = (BITS_IN(StgWord)*3)/4;
- int pe_bits = BITS_IN(StgWord) - pe_shift;
-
- if ( pe_bits < 8 || slot >= (1L << pe_shift) ) { /* big trouble */
- fflush(stdout);
- fprintf(stderr, "PackGA: slot# too big (%d) or not enough pe_bits (%d)\n",
- slot,pe_bits);
- stg_exit(EXIT_FAILURE);
- }
-
- return((((StgWord)(pe)) << pe_shift) | ((StgWord)(slot)));
-
- /* the idea is to use 3/4 of the bits (e.g., 24) for indirection-
- table "slot", and 1/4 for the pe# (e.g., 8).
-
- We check for too many bits in "slot", and double-check (at
- compile-time?) that we have enough bits for "pe". We *don't*
- check for too many bits in "pe", because SysMan enforces a
- MAX_PEs limit at the very very beginning.
-
- Phil & Will 95/08
- */
-}
-
-//@node GC functions for GALA tables, Debugging routines, Interface to GALA table, Global Address Manipulation
-//@subsection GC functions for GALA tables
-
-/*
- When we do a copying collection, we want to evacuate all of the local
- entries in the GALA table for which there are outstanding remote
- pointers (i.e. for which the weight is not MAX_GA_WEIGHT.)
- This routine has to be run BEFORE doing the GC proper (it's a
- ``mark roots'' thing).
-*/
-//@cindex markLocalGAs
-void
-markLocalGAs(rtsBool full)
-{
- GALA *gala, *next, *prev = NULL;
- StgPtr old_la, new_la;
- nat n=0, m=0; // debugging only
- double start_time_GA; // stats only
-
- IF_PAR_DEBUG(tables,
- belch("@@%%%% markLocalGAs (full=%d): Marking LIVE INDIRECTIONS in GALA table starting with GALA at %p\n",
- full, liveIndirections);
- printLAGAtable());
-
- PAR_TICKY_MARK_LOCAL_GAS_START();
-
- for (gala = liveIndirections, m=0; gala != NULL; gala = next, m++) {
- IF_PAR_DEBUG(tables,
- fputs("@@ ",stderr);
- printGA(&(gala->ga));
- fprintf(stderr, ";@ %d: LA: %p (%s) ",
- m, (void*)gala->la, info_type((StgClosure*)gala->la)));
- next = gala->next;
- old_la = gala->la;
- ASSERT(gala->ga.payload.gc.gtid == mytid); /* it's supposed to be local */
- if (gala->ga.weight != MAX_GA_WEIGHT) {
- /* Remote references exist, so we must evacuate the local closure */
- if (get_itbl((StgClosure *)old_la)->type == EVACUATED) {
- /* somebody else already evacuated this closure */
- new_la = (StgPtr)((StgEvacuated *)old_la)->evacuee;
- IF_PAR_DEBUG(tables,
- belch(" already evacuated to %p", new_la));
- } else {
-#if 1
- /* unwind any indirections we find */
- StgClosure *foo = UNWIND_IND((StgClosure *)old_la) ; // debugging only
- //ASSERT(HEAP_ALLOCED(foo));
- n++;
-
- new_la = (StgPtr) MarkRoot(foo);
- IF_PAR_DEBUG(tables,
- belch(" evacuated %p to %p", foo, new_la));
- /* ToDo: is this the right assertion to check that new_la is in to-space?
- ASSERT(!HEAP_ALLOCED(new_la) || Bdescr(new_la)->evacuated);
- */
-#else
- new_la = MarkRoot(old_la); // or just evacuate(old_ga)
- IF_PAR_DEBUG(tables,
- belch(" evacuated %p to %p", old_la, new_la));
-#endif
- }
-
- gala->la = new_la;
- /* remove old LA and replace with new LA */
- if (/* !full && */ gala->preferred && new_la != old_la) {
- GALA *q;
- ASSERT(lookupHashTable(LAtoGALAtable, (StgWord)old_la));
- (void) removeHashTable(LAtoGALAtable, (StgWord) old_la, (void *) gala);
- if ((q = lookupHashTable(LAtoGALAtable, (StgWord) new_la))!=NULL) {
- if (q->preferred && gala->preferred) {
- q->preferred = rtsFalse;
- IF_PAR_DEBUG(tables,
- fprintf(stderr, "@@## found hash entry for closure %p (%s): deprecated GA ",
- new_la, info_type((StgClosure*)new_la));
- printGA(&(q->ga));
- fputc('\n', stderr));
- }
- } else {
- insertHashTable(LAtoGALAtable, (StgWord) new_la, (void *) gala);
- }
- IF_PAR_DEBUG(tables,
- belch("__## Hash table update (%p --> %p): ",
- old_la, new_la));
- }
-
- gala->next = prev;
- prev = gala;
- } else if(LOOKS_LIKE_STATIC_CLOSURE(gala->la)) {
- /* to handle the CAFs, is this all?*/
- MarkRoot(gala->la);
- IF_PAR_DEBUG(tables,
- belch(" processed static closure"));
- n++;
- gala->next = prev;
- prev = gala;
- } else {
- /* Since we have all of the weight, this GA is no longer needed */
- StgWord pga = PackGA(thisPE, gala->ga.payload.gc.slot);
-
- IF_PAR_DEBUG(free,
- belch("@@!! Freeing slot %d",
- gala->ga.payload.gc.slot));
- /* put gala on free indirections list */
- gala->next = freeIndirections;
- freeIndirections = gala;
- (void) removeHashTable(pGAtoGALAtable, pga, (void *) gala);
- if (/* !full && */ gala->preferred)
- (void) removeHashTable(LAtoGALAtable, (W_) gala->la, (void *) gala);
-
- IF_DEBUG(sanity,
- gala->ga.weight = 0xdead0add;
- gala->la = (StgPtr) 0xdead00aa);
- }
- } /* for gala ... */
- liveIndirections = prev; /* list has been reversed during the marking */
-
-
- PAR_TICKY_MARK_LOCAL_GAS_END(n);
-
- IF_PAR_DEBUG(tables,
- belch("@@%%%% markLocalGAs: %d of %d GALAs marked on PE %x",
- n, m, mytid));
-}
-
-/*
- Traverse the GALA table: for every live remote GA check whether it has been
- touched during GC; if not it is not needed locally and we can free the
- closure (i.e. let go of its heap space and send a free message to the
- PE holding its GA).
- This routine has to be run AFTER doing the GC proper.
-*/
-void
-rebuildGAtables(rtsBool full)
-{
- GALA *gala, *next, *prev;
- StgClosure *closure;
- nat n = 0, size_GA = 0; // stats only (no. of GAs, and their heap size in bytes)
-
- IF_PAR_DEBUG(tables,
- belch("@@%%%% rebuildGAtables (full=%d): rebuilding LIVE REMOTE GAs in GALA table starting with GALA at %p\n",
- full, liveRemoteGAs));
-
- PAR_TICKY_REBUILD_GA_TABLES_START();
-
- prepareFreeMsgBuffers();
-
- for (gala = liveRemoteGAs, prev = NULL; gala != NULL; gala = next) {
- IF_PAR_DEBUG(tables,
- printGA(&(gala->ga)));
- next = gala->next;
- ASSERT(gala->ga.payload.gc.gtid != mytid); /* it's supposed to be remote */
-
- closure = (StgClosure *) (gala->la);
- IF_PAR_DEBUG(tables,
- fprintf(stderr, " %p (%s) ",
- (StgClosure *)closure, info_type(closure)));
-
- if (/* !full && */ gala->preferred)
- (void) removeHashTable(LAtoGALAtable, (StgWord) gala->la, (void *) gala);
-
- /* Follow indirection chains to the end, just in case */
- // should conform with unwinding in markLocalGAs
- closure = UNWIND_IND(closure);
-
- /*
- If closure has been evacuated it is live; otherwise it's dead and we
- can nuke the GA attached to it in the LAGA table.
- This approach also drops global aliases for PLCs.
- */
-
- //ASSERT(!HEAP_ALLOCED(closure) || !(Bdescr((StgPtr)closure)->evacuated));
- if (get_itbl(closure)->type == EVACUATED) {
- closure = ((StgEvacuated *)closure)->evacuee;
- IF_PAR_DEBUG(tables,
- fprintf(stderr, " EVAC %p (%s)\n",
- closure, info_type(closure)));
- } else {
- /* closure is not alive any more, thus remove GA and send free msg */
- int pe = taskIDtoPE(gala->ga.payload.gc.gtid);
- StgWord pga = PackGA(pe, gala->ga.payload.gc.slot);
-
- /* check that the block containing this closure is not in to-space */
- IF_PAR_DEBUG(tables,
- fprintf(stderr, " !EVAC %p (%s); sending free to PE %d\n",
- closure, info_type(closure), pe));
-
- (void) removeHashTable(pGAtoGALAtable, pga, (void *) gala);
- freeRemoteGA(pe-1, &(gala->ga)); //-1 cause ids start at 1... not 0
- gala->next = freeGALAList;
- freeGALAList = gala;
- IF_DEBUG(sanity,
- gala->ga.weight = 0xdead0add;
- gala->la = (StgPtr)0xdead00aa);
- continue;
- }
- gala->la = (StgPtr)closure;
- if (/* !full && */ gala->preferred) {
- GALA *q;
- if ((q = lookupHashTable(LAtoGALAtable, (StgWord) gala->la))!=NULL) {
- if (q->preferred && gala->preferred) {
- q->preferred = rtsFalse;
- IF_PAR_DEBUG(tables,
- fprintf(stderr, "@@## found hash entry for closure %p (%s): deprecated GA ",
- gala->la, info_type((StgClosure*)gala->la));
- printGA(&(q->ga));
- fputc('\n', stderr));
- }
- } else {
- insertHashTable(LAtoGALAtable, (StgWord) gala->la, (void *) gala);
- }
- }
- gala->next = prev;
- prev = gala;
- /* Global statistics: count GAs and total size
- if (RtsFlags.ParFlags.ParStats.Global &&
- RtsFlags.GcFlags.giveStats > NO_GC_STATS) {
- StgInfoTable *info;
- nat size, ptrs, nonptrs, vhs, i;
- char str[80];
-
- info = get_closure_info(closure, &size, &ptrs, &nonptrs, &vhs, str);
-
- size_GA += size ;
- n++; // stats: count number of GAs we add to the new table
- }
- */
- }
- liveRemoteGAs = prev; /* list is reversed during marking */
-
- /* If we have any remaining FREE messages to send off, do so now */
- sendFreeMessages();
-
- PAR_TICKY_CNT_FREE_GA();
-
- IF_DEBUG(sanity,
- checkFreeGALAList();
- checkFreeIndirectionsList());
-
- rebuildLAGAtable();
-
-#if defined(PAR_TICKY)
- getLAGAtableSize(&n, &size_GA); // determine no of GAs and global heap
- PAR_TICKY_REBUILD_GA_TABLES_END(n, size_GA); // record these values
-#endif
-
- IF_PAR_DEBUG(tables,
- belch("@#%%%% rebuildGAtables: After ReBuilding GALA table starting with GALA at %p",
- liveRemoteGAs);
- printLAGAtable());
-}
-
-/*
- Rebuild the LA->GA table, assuming that the addresses in the GALAs are
- correct.
- A word on the lookupHashTable check in both loops:
- After GC we may end up with 2 preferred GAs for the same LA! For example,
- if we received a closure whose GA already exists on this PE we CommonUp
- both closures, making one an indirection to the other. Before GC everything
- is fine: one preferred GA refers to the IND, the other preferred GA refers
- to the closure it points to. After GC, however, we have short cutted the
- IND and suddenly we have 2 preferred GAs for the same closure. We detect
- this case in the loop below and deprecate one GA, so that we always just
- have one preferred GA per LA.
-*/
-
-//@cindex rebuildLAGAtable
-void
-rebuildLAGAtable(void)
-{
- GALA *gala;
- nat n=0, m=0; // debugging
-
- /* The old LA->GA table is worthless */
- freeHashTable(LAtoGALAtable, NULL);
- LAtoGALAtable = allocHashTable();
-
- IF_PAR_DEBUG(tables,
- belch("@@%%%% rebuildLAGAtable: new LAGA table at %p",
- LAtoGALAtable));
-
- for (gala = liveIndirections; gala != NULL; gala = gala->next) {
- n++;
- if (gala->preferred) {
- GALA *q;
- if ((q = lookupHashTable(LAtoGALAtable, (StgWord) gala->la))!=NULL) {
- if (q->preferred && gala->preferred) {
- /* this deprecates q (see also GALAdeprecate) */
- q->preferred = rtsFalse;
- (void) removeHashTable(LAtoGALAtable, (StgWord) gala->la, (void *)q);
- IF_PAR_DEBUG(tables,
- fprintf(stderr, "@@## found hash entry for closure %p (%s): deprecated GA ",
- gala->la, info_type((StgClosure*)gala->la));
- printGA(&(q->ga));
- fputc('\n', stderr));
- }
- }
- insertHashTable(LAtoGALAtable, (StgWord) gala->la, (void *) gala);
- }
- }
-
- for (gala = liveRemoteGAs; gala != NULL; gala = gala->next) {
- m++;
- if (gala->preferred) {
- GALA *q;
- if ((q = lookupHashTable(LAtoGALAtable, (StgWord) gala->la))!=NULL) {
- if (q->preferred && gala->preferred) {
- /* this deprecates q (see also GALAdeprecate) */
- q->preferred = rtsFalse;
- (void) removeHashTable(LAtoGALAtable, (StgWord) gala->la, (void *)q);
- IF_PAR_DEBUG(tables,
- fprintf(stderr, "@@## found hash entry for closure %p (%s): deprecated GA ",
- (StgClosure*)gala->la, info_type((StgClosure*)gala->la));
- printGA(&(q->ga));
- fputc('\n', stderr));
- }
- }
- insertHashTable(LAtoGALAtable, (StgWord) gala->la, (void *) gala);
- }
- }
-
- IF_PAR_DEBUG(tables,
- belch("@@%%%% rebuildLAGAtable: inserted %d entries from liveIndirections and %d entries from liveRemoteGAs",
- n,m));
-}
-
-/*
- Determine the size of the LAGA and GALA tables.
- Has to be done after rebuilding the tables.
- Only used for global statistics gathering.
-*/
-
-//@cindex getLAGAtableSize
-void
-getLAGAtableSize(nat *nP, nat *sizeP)
-{
- GALA *gala;
- // nat n=0, tot_size=0;
- StgClosure *closure;
- StgInfoTable *info;
- nat size, ptrs, nonptrs, vhs, i;
- char str[80];
- /* IN order to avoid counting closures twice we maintain a hash table
- of all closures seen so far.
- ToDo: collect this data while rebuilding the GALA table and make use
- of the existing hash tables;
- */
- HashTable *closureTable; // hash table for closures encountered already
-
- closureTable = allocHashTable();
-
- (*nP) = (*sizeP) = 0;
- for (gala = liveIndirections; gala != NULL; gala = gala->next) {
- closure = (StgClosure*) gala->la;
- if (lookupHashTable(closureTable, (StgWord)closure)==NULL) { // not seen yet
- insertHashTable(closureTable, (StgWord)closure, (void *)1);
- info = get_closure_info(closure, &size, &ptrs, &nonptrs, &vhs, str);
- (*sizeP) += size ; // stats: measure total heap size of global closures
- (*nP)++; // stats: count number of GAs
- }
- }
-
- for (gala = liveRemoteGAs; gala != NULL; gala = gala->next) {
- closure = (StgClosure*) gala->la;
- if (lookupHashTable(closureTable, (StgWord)closure)==NULL) { // not seen yet
- insertHashTable(closureTable, (StgWord)closure, (void *)1);
- info = get_closure_info(closure, &size, &ptrs, &nonptrs, &vhs, str);
- (*sizeP) += size ; // stats: measure total heap size of global closures
- (*nP)++; // stats: count number of GAs
- }
- }
-
- freeHashTable(closureTable, NULL);
-}
-
-//@node Debugging routines, Index, GC functions for GALA tables, Global Address Manipulation
-//@subsection Debugging routines
-
-//@cindex printGA
-void
-printGA (globalAddr *ga)
-{
- fprintf(stderr, "((%x, %d, %x))",
- ga->payload.gc.gtid,
- ga->payload.gc.slot,
- ga->weight);
-}
-
-//@cindex printGALA
-void
-printGALA (GALA *gala)
-{
- printGA(&(gala->ga));
- fprintf(stderr, " -> %p (%s)",
- (StgClosure*)gala->la, info_type((StgClosure*)gala->la));
- fprintf(stderr, " %s",
- (gala->preferred) ? "PREF" : "____");
-}
-
-/*
- Printing the LA->GA table.
-*/
-
-//@cindex printLiveIndTable
-void
-printLiveIndTable(void)
-{
- GALA *gala, *q;
- nat n=0; // debugging
-
- belch("@@%%%%:: logical LiveIndTable (%p) (liveIndirections=%p):",
- LAtoGALAtable, liveIndirections);
-
- for (gala = liveIndirections; gala != NULL; gala = gala->next) {
- n++;
- printGALA(gala);
- /* check whether this gala->la is hashed into the LAGA table */
- q = lookupHashTable(LAtoGALAtable, (StgWord)(gala->la));
- fprintf(stderr, "\t%s\n", (q==NULL) ? "...." : (q==gala) ? "====" : "####");
- //ASSERT(lookupHashTable(LAtoGALAtable, (StgWord)(gala->la)));
- }
- belch("@@%%%%:: %d live indirections",
- n);
-}
-
-void
-printRemoteGATable(void)
-{
- GALA *gala, *q;
- nat m=0; // debugging
-
- belch("@@%%%%:: logical RemoteGATable (%p) (liveRemoteGAs=%p):",
- LAtoGALAtable, liveRemoteGAs);
-
- for (gala = liveRemoteGAs; gala != NULL; gala = gala->next) {
- m++;
- printGALA(gala);
- /* check whether this gala->la is hashed into the LAGA table */
- q = lookupHashTable(LAtoGALAtable, (StgWord)(gala->la));
- fprintf(stderr, "\t%s\n", (q==NULL) ? "...." : (q==gala) ? "====" : "####");
- // ASSERT(lookupHashTable(LAtoGALAtable, (StgWord)(gala->la)));
- }
- belch("@@%%%%:: %d remote GAs",
- m);
-}
-
-//@cindex printLAGAtable
-void
-printLAGAtable(void)
-{
- belch("@@%%: LAGAtable (%p) with liveIndirections=%p, liveRemoteGAs=%p:",
- LAtoGALAtable, liveIndirections, liveRemoteGAs);
-
- printLiveIndTable();
- printRemoteGATable();
-}
-
-/*
- Check whether a GA is already in a list.
-*/
-rtsBool
-isOnLiveIndTable(globalAddr *ga)
-{
- GALA *gala;
-
- for (gala = liveIndirections; gala != NULL; gala = gala->next)
- if (gala->ga.weight==ga->weight &&
- gala->ga.payload.gc.slot==ga->payload.gc.slot &&
- gala->ga.payload.gc.gtid==ga->payload.gc.gtid)
- return rtsTrue;
-
- return rtsFalse;
-}
-
-rtsBool
-isOnRemoteGATable(globalAddr *ga)
-{
- GALA *gala;
-
- for (gala = liveRemoteGAs; gala != NULL; gala = gala->next)
- if (gala->ga.weight==ga->weight &&
- gala->ga.payload.gc.slot==ga->payload.gc.slot &&
- gala->ga.payload.gc.gtid==ga->payload.gc.gtid)
- return rtsTrue;
-
- return rtsFalse;
-}
-
-/*
- Sanity check for free lists.
-*/
-void
-checkFreeGALAList(void) {
- GALA *gl;
-
- for (gl=freeGALAList; gl != NULL; gl=gl->next) {
- ASSERT(gl->ga.weight==0xdead0add);
- ASSERT(gl->la==(StgPtr)0xdead00aa);
- }
-}
-
-void
-checkFreeIndirectionsList(void) {
- GALA *gl;
-
- for (gl=freeIndirections; gl != NULL; gl=gl->next) {
- ASSERT(gl->ga.weight==0xdead0add);
- ASSERT(gl->la==(StgPtr)0xdead00aa);
- }
-}
-#endif /* PAR -- whole file */
-
-//@node Index, , Debugging routines, Global Address Manipulation
-//@subsection Index
-
-//@index
-//* DebugPrintLAGAtable:: @cindex\s-+DebugPrintLAGAtable
-//* GALAlookup:: @cindex\s-+GALAlookup
-//* LAGAlookup:: @cindex\s-+LAGAlookup
-//* LAtoGALAtable:: @cindex\s-+LAtoGALAtable
-//* PackGA:: @cindex\s-+PackGA
-//* addWeight:: @cindex\s-+addWeight
-//* allocGALA:: @cindex\s-+allocGALA
-//* allocIndirection:: @cindex\s-+allocIndirection
-//* freeIndirections:: @cindex\s-+freeIndirections
-//* initGAtables:: @cindex\s-+initGAtables
-//* liveIndirections:: @cindex\s-+liveIndirections
-//* liveRemoteGAs:: @cindex\s-+liveRemoteGAs
-//* makeGlobal:: @cindex\s-+makeGlobal
-//* markLocalGAs:: @cindex\s-+markLocalGAs
-//* nextIndirection:: @cindex\s-+nextIndirection
-//* pGAtoGALAtable:: @cindex\s-+pGAtoGALAtable
-//* printGA:: @cindex\s-+printGA
-//* printGALA:: @cindex\s-+printGALA
-//* rebuildLAGAtable:: @cindex\s-+rebuildLAGAtable
-//* registerTask:: @cindex\s-+registerTask
-//* setRemoteGA:: @cindex\s-+setRemoteGA
-//* splitWeight:: @cindex\s-+splitWeight
-//* taskIDtoPE:: @cindex\s-+taskIDtoPE
-//* taskIDtoPEtable:: @cindex\s-+taskIDtoPEtable
-//* thisPE:: @cindex\s-+thisPE
-//@end index