2 % (c) The Parade/AQUA Projects, Glasgow University, 1995
3 % Kevin Hammond, February 15th. 1995
5 % This is for GUM only.
7 %************************************************************************
9 \section[Pack.lc]{Packing closures for export to remote processors}
11 %************************************************************************
13 This module defines routines for packing closures in the parallel runtime
17 #ifdef PAR /* whole file */
22 Static data and code declarations.
25 static W_ *PackBuffer = NULL; /* size: can be set via option */
27 static W_ packlocn, clqsize, clqpos;
28 static W_ unpackedsize;
29 static W_ reservedPAsize; /*Space reserved for primitive arrays*/
30 static rtsBool RoomInBuffer;
33 static void InitPacking(STG_NO_ARGS), DonePacking(STG_NO_ARGS);
34 static rtsBool NotYetPacking PROTO((int offset)),
35 RoomToPack PROTO((W_ size, W_ ptrs));
36 static void AmPacking PROTO((P_ closure));
38 static void PackClosure PROTO((P_ closure));
39 static void Pack PROTO((W_ data)),
40 PackPLC PROTO((P_ addr)),
41 PackOffset PROTO((int offset)),
42 GlobaliseAndPackGA PROTO((P_ closure));
44 static int OffsetFor PROTO((P_ closure));
47 %************************************************************************
49 \subsection[PackNearbyGraph]{Packing Sections of Nearby Graph}
51 %************************************************************************
53 @PackNearbyGraph@ packs a closure and associated graph into a static
54 buffer (@PackBuffer@). It returns the address of this buffer and the
55 size of the data packed into the buffer (in its second parameter,
56 @packbuffersize@). The associated graph is packed in a depth first
57 manner, hence it uses an explicit queue of closures to be packed
58 rather than simply using a recursive algorithm. Once the packet is
59 full, closures (other than primitive arrays) are packed as FetchMes,
60 and their children are not queued for packing.
64 PackNearbyGraph(closure, packbuffersize)
68 /* Ensure enough heap for all possible RBH_Save closures */
70 ASSERT(RTSflags.ParFlags.packBufferSize > 0);
72 if (SAVE_Hp + PACK_HEAP_REQUIRED > SAVE_HpLim)
77 QueueClosure(closure);
79 PackClosure(DeQueueClosure());
80 } while (!QueueEmpty());
82 /* Record how much space is needed to unpack the graph */
83 PackBuffer[0] = unpackedsize;
85 /* Set the size parameter */
86 ASSERT(packlocn <= RTSflags.ParFlags.packBufferSize);
87 *packbuffersize = packlocn;
95 @PackTSO@ and @PackStkO@ are entry points for two special kinds of
96 closure which are used in the parallel RTS. Compared with other
97 closures they are rather awkward to pack because they don't follow the
98 normal closure layout (where all pointers occur before all non-pointers).
99 Luckily, they're only needed when migrating threads between processors.
103 PackTSO(tso,packbuffersize)
108 PackBuffer[0] = PackBuffer[1] = 0;
113 PackStkO(stko,packbuffersize)
118 PackBuffer[0] = PackBuffer[1] = 0;
124 %************************************************************************
126 \subsection[PackClosure]{Packing Closures}
128 %************************************************************************
130 @PackClosure@ is the heart of the normal packing code. It packs a
131 single closure into the pack buffer, skipping over any indirections
132 and globalising it as necessary, queues any child pointers for further
133 packing, and turns it into a @FetchMe@ or revertible black hole
134 (@RBH@) locally if it was a thunk. Before the actual closure is
135 packed, a suitable global address (GA) is inserted in the pack buffer.
136 There is always room to pack a fetch-me to the closure (guaranteed by
137 the RoomToPack calculation), and this is packed if there is no room
138 for the entire closure.
140 Space is allocated for any primitive array children of a closure, and
141 hence a primitive array can always be packed along with it's parent
149 W_ size, ptrs, nonptrs, vhs;
152 while (IS_INDIRECTION(INFO_PTR(closure))) {
153 /* Don't pack indirection closures */
155 fprintf(stderr, "Shorted an indirection at %x", closure);
157 closure = (P_) IND_CLOSURE_PTR(closure);
160 clpacklocn = OffsetFor(closure);
162 /* If the closure's not already being packed */
163 if (NotYetPacking(clpacklocn)) {
167 * PLCs reside on all of the PEs already. Just pack the
168 * address as a GA (a bit of a kludge, since an address may
169 * not fit in *any* of the individual GA fields). Const,
170 * charlike and small intlike closures are converted into
173 switch (INFO_TYPE(INFO_PTR(closure))) {
175 case INFO_CHARLIKE_TYPE:
177 fprintf(stderr, "Packing a charlike %s\n", CHARLIKE_VALUE(closure));
179 PackPLC((P_) CHARLIKE_CLOSURE(CHARLIKE_VALUE(closure)));
182 case INFO_CONST_TYPE:
184 fprintf(stderr, "Packing a const %s\n", CONST_STATIC_CLOSURE(INFO_PTR(closure)));
186 PackPLC(CONST_STATIC_CLOSURE(INFO_PTR(closure)));
189 case INFO_STATIC_TYPE:
190 case INFO_CAF_TYPE: /* For now we ship indirections to CAFs: They are
191 * evaluated on each PE if needed */
193 fprintf(stderr, "Packing a PLC %x\n", closure);
198 case INFO_INTLIKE_TYPE:
200 I_ val = INTLIKE_VALUE(closure);
202 if ((val <= MAX_INTLIKE) && (val >= MIN_INTLIKE)) {
204 fprintf(stderr, "Packing a small intlike %d as a PLC\n", val);
206 PackPLC(INTLIKE_CLOSURE(val));
210 fprintf(stderr, "Packing a big intlike %d as a normal closure\n", val);
217 fprintf(stderr, "Not a PLC: ");
221 /* Otherwise it's not Fixed */
223 info = get_closure_info(closure, &size, &ptrs, &nonptrs, &vhs);
225 if (INFO_TYPE(info) == INFO_FETCHME_TYPE || IS_BLACK_HOLE(info))
226 size = ptrs = nonptrs = vhs = 0;
229 * Now peek ahead to see whether the closure has any primitive array
232 for (i = 0; i < ptrs; ++i) {
234 W_ childSize, childPtrs, childNonPtrs, childVhs;
236 childInfo = get_closure_info(((PP_) (closure))[i + FIXED_HS + vhs],
237 &childSize, &childPtrs, &childNonPtrs, &childVhs);
238 if (IS_BIG_MOTHER(childInfo)) {
239 reservedPAsize += PACK_GA_SIZE + FIXED_HS + childVhs + childNonPtrs
240 + childPtrs * PACK_FETCHME_SIZE;
244 /* Record the location of the GA */
247 /* Pack the global address */
248 GlobaliseAndPackGA(closure);
251 * Pack a fetchme to the closure if it's a black hole, or the buffer is full
252 * and it isn't a primitive array. N.B. Primitive arrays are always packed
253 * (because their parents index into them directly)
256 if (IS_BLACK_HOLE(info) ||
257 !(RoomToPack(PACK_GA_SIZE + FIXED_HS + vhs + nonptrs, ptrs)
258 || IS_BIG_MOTHER(info))) {
260 ASSERT(packlocn > PACK_HDR_SIZE);
262 /* Just pack as a FetchMe */
264 for (i = 0; i < FIXED_HS; ++i) {
265 if (i == INFO_HDR_POSN)
266 Pack((W_) FetchMe_info);
271 unpackedsize += FIXED_HS + FETCHME_CLOSURE_SIZE(dummy);
274 /* At last! A closure we can actually pack! */
276 if (IS_MUTABLE(info) && (INFO_TYPE(info) != INFO_FETCHME_TYPE))
277 fprintf(stderr, "Warning: Replicated a Mutable closure!\n");
279 for (i = 0; i < FIXED_HS + vhs; ++i)
282 for (i = 0; i < ptrs; ++i)
283 QueueClosure(((PP_) (closure))[i + FIXED_HS + vhs]);
285 for (i = 0; i < nonptrs; ++i)
286 Pack(closure[i + FIXED_HS + vhs + ptrs]);
288 unpackedsize += FIXED_HS + (size < MIN_UPD_SIZE ? MIN_UPD_SIZE : size);
291 * Record that this is a revertable black hole so that we can fill in
292 * its address from the fetch reply. Problem: unshared thunks may cause
293 * space leaks this way, their GAs should be deallocated following an
297 if (IS_THUNK(info) && IS_UPDATABLE(info)) {
303 convertToRBH(closure);
309 /* Pack an indirection to the original closure! */
311 PackOffset(clpacklocn);
315 %************************************************************************
317 \subsection[simple-pack-routines]{Simple Packing Routines}
319 %************************************************************************
321 @Pack@ is the basic packing routine. It just writes a word of
322 data into the pack buffer and increments the pack location.
329 ASSERT(packlocn < RTSflags.ParFlags.packBufferSize);
330 PackBuffer[packlocn++] = data;
334 If a closure is local, make it global. Then, divide its weight for export.
335 The GA is then packed into the pack buffer.
339 GlobaliseAndPackGA(closure)
345 if ((ga = LAGAlookup(closure)) == NULL)
346 ga = MakeGlobal(closure, rtsTrue);
347 splitWeight(&packGA, ga);
348 ASSERT(packGA.weight > 0);
351 fprintf(stderr, "Packing (%x, %d, %x)\n",
352 packGA.loc.gc.gtid, packGA.loc.gc.slot, packGA.weight);
354 Pack((W_) packGA.weight);
355 Pack((W_) packGA.loc.gc.gtid);
356 Pack((W_) packGA.loc.gc.slot);
360 @PackPLC@ makes up a bogus GA for a PLC. Weight 0 implies that a PLC
361 address follows instead of PE, slot.
368 Pack(0L); /* weight */
369 Pack((W_) addr); /* address */
373 @PackOffset@ packs a special GA value that will be interpreted as
374 an offset to a closure in the pack buffer. This is used to avoid
375 unfolding the graph structure into a tree.
383 fprintf(stderr,"Packing Offset %d at pack location %u\n",offset,packlocn);
385 Pack(1L); /* weight */
387 Pack(offset); /* slot/offset */
391 %************************************************************************
393 \subsection[pack-offsets]{Offsets into the Pack Buffer}
395 %************************************************************************
397 The offset hash table is used during packing to record the location in
398 the pack buffer of each closure which is packed.
401 static HashTable *offsettable;
404 @InitPacking@ initialises the packing buffer etc.
408 InitPackBuffer(STG_NO_ARGS)
410 if (PackBuffer == NULL) { /* not yet allocated */
412 PackBuffer = (W_ *) stgMallocWords(RTSflags.ParFlags.packBufferSize+PACK_HDR_SIZE,
415 InitPendingGABuffer(RTSflags.ParFlags.packBufferSize);
416 AllocClosureQueue(RTSflags.ParFlags.packBufferSize);
421 InitPacking(STG_NO_ARGS)
423 /* InitPackBuffer(); now done in ParInit HWL_ */
425 packlocn = PACK_HDR_SIZE;
428 RoomInBuffer = rtsTrue;
430 offsettable = allocHashTable();
434 @DonePacking@ is called when we've finished packing. It releases memory
439 DonePacking(STG_NO_ARGS)
441 freeHashTable(offsettable,NULL);
446 @AmPacking@ records that the closure is being packed. Note the abuse
447 of the data field in the hash table -- this saves calling @malloc@!
455 fprintf(stderr, "Packing %#lx (IP %#lx) at %u\n",
456 closure, INFO_PTR(closure), packlocn);
458 insertHashTable(offsettable, (W_) closure, (void *) (W_) packlocn);
462 @OffsetFor@ returns an offset for a closure which is already being
467 OffsetFor(P_ closure)
469 return (int) (W_) lookupHashTable(offsettable, (W_) closure);
473 @NotYetPacking@ determines whether the closure's already being packed.
474 Offsets $<$ @PACK_HDR_SIZE@ (e.g. 0) mean no.
478 NotYetPacking(offset)
481 return(offset < PACK_HDR_SIZE);
485 @RoomToPack@ determines whether there's room to pack the closure into
486 the pack buffer based on
488 o how full the buffer is already,
489 o the closures' size and number of pointers (which must be packed as GAs),
490 o the size and number of pointers held by any primitive arrays that it points to
492 It has a *side-effect* in assigning RoomInBuffer to False.
496 RoomToPack(size, ptrs)
500 (packlocn + reservedPAsize + size +
501 ((clqsize - clqpos) + ptrs) * PACK_FETCHME_SIZE >= RTSflags.ParFlags.packBufferSize)) {
503 fprintf(stderr, "Buffer full\n");
505 RoomInBuffer = rtsFalse;
507 return (RoomInBuffer);
511 %************************************************************************
513 \subsection[pack-closure-queue]{Closure Queues}
515 %************************************************************************
517 These routines manage the closure queue.
520 static W_ clqpos, clqsize;
522 static P_ *ClosureQueue = NULL; /* HWL: init in main */
525 @InitClosureQueue@ initialises the closure queue.
529 AllocClosureQueue(size)
532 ASSERT(ClosureQueue == NULL);
533 ClosureQueue = (P_ *) stgMallocWords(size, "AllocClosureQueue");
537 InitClosureQueue(STG_NO_ARGS)
539 clqpos = clqsize = 0;
541 if ( ClosureQueue == NULL ) {
542 AllocClosureQueue(RTSflags.ParFlags.packBufferSize);
547 @QueueEmpty@ returns @rtsTrue@ if the closure queue is empty;
548 @rtsFalse@ otherwise.
552 QueueEmpty(STG_NO_ARGS)
554 return(clqpos >= clqsize);
558 @QueueClosure@ adds its argument to the closure queue.
562 QueueClosure(closure)
565 if(clqsize < RTSflags.ParFlags.packBufferSize)
566 ClosureQueue[clqsize++] = closure;
569 fprintf(stderr,"Closure Queue Overflow (EnQueueing %lx)\n", (W_)closure);
575 @DeQueueClosure@ returns the head of the closure queue.
579 DeQueueClosure(STG_NO_ARGS)
582 return(ClosureQueue[clqpos++]);
588 %************************************************************************
590 \subsection[pack-ga-types]{Types of Global Addresses}
592 %************************************************************************
594 These routines determine whether a GA is one of a number of special types
602 return (ga->weight == 1 && ga->loc.gc.gtid == 0);
609 return (ga->weight == 0);
613 %************************************************************************
615 \subsection[pack-print-packet]{Printing Packet Contents}
617 %************************************************************************
625 W_ size, ptrs, nonptrs, vhs;
631 W_ pptr = 0, pptrs = 0, pvhs;
633 W_ unpacklocn = PACK_HDR_SIZE;
634 W_ gastart = unpacklocn;
635 W_ closurestart = unpacklocn;
643 /* Unpack the header */
646 fprintf(stderr, "Packed Packet size %u\n\n--- Begin ---\n", bufsize);
649 gastart = unpacklocn;
650 ga.weight = buffer[unpacklocn++];
652 ga.loc.gc.gtid = buffer[unpacklocn++];
653 ga.loc.gc.slot = buffer[unpacklocn++];
655 ga.loc.plc = (P_) buffer[unpacklocn++];
656 closurestart = unpacklocn;
659 fprintf(stderr, "[%u]: PLC @ %#lx\n", gastart, ga.loc.plc);
660 } else if (isOffset(&ga)) {
661 fprintf(stderr, "[%u]: OFFSET TO [%d]\n", gastart, ga.loc.gc.slot);
663 /* Print normal closures */
665 fprintf(stderr, "[%u]: (%x, %d, %x) ", gastart,
666 ga.loc.gc.gtid, ga.loc.gc.slot, ga.weight);
668 info = get_closure_info((P_) (buffer + closurestart), &size, &ptrs, &nonptrs, &vhs);
670 if (INFO_TYPE(info) == INFO_FETCHME_TYPE || IS_BLACK_HOLE(info))
671 size = ptrs = nonptrs = vhs = 0;
673 if (IS_THUNK(info)) {
674 if (IS_UPDATABLE(info))
675 fputs("SHARED ", stderr);
677 fputs("UNSHARED ", stderr);
679 if (IS_BLACK_HOLE(info)) {
680 fputs("BLACK HOLE\n", stderr);
683 fprintf(stderr, "FH [%#lx", buffer[unpacklocn++]);
684 for (i = 1; i < FIXED_HS; i++)
685 fprintf(stderr, " %#lx", buffer[unpacklocn++]);
687 /* Variable header */
689 fprintf(stderr, "] VH [%#lx", buffer[unpacklocn++]);
691 for (i = 1; i < vhs; i++)
692 fprintf(stderr, " %#lx", buffer[unpacklocn++]);
695 fprintf(stderr, "] PTRS %u", ptrs);
699 fprintf(stderr, " NPTRS [%#lx", buffer[unpacklocn++]);
701 for (i = 1; i < nonptrs; i++)
702 fprintf(stderr, " %#lx", buffer[unpacklocn++]);
709 /* Add to queue for processing */
710 QueueClosure((P_) (buffer + closurestart));
713 /* Locate next parent pointer */
715 while (pptr + 1 > pptrs) {
716 parent = DeQueueClosure();
721 (void) get_closure_info(parent, &size, &pptrs, &nonptrs, &pvhs);
725 } while (parent != NULL);
727 fprintf(stderr, "--- End ---\n\n");
732 %************************************************************************
734 \subsection[pack-get-closure-info]{Closure Info}
736 %************************************************************************
738 @get_closure_info@ determines the size, number of pointers etc. for this
739 type of closure -- see @SMInfoTables.lh@ for the legal info. types etc.
741 [Can someone please keep this function up to date. I keep needing it
742 (or something similar) for interpretive code, and it keeps
743 bit-rotting. {\em It really belongs somewhere else too}. KH @@ 17/2/95]
747 get_closure_info(closure, size, ptrs, nonptrs, vhs)
749 W_ *size, *ptrs, *nonptrs, *vhs;
751 P_ ip = (P_) INFO_PTR(closure);
753 switch (INFO_TYPE(ip)) {
754 case INFO_SPEC_U_TYPE:
755 case INFO_SPEC_S_TYPE:
756 case INFO_SPEC_N_TYPE:
757 *size = SPEC_CLOSURE_SIZE(closure);
758 *ptrs = SPEC_CLOSURE_NoPTRS(closure);
759 *nonptrs = SPEC_CLOSURE_NoNONPTRS(closure);
760 *vhs = 0 /*SPEC_VHS*/;
763 case INFO_GEN_U_TYPE:
764 case INFO_GEN_S_TYPE:
765 case INFO_GEN_N_TYPE:
766 *size = GEN_CLOSURE_SIZE(closure);
767 *ptrs = GEN_CLOSURE_NoPTRS(closure);
768 *nonptrs = GEN_CLOSURE_NoNONPTRS(closure);
773 *size = DYN_CLOSURE_SIZE(closure);
774 *ptrs = DYN_CLOSURE_NoPTRS(closure);
775 *nonptrs = DYN_CLOSURE_NoNONPTRS(closure);
779 case INFO_TUPLE_TYPE:
780 *size = TUPLE_CLOSURE_SIZE(closure);
781 *ptrs = TUPLE_CLOSURE_NoPTRS(closure);
782 *nonptrs = TUPLE_CLOSURE_NoNONPTRS(closure);
787 *size = DATA_CLOSURE_SIZE(closure);
788 *ptrs = DATA_CLOSURE_NoPTRS(closure);
789 *nonptrs = DATA_CLOSURE_NoNONPTRS(closure);
793 case INFO_IMMUTUPLE_TYPE:
794 case INFO_MUTUPLE_TYPE:
795 *size = MUTUPLE_CLOSURE_SIZE(closure);
796 *ptrs = MUTUPLE_CLOSURE_NoPTRS(closure);
797 *nonptrs = MUTUPLE_CLOSURE_NoNONPTRS(closure);
801 case INFO_STATIC_TYPE:
802 *size = STATIC_CLOSURE_SIZE(closure);
803 *ptrs = STATIC_CLOSURE_NoPTRS(closure);
804 *nonptrs = STATIC_CLOSURE_NoNONPTRS(closure);
810 *size = IND_CLOSURE_SIZE(closure);
811 *ptrs = IND_CLOSURE_NoPTRS(closure);
812 *nonptrs = IND_CLOSURE_NoNONPTRS(closure);
816 case INFO_CONST_TYPE:
817 *size = CONST_CLOSURE_SIZE(closure);
818 *ptrs = CONST_CLOSURE_NoPTRS(closure);
819 *nonptrs = CONST_CLOSURE_NoNONPTRS(closure);
823 case INFO_SPEC_RBH_TYPE:
824 *size = SPEC_RBH_CLOSURE_SIZE(closure);
825 *ptrs = SPEC_RBH_CLOSURE_NoPTRS(closure);
826 *nonptrs = SPEC_RBH_CLOSURE_NoNONPTRS(closure);
828 *nonptrs -= (2 - *ptrs);
835 case INFO_GEN_RBH_TYPE:
836 *size = GEN_RBH_CLOSURE_SIZE(closure);
837 *ptrs = GEN_RBH_CLOSURE_NoPTRS(closure);
838 *nonptrs = GEN_RBH_CLOSURE_NoNONPTRS(closure);
840 *nonptrs -= (2 - *ptrs);
847 case INFO_CHARLIKE_TYPE:
848 *size = CHARLIKE_CLOSURE_SIZE(closure);
849 *ptrs = CHARLIKE_CLOSURE_NoPTRS(closure);
850 *nonptrs = CHARLIKE_CLOSURE_NoNONPTRS(closure);
854 case INFO_INTLIKE_TYPE:
855 *size = INTLIKE_CLOSURE_SIZE(closure);
856 *ptrs = INTLIKE_CLOSURE_NoPTRS(closure);
857 *nonptrs = INTLIKE_CLOSURE_NoNONPTRS(closure);
861 case INFO_FETCHME_TYPE:
862 *size = FETCHME_CLOSURE_SIZE(closure);
863 *ptrs = FETCHME_CLOSURE_NoPTRS(closure);
864 *nonptrs = FETCHME_CLOSURE_NoNONPTRS(closure);
869 *size = FMBQ_CLOSURE_SIZE(closure);
870 *ptrs = FMBQ_CLOSURE_NoPTRS(closure);
871 *nonptrs = FMBQ_CLOSURE_NoNONPTRS(closure);
876 *size = BQ_CLOSURE_SIZE(closure);
877 *ptrs = BQ_CLOSURE_NoPTRS(closure);
878 *nonptrs = BQ_CLOSURE_NoNONPTRS(closure);
883 *size = BH_CLOSURE_SIZE(closure);
884 *ptrs = BH_CLOSURE_NoPTRS(closure);
885 *nonptrs = BH_CLOSURE_NoNONPTRS(closure);
890 fprintf(stderr, "get_closure_info: Unexpected closure type (%lu), closure %lx\n",
891 INFO_TYPE(ip), (W_) closure);
899 @AllocateHeap@ will bump the heap pointer by @size@ words if the space
900 is available, but it will not perform garbage collection.
910 /* Allocate a new closure */
911 if (SAVE_Hp + size > SAVE_HpLim)
914 newClosure = SAVE_Hp + 1;
921 doGlobalGC(STG_NO_ARGS)
923 fprintf(stderr,"Splat -- we just hit global GC!\n");
930 #endif /* PAR -- whole file */