2 % (c) The AQUA/Parade Projects, Glasgow University, 1995
4 %************************************************************************
6 \section[GlobAddr.lc]{Global Address Manipulation}
8 %************************************************************************
11 #ifdef PAR /* whole file */
16 @globalAddr@ structures are allocated in chunks to reduce malloc overhead.
20 GALA *freeGALAList = NULL;
22 #define GCHUNK (1024 * sizeof(W_) / sizeof(GALA))
23 /* Number of globalAddr cells to allocate in one go */
26 allocGALA(STG_NO_ARGS)
30 if ((gl = freeGALAList) != NULL) {
31 freeGALAList = gl->next;
32 } else if ((gl = (GALA *) malloc(GCHUNK * sizeof(GALA))) != NULL) {
33 freeGALAList = gl + 1;
34 for (p = freeGALAList; p < gl + GCHUNK - 1; p++)
39 fprintf(stderr, "VM exhausted\n");
47 We don't really like GLOBAL_TASK_ID, so we keep a table of TASK_ID to
48 PE mappings. The idea is that a PE identifier will fit in 16 bits, whereas
53 HashTable *taskIDtoPEtable = NULL;
55 static int nextPE = 0;
61 return (W_) lookupHashTable(taskIDtoPEtable, gtid);
73 insertHashTable(taskIDtoPEtable, gtid, (void *) (W_) nextPE++);
78 The local address to global address mapping returns a globalAddr structure
79 (pe task id, slot, weight) for any closure in the local heap which has a
80 global identity. Such closures may be copies of normal form objects with
81 a remote `master' location, @FetchMe@ nodes referencing remote objects, or
82 globally visible objects in the local heap (for which we are the master).
86 HashTable *LAtoGALAtable = NULL;
94 /* We never look for GA's on indirections */
95 ASSERT(INFO_PTR(addr) != (W_) Ind_info);
96 if ((gala = lookupHashTable(LAtoGALAtable, (W_) addr)) == NULL)
104 We also manage a mapping of global addresses to local addresses, so that
105 we can ``common up'' multiple references to the same object as they arrive
106 in data packets from remote PEs.
108 The global address to local address mapping is actually managed via a
109 ``packed global address'' to GALA hash table. The packed global
110 address takes the interesting part of the @globalAddr@ structure
111 (i.e. the pe and slot fields) and packs them into a single word
112 suitable for hashing.
116 HashTable *pGAtoGALAtable = NULL;
122 W_ pga = PACK_GA(taskIDtoPE(ga->loc.gc.gtid), ga->loc.gc.slot);
126 if ((gala = (GALA *) lookupHashTable(pGAtoGALAtable, pga)) == NULL)
131 * Bypass any indirections when returning a local closure to the caller.
132 * Note that we do not short-circuit the entry in the GALA tables right
133 * now, because we would have to do a hash table delete and insert in
134 * the LAtoGALAtable to keep that table up-to-date for preferred GALA pairs.
135 * That's probably a bit expensive.
137 while (IS_INDIRECTION(INFO_PTR(la)))
138 la = (P_) IND_CLOSURE_PTR(la);
145 External references to our globally-visible closures are managed through an
146 indirection table. The idea is that the closure may move about as the result
147 of local garbage collections, but its global identity is determined by its
148 slot in the indirection table, which never changes.
150 The indirection table is maintained implicitly as part of the global
151 address to local address table. We need only keep track of the
152 highest numbered indirection index allocated so far, along with a free
153 list of lower numbered indices no longer in use.
157 static I_ nextIndirection = 0;
159 GALA *freeIndirections = NULL;
163 Allocate an indirection slot for the closure currently at address @addr@.
168 allocIndirection(addr)
173 if ((gala = freeIndirections) != NULL) {
174 freeIndirections = gala->next;
177 gala->ga.loc.gc.gtid = mytid;
178 gala->ga.loc.gc.slot = nextIndirection++;
180 gala->ga.weight = MAX_GA_WEIGHT;
187 Make a local closure at @addr@ globally visible. We have to allocate an
188 indirection slot for it, and update both the local address to global address
189 and global address to local address maps.
193 GALA *liveIndirections = NULL;
196 MakeGlobal(addr, preferred)
200 GALA *oldGALA = lookupHashTable(LAtoGALAtable, (W_) addr);
201 GALA *newGALA = allocIndirection(addr);
202 W_ pga = PACK_GA(thisPE, newGALA->ga.loc.gc.slot);
204 ASSERT(GALAlookup(&(newGALA->ga)) == NULL);
207 newGALA->preferred = preferred;
210 /* The new GA is now the preferred GA for the LA */
211 if (oldGALA != NULL) {
212 oldGALA->preferred = rtsFalse;
213 (void) removeHashTable(LAtoGALAtable, (W_) addr, (void *) oldGALA);
215 insertHashTable(LAtoGALAtable, (W_) addr, (void *) newGALA);
218 newGALA->next = liveIndirections;
219 liveIndirections = newGALA;
221 insertHashTable(pGAtoGALAtable, pga, (void *) newGALA);
223 return &(newGALA->ga);
228 Assign an existing remote global address to an existing closure.
229 We do not retain the @globalAddr@ structure that's passed in as an argument,
230 so it can be a static in the calling routine.
234 GALA *liveRemoteGAs = NULL;
237 setRemoteGA(addr, ga, preferred)
242 GALA *oldGALA = lookupHashTable(LAtoGALAtable, (W_) addr);
243 GALA *newGALA = allocGALA();
244 W_ pga = PACK_GA(taskIDtoPE(ga->loc.gc.gtid), ga->loc.gc.slot);
246 ASSERT(ga->loc.gc.gtid != mytid);
247 ASSERT(ga->weight > 0);
248 ASSERT(GALAlookup(ga) == NULL);
252 newGALA->preferred = preferred;
255 /* The new GA is now the preferred GA for the LA */
256 if (oldGALA != NULL) {
257 oldGALA->preferred = rtsFalse;
258 (void) removeHashTable(LAtoGALAtable, (W_) addr, (void *) oldGALA);
260 insertHashTable(LAtoGALAtable, (W_) addr, (void *) newGALA);
262 newGALA->next = liveRemoteGAs;
263 liveRemoteGAs = newGALA;
265 insertHashTable(pGAtoGALAtable, pga, (void *) newGALA);
269 return &(newGALA->ga);
273 Give me a bit of weight to give away on a new reference to a particular global
274 address. If we run down to nothing, we have to assign a new GA.
279 splitWeight(to, from)
280 globalAddr *to, *from;
282 /* Make sure we have enough weight to split */
283 if (from->weight == 1)
284 from = MakeGlobal(GALAlookup(from), rtsTrue);
288 if (from->weight == 0)
289 to->weight = 1L << (BITS_IN(unsigned) - 1);
291 to->weight = from->weight / 2;
293 from->weight -= to->weight;
298 Here, I am returning a bit of weight that a remote PE no longer needs.
306 W_ pga = PACK_GA(taskIDtoPE(ga->loc.gc.gtid), ga->loc.gc.slot);
307 GALA *gala = (GALA *) lookupHashTable(pGAtoGALAtable, pga);
310 fprintf(stderr, "Adding weight %x to (%x, %d, %x), preferred = %d\n", ga->weight,
311 gala->ga.loc.gc.gtid, gala->ga.loc.gc.slot, gala->ga.weight, gala->preferred);
313 gala->ga.weight += ga->weight;
321 Initialize all of the global address structures: the task ID to PE id
322 map, the local address to global address map, the global address to
323 local address map, and the indirection table.
328 initGAtables(STG_NO_ARGS)
330 taskIDtoPEtable = allocHashTable();
331 LAtoGALAtable = allocHashTable();
332 pGAtoGALAtable = allocHashTable();
337 Rebuild the LA->GA table, assuming that the addresses in the GALAs are correct.
342 RebuildLAGAtable(STG_NO_ARGS)
346 /* The old LA->GA table is worthless */
347 freeHashTable(LAtoGALAtable, NULL);
348 LAtoGALAtable = allocHashTable();
350 for (gala = liveIndirections; gala != NULL; gala = gala->next) {
352 insertHashTable(LAtoGALAtable, (W_) gala->la, (void *) gala);
355 for (gala = liveRemoteGAs; gala != NULL; gala = gala->next) {
357 insertHashTable(LAtoGALAtable, (W_) gala->la, (void *) gala);
361 #endif /* PAR -- whole file */