2 Time-stamp: <Thu Dec 16 1999 18:21:17 Stardate: [-30]4058.61 software>
3 $Id: Pack.c,v 1.3 2000/03/17 14:37:22 simonmar Exp $
5 Graph packing and unpacking code for sending it to another processor
6 and retrieving the original graph structure from the packet.
7 In the old RTS the code was split into Pack.c and Unpack.c (now deceased)
8 Used in GUM and GrAnSim.
10 The GrAnSim version of the code defines routines for *simulating* the
11 packing of closures in the same way it is done in the parallel runtime
12 system. Basically GrAnSim only puts the addresses of the closures to be
13 transferred into a buffer. This buffer will then be associated with the
14 event of transferring the graph. When this event is scheduled, the
15 @UnpackGraph@ routine is called and the buffer can be discarded
18 Note that in GranSim we need many buffers, not just one per PE. */
20 //@node Graph packing, , ,
21 //@section Graph packing
23 #if defined(PAR) || defined(GRAN) /* whole file */
25 #define _HS (sizeofW(StgHeader))
30 //* Global variables::
31 //* ADT of Closure Queues::
32 //* Initialisation for packing::
33 //* Packing Functions::
34 //* Low level packing routines::
35 //* Unpacking routines::
36 //* Aux fcts for packing::
37 //* Printing Packet Contents::
42 //@node Includes, Prototypes, Graph packing, Graph packing
43 //@subsection Includes
48 #include "ClosureTypes.h"
52 #include "GranSimRts.h"
53 #include "ParallelRts.h"
55 # include "ParallelDebug.h"
59 /* Which RTS flag should be used to get the size of the pack buffer ? */
61 # define RTS_PACK_BUFFER_SIZE RtsFlags.ParFlags.packBufferSize
63 # define RTS_PACK_BUFFER_SIZE RtsFlags.GranFlags.packBufferSize
66 //@node Prototypes, Global variables, Includes, Graph packing
67 //@subsection Prototypes
72 //@node ADT of closure queues, Init for packing, Prototypes, Prototypes
73 //@subsubsection ADT of closure queues
75 static inline void AllocClosureQueue(nat size);
76 static inline void InitClosureQueue(void);
77 static inline rtsBool QueueEmpty(void);
78 static inline void QueueClosure(StgClosure *closure);
79 static inline StgClosure *DeQueueClosure(void);
81 //@node Init for packing, Packing routines, ADT of closure queues, Prototypes
82 //@subsubsection Init for packing
84 static void initPacking(void);
86 rtsBool initPackBuffer(void);
88 rtsPackBuffer *InstantiatePackBuffer (void);
89 static void reallocPackBuffer (void);
92 //@node Packing routines, Low level packing fcts, Init for packing, Prototypes
93 //@subsubsection Packing routines
95 static void PackClosure (StgClosure *closure);
97 //@node Low level packing fcts, Unpacking routines, Packing routines, Prototypes
98 //@subsubsection Low level packing fcts
101 static inline void Pack (StgClosure *data);
103 static inline void Pack (StgWord data);
105 static void PackPLC (StgPtr addr);
106 static void PackOffset (int offset);
107 static void GlobaliseAndPackGA (StgClosure *closure);
110 //@node Unpacking routines, Aux fcts for packing, Low level packing fcts, Prototypes
111 //@subsubsection Unpacking routines
114 void InitPendingGABuffer(nat size);
115 void CommonUp(StgClosure *src, StgClosure *dst);
116 StgClosure *UnpackGraph(rtsPackBuffer *packBuffer,
120 void CommonUp(StgClosure *src, StgClosure *dst);
121 StgClosure *UnpackGraph(rtsPackBuffer* buffer);
124 //@node Aux fcts for packing, , Unpacking routines, Prototypes
125 //@subsubsection Aux fcts for packing
128 static void DonePacking(void);
129 static void AmPacking(StgClosure *closure);
130 static int OffsetFor(StgClosure *closure);
131 static rtsBool NotYetPacking(int offset);
132 static rtsBool RoomToPack (nat size, nat ptrs);
133 rtsBool isOffset(globalAddr *ga);
134 rtsBool isFixed(globalAddr *ga);
136 static void DonePacking(void);
137 static rtsBool NotYetPacking(StgClosure *closure);
140 //@node Global variables, ADT of Closure Queues, Prototypes, Graph packing
141 //@subsection Global variables
143 Static data declarations
146 static nat pack_locn, /* ptr to first free loc in pack buffer */
148 buf_id = 1; /* identifier for buffer */
149 static nat unpacked_size;
150 static nat reservedPAsize; /* Space reserved for primitive arrays */
151 static rtsBool RoomInBuffer;
156 To be pedantic: in GrAnSim we're packing *addresses* of closures,
157 not the closures themselves.
159 static rtsPackBuffer *Bonzo = NULL; /* size: can be set via option */
161 static rtsPackBuffer *Bonzo = NULL; /* size: can be set via option */
165 Bit of a hack for testing if a closure is the root of the graph. This is
166 set in @PackNearbyGraph@ and tested in @PackClosure@.
169 static nat packed_thunks = 0;
170 static StgClosure *graph_root;
174 The offset hash table is used during packing to record the location in
175 the pack buffer of each closure which is packed.
177 //@cindex offsetTable
178 static HashTable *offsetTable;
180 //@cindex PendingGABuffer
181 static globalAddr *PendingGABuffer;
182 /* is initialised in main; */
185 //@node ADT of Closure Queues, Initialisation for packing, Global variables, Graph packing
186 //@subsection ADT of Closure Queues
194 //@node Closure Queues, Init routines, ADT of Closure Queues, ADT of Closure Queues
195 //@subsubsection Closure Queues
199 These routines manage the closure queue.
202 static nat clq_pos, clq_size;
204 static StgClosure **ClosureQueue = NULL; /* HWL: init in main */
206 //@node Init routines, Basic routines, Closure Queues, ADT of Closure Queues
207 //@subsubsection Init routines
209 /* @InitClosureQueue@ initialises the closure queue. */
211 //@cindex AllocClosureQueue
213 AllocClosureQueue(size)
216 ASSERT(ClosureQueue == NULL);
217 ClosureQueue = (StgClosure**) stgMallocWords(size, "AllocClosureQueue");
220 //@cindex InitClosureQueue
222 InitClosureQueue(void)
224 clq_pos = clq_size = 0;
226 if ( ClosureQueue == NULL )
227 AllocClosureQueue(RTS_PACK_BUFFER_SIZE);
230 //@node Basic routines, , Init routines, ADT of Closure Queues
231 //@subsubsection Basic routines
234 QueueEmpty returns rtsTrue if the closure queue is empty; rtsFalse otherwise.
238 static inline rtsBool
241 return(clq_pos >= clq_size);
244 /* QueueClosure adds its argument to the closure queue. */
246 //@cindex QueueClosure
248 QueueClosure(closure)
251 if(clq_size < RTS_PACK_BUFFER_SIZE )
252 ClosureQueue[clq_size++] = closure;
254 barf("Closure Queue Overflow (EnQueueing %p (%s))",
255 closure, info_type(closure));
258 /* DeQueueClosure returns the head of the closure queue. */
260 //@cindex DeQueueClosure
261 static inline StgClosure *
265 return(ClosureQueue[clq_pos++]);
267 return((StgClosure*)NULL);
270 //@node Initialisation for packing, Packing Functions, ADT of Closure Queues, Graph packing
271 //@subsection Initialisation for packing
273 Simple Packing Routines
275 About packet sizes in GrAnSim: In GrAnSim we use a malloced block of
276 gransim_pack_buffer_size words to simulate a packet of pack_buffer_size
277 words. In the simulated PackBuffer we only keep the addresses of the
278 closures that would be packed in the parallel system (see Pack). To
279 decide if a packet overflow occurs pack_buffer_size must be compared
280 versus unpacked_size (see RoomToPack). Currently, there is no multi
281 packet strategy implemented, so in the case of an overflow we just stop
282 adding closures to the closure queue. If an overflow of the simulated
283 packet occurs, we just realloc some more space for it and carry on as
288 InstantiatePackBuffer (void) {
289 extern rtsPackBuffer *Bonzo;
291 Bonzo = (rtsPackBuffer *) stgMallocWords(sizeofW(rtsPackBuffer),
292 "InstantiatePackBuffer: failed to alloc packBuffer");
293 Bonzo->size = RtsFlags.GranFlags.packBufferSize_internal;
294 Bonzo->buffer = (StgWord **) stgMallocWords(RtsFlags.GranFlags.packBufferSize_internal,
295 "InstantiatePackBuffer: failed to alloc GranSim internal packBuffer");
296 /* NB: gransim_pack_buffer_size instead of pack_buffer_size -- HWL */
297 /* stgMallocWords is now simple allocate in Storage.c */
303 Reallocate the GranSim internal pack buffer to make room for more closure
304 pointers. This is independent of the check for packet overflow as in GUM
307 reallocPackBuffer (void) {
309 ASSERT(pack_locn >= (int)Bonzo->size+sizeofW(rtsPackBuffer));
311 IF_GRAN_DEBUG(packBuffer,
312 belch("** Increasing size of PackBuffer %p to %d words (PE %u @ %d)\n",
313 Bonzo, Bonzo->size+REALLOC_SZ,
314 CurrentProc, CurrentTime[CurrentProc]));
316 Bonzo = (rtsPackBuffer*)realloc(Bonzo,
317 sizeof(StgClosure*)*(REALLOC_SZ +
319 sizeofW(rtsPackBuffer))) ;
320 if (Bonzo==(rtsPackBuffer*)NULL)
321 barf("Failing to realloc %d more words for PackBuffer %p (PE %u @ %d)\n",
322 REALLOC_SZ, Bonzo, CurrentProc, CurrentTime[CurrentProc]);
324 Bonzo->size += REALLOC_SZ;
326 ASSERT(pack_locn < Bonzo->size+sizeofW(rtsPackBuffer));
331 /* @initPacking@ initialises the packing buffer etc. */
332 //@cindex initPackBuffer
336 if (Bonzo == NULL) { /* not yet allocated */
338 if ((Bonzo = (rtsPackBuffer *)
339 stgMallocWords(sizeofW(rtsPackBuffer)+RtsFlags.ParFlags.packBufferSize,
340 "initPackBuffer")) == NULL)
343 InitPendingGABuffer(RtsFlags.ParFlags.packBufferSize);
344 AllocClosureQueue(RtsFlags.ParFlags.packBufferSize);
354 Bonzo = InstantiatePackBuffer(); /* for GrAnSim only -- HWL */
355 /* NB: free in UnpackGraph */
358 Bonzo->id = buf_id++; /* buffer id are only used for debugging! */
359 pack_locn = 0; /* the index into the actual pack buffer */
360 unpacked_size = 0; /* the size of the whole graph when unpacked */
362 RoomInBuffer = rtsTrue;
364 packed_thunks = 0; /* total number of thunks packed so far */
366 offsetTable = allocHashTable();
370 //@node Packing Functions, Low level packing routines, Initialisation for packing, Graph packing
371 //@subsection Packing Functions
374 //* Packing Sections of Nearby Graph::
375 //* Packing Closures::
378 //@node Packing Sections of Nearby Graph, Packing Closures, Packing Functions, Packing Functions
379 //@subsubsection Packing Sections of Nearby Graph
381 Packing Sections of Nearby Graph
383 @PackNearbyGraph@ packs a closure and associated graph into a static
384 buffer (@PackBuffer@). It returns the address of this buffer and the
385 size of the data packed into the buffer (in its second parameter,
386 @packBufferSize@). The associated graph is packed in a depth first
387 manner, hence it uses an explicit queue of closures to be packed rather
388 than simply using a recursive algorithm. Once the packet is full,
389 closures (other than primitive arrays) are packed as FetchMes, and their
390 children are not queued for packing. */
392 //@cindex PackNearbyGraph
394 /* NB: this code is shared between GranSim and GUM;
395 tso only used in GranSim */
397 PackNearbyGraph(closure, tso, packBufferSize)
402 extern rtsPackBuffer *Bonzo;
403 /* Ensure enough heap for all possible RBH_Save closures */
405 ASSERT(RTS_PACK_BUFFER_SIZE > 0);
407 /* ToDo: check that we have enough heap for the packet
409 if (Hp + PACK_HEAP_REQUIRED > HpLim)
415 graph_root = closure;
419 belch(">>> Packing <<%d>> (buffer @ %p); graph root @ %p [PE %d]\n demanded by TSO %d (%p) [PE %u]",
420 Bonzo->id, Bonzo, closure, where_is(closure),
421 tso->id, tso, where_is((StgClosure*)tso)));
424 belch("** PrintGraph of %p is:", closure);
425 PrintGraph(closure,0));
428 belch(">>> Packing <<%d>> (buffer @ %p); graph root @ %p [%x]\n demanded by TSO %d (%p)",
429 Bonzo->id, Bonzo, closure, mytid,
433 belch("** PrintGraph of %p is:", closure);
434 belch("** pack_locn=%d", pack_locn);
435 PrintGraph(closure,0));
437 QueueClosure(closure);
439 PackClosure(DeQueueClosure());
440 } while (!QueueEmpty());
444 /* Record how much space is needed to unpack the graph */
445 Bonzo->tso = tso; // ToDo: check: used in GUM or only for debugging?
446 Bonzo->unpacked_size = unpacked_size;
447 Bonzo->size = pack_locn;
449 /* Set the size parameter */
450 ASSERT(pack_locn <= RtsFlags.ParFlags.packBufferSize);
451 *packBufferSize = pack_locn;
455 /* Record how much space is needed to unpack the graph */
456 // PackBuffer[PACK_FLAG_LOCN] = (P_) MAGIC_PACK_FLAG; for testing
458 Bonzo->unpacked_size = unpacked_size;
460 // ASSERT(pack_locn <= PackBuffer[PACK_SIZE_LOCN]+PACK_HDR_SIZE);
461 /* ToDo: Print an earlier, more meaningful message */
462 if (pack_locn==0) /* i.e. packet is empty */
463 barf("EMPTY PACKET! Can't transfer closure %p at all!!\n",
465 Bonzo->size = pack_locn;
466 *packBufferSize = pack_locn;
470 DonePacking(); /* {GrAnSim}vaD 'ut'Ha' */
474 belch("** Finished <<%d>> packing graph %p; closures packed: %d; thunks packed: %d; size of graph: %d",
475 Bonzo->id, closure, Bonzo->size, packed_thunks, Bonzo->unpacked_size));
476 if (RtsFlags.GranFlags.GranSimStats.Global) {
477 globalGranStats.tot_packets++;
478 globalGranStats.tot_packet_size += pack_locn;
481 IF_GRAN_DEBUG(pack, PrintPacket(Bonzo));
484 belch("** Finished <<%d>> packing graph %p; closures packed: %d; thunks packed: %d; size of graph: %d",
485 Bonzo->id, closure, Bonzo->size, packed_thunks, Bonzo->unpacked_size);
492 //@cindex PackOneNode
495 /* This version is used when the node is already local */
498 PackOneNode(closure, tso, packBufferSize)
503 extern rtsPackBuffer *Bonzo;
509 belch("** PackOneNode: %p (%s)[PE %d] requested by TSO %d (%p) [PE %d]",
510 closure, info_type(closure),
511 where_is(closure), tso->id, tso, where_is((StgClosure *)tso)));
515 /* Record how much space is needed to unpack the graph */
517 Bonzo->unpacked_size = unpacked_size;
519 /* Set the size parameter */
520 ASSERT(pack_locn <= RTS_PACK_BUFFER_SIZE);
521 Bonzo->size = pack_locn;
522 *packBufferSize = pack_locn;
524 if (RtsFlags.GranFlags.GranSimStats.Global) {
525 globalGranStats.tot_packets++;
526 globalGranStats.tot_packet_size += pack_locn;
538 PackTSO and PackStkO are entry points for two special kinds of closure
539 which are used in the parallel RTS. Compared with other closures they
540 are rather awkward to pack because they don't follow the normal closure
541 layout (where all pointers occur before all non-pointers). Luckily,
542 they're only needed when migrating threads between processors. */
546 PackTSO(tso, packBufferSize)
550 extern rtsPackBuffer *Bonzo;
552 belch("** Packing TSO %d (%p)", tso->id, tso));
554 // PackBuffer[0] = PackBuffer[1] = 0; ???
560 PackStkO(stko, packBufferSize)
564 extern rtsPackBuffer *Bonzo;
566 belch("** Packing STKO %p", stko));
568 // PackBuffer[0] = PackBuffer[1] = 0;
573 PackFetchMe(StgClosure *closure)
575 barf("{PackFetchMe}Daq Qagh: no FetchMe closures in GRAN!");
581 PackTSO(tso, packBufferSize)
585 barf("{PackTSO}Daq Qagh: trying to pack a TSO; thread migrations not supported, yet");
589 PackStkO(stko, packBufferSize)
593 barf("{PackStkO}Daq Qagh: trying to pack a STKO; thread migrations not supported, yet");
596 //@cindex PackFetchMe
598 PackFetchMe(StgClosure *closure)
604 barf("{PackFetchMe}Daq Qagh: no FetchMe closures in GRAN!");
606 /* Pack a FetchMe closure instead of closure */
608 /* this assumes that the info ptr is always the first word in a closure*/
610 for (i = 1; i < _HS; ++i) // pack rest of fixed header
611 Pack((StgWord)*(((StgPtr)closure)+i));
613 unpacked_size += _HS; // ToDo: check
619 //@node Packing Closures, , Packing Sections of Nearby Graph, Packing Functions
620 //@subsubsection Packing Closures
624 @PackClosure@ is the heart of the normal packing code. It packs a single
625 closure into the pack buffer, skipping over any indirections and
626 globalising it as necessary, queues any child pointers for further
627 packing, and turns it into a @FetchMe@ or revertible black hole (@RBH@)
628 locally if it was a thunk. Before the actual closure is packed, a
629 suitable global address (GA) is inserted in the pack buffer. There is
630 always room to pack a fetch-me to the closure (guaranteed by the
631 RoomToPack calculation), and this is packed if there is no room for the
634 Space is allocated for any primitive array children of a closure, and
635 hence a primitive array can always be packed along with it's parent
638 //@cindex PackClosure
647 StgClosure *indirectee, *rbh;
648 nat size, ptrs, nonptrs, vhs, i, clpack_locn;
649 rtsBool is_CONSTR = rtsFalse;
652 ASSERT(closure!=NULL);
653 indirectee = closure;
655 /* Don't pack indirection closures */
656 closure = indirectee;
657 indirectee = IS_INDIRECTION(closure);
660 belch("** Shorted an indirection (%s) at %p (-> %p)",
661 info_type(closure), closure, indirectee));
662 } while (indirectee);
664 clpack_locn = OffsetFor(closure);
666 /* If the closure has been packed already, just pack an indirection to it
667 to guarantee that the graph doesn't become a tree when unpacked */
668 if (!NotYetPacking(clpack_locn)) {
671 PackOffset(clpack_locn);
676 * PLCs reside on all of the PEs already. Just pack the
677 * address as a GA (a bit of a kludge, since an address may
678 * not fit in *any* of the individual GA fields). Const,
679 * charlike and small intlike closures are converted into
682 switch (get_itbl(closure)->type) {
685 // check error cases only in a debugging setup
692 barf("** {Pack}Daq Qagh: found return vector %p (%s) when packing (thread migration not implemented)",
693 closure, info_type(closure));
700 barf("** {Pack}Daq Qagh: found stack frame %p (%s) when packing (thread migration not implemented)",
701 closure, info_type(closure));
707 /* something's very wrong */
708 barf("** {Pack}Daq Qagh: found %s (%p) when packing",
709 info_type(closure), closure);
713 case CONSTR_CHARLIKE:
715 belch("** Packing a charlike closure %d",
716 ((StgIntCharlikeClosure*)closure)->data));
718 PackPLC(CHARLIKE_CLOSURE(((StgIntCharlikeClosure*)closure)->data));
723 StgInt val = ((StgIntCharlikeClosure*)closure)->data;
725 if ((val <= MAX_INTLIKE) && (val >= MIN_INTLIKE)) {
727 belch("** Packing a small intlike %d as a PLC", val));
728 PackPLC(INTLIKE_CLOSURE(val));
732 belch("** Packing a big intlike %d as a normal closure",
744 /* it's a constructor (i.e. plain data) but we don't know
745 how many ptrs, non-ptrs there are => use generic code */
747 belch("** Packing a CONSTR %p (%s) using generic packing with GA",
748 closure, info_type(closure)));
749 // is_CONSTR = rtsTrue;
751 /* fall through to generic packing code */
754 case CONSTR_NOCAF_STATIC:// For now we ship indirections to CAFs: They are
755 // evaluated on each PE if needed
757 belch("** Packing a %p (%s) as a PLC",
758 closure, info_type(closure)));
764 /* MVARs may not be copied; they are sticky objects in the new RTS */
765 /* therefore we treat them just as RBHs etc (what a great system!) */
767 belch("** Found an MVar at %p (%s)",
768 closure, info_type(closure)));
769 /* fall through !! */
771 case THUNK_SELECTOR: // ToDo: fix packing of this strange beast
773 belch("** Found an THUNK_SELECTORE at %p (%s)",
774 closure, info_type(closure)));
775 /* fall through !! */
778 case SE_CAF_BLACKHOLE:
785 /* If it's a (revertible) black-hole, pack a FetchMe closure to it */
786 //ASSERT(pack_locn > PACK_HDR_SIZE);
789 belch("** Packing a BH or FM at %p (%s) of (fixed size %d)",
790 closure, info_type(closure), _HS));
792 /* Need a GA even when packing a constructed FETCH_ME (cruel world!) */
793 GlobaliseAndPackGA(closure);
795 PackFetchMe(closure);
799 /* IF_PAR_DEBUG(pack, */
800 /* belch("** Not a PLC or BH ... ")); */
803 /* get info about basic layout of the closure */
804 info = get_closure_info(closure, &size, &ptrs, &nonptrs, &vhs, str);
806 ASSERT(!IS_BLACK_HOLE(closure));
809 fprintf(stderr, "** packing %p (%s) (size=%d, ptrs=%d, nonptrs=%d)\n",
810 closure, info_type(closure), size, ptrs, nonptrs));
813 * Now peek ahead to see whether the closure has any primitive array
817 ToDo: fix this code -- HWL
818 for (i = 0; i < ptrs; ++i) {
819 StgInfoTable * childInfo;
820 nat childSize, childPtrs, childNonPtrs, childVhs;
822 // extract i-th pointer out of closure
823 childInfo = get_closure_info(((PP_) (closure))[i + FIXED_HS + vhs],
824 &childSize, &childPtrs, &childNonPtrs, &childVhs, str);
825 if (IS_BIG_MOTHER(childInfo)) {
826 reservedPAsize += PACK_GA_SIZE + FIXED_HS + childVhs + childNonPtrs
827 + childPtrs * PACK_FETCHME_SIZE;
831 /* Record the location of the GA */
834 /* Pack the global address */
836 GlobaliseAndPackGA(closure);
839 belch("** No GA allocated for CONSTR %p (%s)",
840 closure, info_type(closure)));
844 * Pack a fetchme to the closure if it's a black hole, or the buffer is full
845 * and it isn't a primitive array. N.B. Primitive arrays are always packed
846 * (because their parents index into them directly)
849 // ToDo: pack FMs if no more room available in packet (see below)
850 if (!(RoomToPack(PACK_GA_SIZE + _HS + vhs + nonptrs, ptrs)))
851 barf("** Qagh: Pack: not enough room in packet to pack closure %p (%s)",
852 closure, info_type(closure));
855 Has been moved into the switch statement
857 if (IS_BLACK_HOLE(closure))
858 !(RoomToPack(PACK_GA_SIZE + FIXED_HS + vhs + nonptrs, ptrs)
859 || IS_BIG_MOTHER(info)))
862 ASSERT(pack_locn > PACK_HDR_SIZE);
865 for (i = 0; i < FIXED_HS; ++i) {
866 if (i == INFO_HDR_POSN)
867 Pack((StgWord) FetchMe_info);
872 unpacked_size += FIXED_HS + FETCHME_CLOSURE_SIZE(dummy);
876 if (info->type == ARR_WORDS || info->type == MUT_ARR_PTRS ||
877 info->type == MUT_ARR_PTRS_FROZEN || info->type == MUT_VAR)
878 belch("** ghuH: found %s; packing of primitive arrays not yet implemented",
881 /* At last! A closure we can actually pack! */
882 if (ip_MUTABLE(info) && (info->type != FETCH_ME))
883 fprintf(stderr, "** ghuH: Replicated a Mutable closure!\n");
886 Remember, the generic closure layout is as follows:
887 +-------------------------------------------------+
888 | FIXED HEADER | VARIABLE HEADER | PTRS | NON-PRS |
889 +-------------------------------------------------+
891 /* pack fixed and variable header */
892 for (i = 0; i < _HS + vhs; ++i)
893 Pack((StgWord)*(((StgPtr)closure)+i));
895 /* register all ptrs for further packing */
896 for (i = 0; i < ptrs; ++i)
897 QueueClosure(((StgClosure *) *(((StgPtr)closure)+(i+_HS+vhs))));
900 for (i = 0; i < nonptrs; ++i)
901 Pack((StgWord)*(((StgPtr)closure)+(i+_HS+vhs+ptrs)));
903 unpacked_size += _HS + (size < MIN_UPD_SIZE ? MIN_UPD_SIZE : size);
906 * Record that this is a revertable black hole so that we can fill in
907 * its address from the fetch reply. Problem: unshared thunks may cause
908 * space leaks this way, their GAs should be deallocated following an
912 // IS_UPDATABLE(closure) == !closure_UNPOINTED(closure) !? HWL
913 if (closure_THUNK(closure) && !closure_UNPOINTED(closure)) {
914 rbh = convertToRBH(closure);
915 ASSERT(rbh == closure); // rbh at the same position (minced version)
922 /* Fake the packing of a closure */
928 StgInfoTable *info, *childInfo;
929 nat size, ptrs, nonptrs, vhs;
930 char info_hdr_ty[80];
932 StgClosure *indirectee, *rbh;
934 rtsBool is_mutable, will_be_rbh, no_more_thunks_please;
936 is_mutable = rtsFalse;
938 /* In GranSim we don't pack and unpack closures -- we just simulate
939 packing by updating the bitmask. So, the graph structure is unchanged
940 i.e. we don't short out indirections here. -- HWL */
942 /* Nothing to do with packing but good place to (sanity) check closure;
943 if the closure is a thunk, it must be unique; otherwise we have copied
944 work at some point before that which violates one of our main global
945 assertions in GranSim/GUM */
946 ASSERT(!closure_THUNK(closure) || is_unique(closure));
949 belch("** Packing closure %p (%s)",
950 closure, info_type(closure)));
952 if (where_is(closure) != where_is(graph_root)) {
954 belch("** faking a FETCHME [current PE: %d, closure's PE: %d]",
955 where_is(graph_root), where_is(closure)));
957 /* GUM would pack a FETCHME here; simulate that by increasing the */
958 /* unpacked size accordingly but don't pack anything -- HWL */
959 unpacked_size += _HS + 2 ; // sizeofW(StgFetchMe);
963 /* If the closure's not already being packed */
964 if (!NotYetPacking(closure))
965 /* Don't have to do anything in GrAnSim if closure is already */
969 belch("** Closure %p is already packed and omitted now!",
974 switch (get_itbl(closure)->type) {
975 /* ToDo: check for sticky bit here? */
976 /* BH-like closures which must not be moved to another PE */
977 case CAF_BLACKHOLE: /* # of ptrs, nptrs: 0,2 */
978 case SE_BLACKHOLE: /* # of ptrs, nptrs: 0,2 */
979 case SE_CAF_BLACKHOLE: /* # of ptrs, nptrs: 0,2 */
980 case BLACKHOLE: /* # of ptrs, nptrs: 0,2 */
981 case BLACKHOLE_BQ: /* # of ptrs, nptrs: 1,1 */
982 case RBH: /* # of ptrs, nptrs: 1,1 */
983 /* same for these parallel specific closures */
988 belch("** Avoid packing BH-like closures (%p, %s)!",
989 closure, info_type(closure)));
990 /* Just ignore RBHs i.e. they stay where they are */
995 StgClosure *sel = ((StgSelector *)closure)->selectee;
998 belch("** Avoid packing THUNK_SELECTOR (%p, %s) but queuing %p (%s)!",
999 closure, info_type(closure), sel, info_type(sel)));
1002 belch("** [%p (%s) (Queueing closure) ....]",
1003 sel, info_type(sel)));
1008 case CONSTR_NOCAF_STATIC:
1009 /* For now we ship indirections to CAFs:
1010 * They are evaluated on each PE if needed */
1012 belch("** Nothing to pack for %p (%s)!",
1013 closure, info_type(closure)));
1014 // Pack(closure); GUM only
1017 case CONSTR_CHARLIKE:
1018 case CONSTR_INTLIKE:
1020 belch("** Nothing to pack for %s (%p)!",
1021 closure, info_type(closure)));
1022 // PackPLC(((StgIntCharlikeClosure *)closure)->data); GUM only
1027 /* partial applications; special treatment necessary? */
1030 case CAF_UNENTERED: /* # of ptrs, nptrs: 1,3 */
1031 case CAF_ENTERED: /* # of ptrs, nptrs: 0,4 (allegedly bogus!!) */
1032 /* CAFs; special treatment necessary? */
1036 barf("{PackClosure}Daq Qagh: found an MVAR (%p, %s); ToDo: implement proper treatment of MVARs",
1037 closure, info_type(closure));
1042 case MUT_ARR_PTRS_FROZEN:
1043 /* Mutable objects; require special treatment to ship all data */
1044 is_mutable = rtsTrue;
1050 /* weak pointers and other FFI objects */
1051 barf("{PackClosure}Daq Qagh: found an FFI object (%p, %s); FFI not yet supported by GranSim, sorry",
1052 closure, info_type(closure));
1055 /* parallel objects */
1056 barf("{PackClosure}Daq Qagh: found a TSO when packing (%p, %s); thread migration not yet implemented, sorry",
1057 closure, info_type(closure));
1060 /* Hugs objects (i.e. closures used by the interpreter) */
1061 barf("{PackClosure}Daq Qagh: found a Hugs closure when packing (%p, %s); GranSim not yet integrated with Hugs, sorry",
1062 closure, info_type(closure));
1064 case IND: /* # of ptrs, nptrs: 1,0 */
1065 case IND_STATIC: /* # of ptrs, nptrs: 1,0 */
1066 case IND_PERM: /* # of ptrs, nptrs: 1,1 */
1067 case IND_OLDGEN: /* # of ptrs, nptrs: 1,1 */
1068 case IND_OLDGEN_PERM: /* # of ptrs, nptrs: 1,1 */
1069 /* we shouldn't find an indirection here, because we have shorted them
1070 out at the beginning of this functions already.
1074 barf("{PackClosure}Daq Qagh: found indirection when packing (%p, %s)",
1075 closure, info_type(closure));
1082 /* stack frames; should never be found when packing for now;
1083 once we support thread migration these have to be covered properly
1085 barf("{PackClosure}Daq Qagh: found stack frame when packing (%p, %s)",
1086 closure, info_type(closure));
1094 /* vectored returns; should never be found when packing; */
1095 barf("{PackClosure}Daq Qagh: found vectored return (%p, %s)",
1096 closure, info_type(closure));
1098 case INVALID_OBJECT:
1099 barf("{PackClosure}Daq Qagh: found Invalid object (%p, %s)",
1100 closure, info_type(closure));
1104 Here we know that the closure is a CONSTR, FUN or THUNK (maybe
1105 a specialised version with wired in #ptr/#nptr info; currently
1106 we treat these specialised versions like the generic version)
1110 /* Otherwise it's not Fixed */
1112 info = get_closure_info(closure, &size, &ptrs, &nonptrs, &vhs, str);
1113 will_be_rbh = closure_THUNK(closure) && !closure_UNPOINTED(closure);
1116 belch("** Info on closure %p (%s): size=%d; ptrs=%d",
1117 closure, info_type(closure),
1119 (will_be_rbh) ? "will become RBH" : "will NOT become RBH"));
1121 // check whether IS_UPDATABLE(closure) == !closure_UNPOINTED(closure) -- HWL
1122 no_more_thunks_please =
1123 (RtsFlags.GranFlags.ThunksToPack>0) &&
1124 (packed_thunks>=RtsFlags.GranFlags.ThunksToPack);
1127 should be covered by get_closure_info
1128 if (info->type == FETCH_ME || info->type == FETCH_ME_BQ ||
1129 info->type == BLACKHOLE || info->type == RBH )
1130 size = ptrs = nonptrs = vhs = 0;
1132 /* Now peek ahead to see whether the closure has any primitive */
1133 /* array children */
1136 for (i = 0; i < ptrs; ++i) {
1138 W_ childSize, childPtrs, childNonPtrs, childVhs;
1140 childInfo = get_closure_info(((StgPtrPtr) (closure))[i + FIXED_HS + vhs],
1141 &childSize, &childPtrs, &childNonPtrs,
1142 &childVhs, junk_str);
1143 if (IS_BIG_MOTHER(childInfo)) {
1144 reservedPAsize += PACK_GA_SIZE + FIXED_HS +
1145 childVhs + childNonPtrs +
1146 childPtrs * PACK_FETCHME_SIZE;
1147 PAsize += PACK_GA_SIZE + FIXED_HS + childSize;
1148 PAptrs += childPtrs;
1152 /* Don't pack anything (GrAnSim) if it's a black hole, or the buffer
1153 * is full and it isn't a primitive array. N.B. Primitive arrays are
1154 * always packed (because their parents index into them directly) */
1156 if (IS_BLACK_HOLE(closure))
1160 !(RoomToPack(PACK_GA_SIZE + FIXED_HS + vhs + nonptrs, ptrs)
1161 || IS_BIG_MOTHER(info)))
1165 /* At last! A closure we can actually pack! */
1167 if (closure_MUTABLE(closure)) // not nec. && (info->type != FETCHME))
1168 belch("ghuH: Replicated a Mutable closure!");
1170 if (RtsFlags.GranFlags.GranSimStats.Global &&
1171 no_more_thunks_please && will_be_rbh) {
1172 globalGranStats.tot_cuts++;
1173 if ( RtsFlags.GranFlags.Debug.pack )
1174 belch("** PackClosure (w/ ThunksToPack=%d): Cutting tree with root at %#x\n",
1175 RtsFlags.GranFlags.ThunksToPack, closure);
1176 } else if (will_be_rbh || (closure==graph_root) ) {
1178 globalGranStats.tot_thunks++;
1181 if (no_more_thunks_please && will_be_rbh)
1182 return; /* don't pack anything */
1184 /* actual PACKING done here -- HWL */
1186 for (i = 0; i < ptrs; ++i) {
1187 /* extract i-th pointer from closure */
1188 QueueClosure((StgClosure *)(closure->payload[i]));
1190 belch("** [%p (%s) (Queueing closure) ....]",
1191 closure->payload[i], info_type(payloadPtr(closure,i))));
1195 for packing words (GUM only) do something like this:
1197 for (i = 0; i < ptrs; ++i) {
1198 Pack(payloadWord(obj,i+j));
1201 /* Turn thunk into a revertible black hole. */
1203 rbh = convertToRBH(closure);
1204 ASSERT(rbh != NULL);
1209 //@node Low level packing routines, Unpacking routines, Packing Functions, Graph packing
1210 //@subsection Low level packing routines
1213 @Pack@ is the basic packing routine. It just writes a word of data into
1214 the pack buffer and increments the pack location. */
1223 ASSERT(pack_locn < RtsFlags.ParFlags.packBufferSize);
1224 Bonzo->buffer[pack_locn++] = data;
1231 StgClosure *closure;
1234 nat size, ptrs, nonptrs, vhs;
1237 /* This checks the size of the GrAnSim internal pack buffer. The simulated
1238 pack buffer is checked via RoomToPack (as in GUM) */
1239 if (pack_locn >= (int)Bonzo->size+sizeofW(rtsPackBuffer))
1240 reallocPackBuffer();
1242 if (closure==(StgClosure*)NULL)
1243 belch("Qagh {Pack}Daq: Trying to pack 0");
1244 Bonzo->buffer[pack_locn++] = closure;
1245 /* ASSERT: Data is a closure in GrAnSim here */
1246 info = get_closure_info(closure, &size, &ptrs, &nonptrs, &vhs, str);
1247 unpacked_size += _HS + (size < MIN_UPD_SIZE ?
1254 If a closure is local, make it global. Then, divide its weight for
1255 export. The GA is then packed into the pack buffer. */
1260 GlobaliseAndPackGA(closure)
1261 StgClosure *closure;
1266 if ((ga = LAGAlookup(closure)) == NULL)
1267 ga = makeGlobal(closure, rtsTrue);
1268 splitWeight(&packGA, ga);
1269 ASSERT(packGA.weight > 0);
1272 fprintf(stderr, "** Globalising closure %p (%s) with GA",
1273 closure, info_type(closure));
1275 fputc('\n', stderr));
1278 Pack((StgWord) packGA.weight);
1279 Pack((StgWord) packGA.payload.gc.gtid);
1280 Pack((StgWord) packGA.payload.gc.slot);
1284 @PackPLC@ makes up a bogus GA for a PLC. Weight 0 implies that a PLC
1285 address follows instead of PE, slot. */
1293 Pack(0L); /* weight */
1294 Pack((StgWord) addr); /* address */
1298 @PackOffset@ packs a special GA value that will be interpreted as an
1299 offset to a closure in the pack buffer. This is used to avoid unfolding
1300 the graph structure into a tree. */
1307 belch("** Packing Offset %d at pack location %u",
1308 offset, pack_locn));
1309 Pack(1L); /* weight */
1311 Pack(offset); /* slot/offset */
1315 //@node Unpacking routines, Aux fcts for packing, Low level packing routines, Graph packing
1316 //@subsection Unpacking routines
1319 This was formerly in the (now deceased) module Unpack.c
1321 Unpacking closures which have been exported to remote processors
1323 This module defines routines for unpacking closures in the parallel
1324 runtime system (GUM).
1326 In the case of GrAnSim, this module defines routines for *simulating* the
1327 unpacking of closures as it is done in the parallel runtime system.
1330 //@node GUM code, Local Definitions, Unpacking routines, Unpacking routines
1331 //@subsubsection GUM code
1335 //@cindex InitPendingGABuffer
1337 InitPendingGABuffer(size)
1340 PendingGABuffer = (globalAddr *)
1341 stgMallocBytes(size*2*sizeof(globalAddr),
1342 "InitPendingGABuffer");
1346 @CommonUp@ commons up two closures which we have discovered to be
1347 variants of the same object. One is made an indirection to the other. */
1351 CommonUp(StgClosure *src, StgClosure *dst)
1353 StgBlockingQueueElement *bqe;
1355 ASSERT(src != (StgClosure *)NULL && dst != (StgClosure *)NULL);
1358 IF_PAR_DEBUG(verbose,
1359 belch("__ CommonUp %p (%s) with %p (%s)",
1360 src, info_type(src), dst, info_type(dst)));
1362 switch (get_itbl(src)->type) {
1364 bqe = ((StgBlockingQueue *)src)->blocking_queue;
1368 bqe = ((StgFetchMeBlockingQueue *)src)->blocking_queue;
1372 bqe = ((StgRBH *)src)->blocking_queue;
1381 /* Don't common up anything else */
1384 /* NB: this also awakens the blocking queue for src */
1386 // updateWithIndirection(src, dst);
1388 ASSERT(!IS_BIG_MOTHER(INFO_PTR(dst)));
1389 if (bqe != END_BQ_QUEUE)
1390 awaken_blocked_queue(bqe, src);
1395 @UnpackGraph@ unpacks the graph contained in a message buffer. It
1396 returns a pointer to the new graph. The @gamap@ parameter is set to
1397 point to an array of (oldGA,newGA) pairs which were created as a result
1398 of unpacking the buffer; @nGAs@ is set to the number of GA pairs which
1401 The format of graph in the pack buffer is as defined in @Pack.lc@. */
1403 //@cindex UnpackGraph
1405 UnpackGraph(packBuffer, gamap, nGAs)
1406 rtsPackBuffer *packBuffer;
1410 nat size, ptrs, nonptrs, vhs;
1411 StgWord **buffer, **bufptr, **slotptr;
1412 globalAddr ga, *gaga;
1413 StgClosure *closure, *existing,
1414 *graphroot, *graph, *parent;
1415 StgInfoTable *ip, *oldip;
1417 pptr = 0, pptrs = 0, pvhs;
1421 initPackBuffer(); /* in case it isn't already init'd */
1422 graphroot = (StgClosure *)NULL;
1424 gaga = PendingGABuffer;
1428 /* Unpack the header */
1429 bufsize = packBuffer->size;
1430 buffer = packBuffer->buffer;
1435 graph = allocate(bufsize);
1436 ASSERT(graph != NULL);
1439 parent = (StgClosure *)NULL;
1442 /* This is where we will ultimately save the closure's address */
1445 /* First, unpack the next GA or PLC */
1446 ga.weight = (rtsWeight) *bufptr++;
1448 if (ga.weight > 0) {
1449 ga.payload.gc.gtid = (GlobalTaskId) *bufptr++;
1450 ga.payload.gc.slot = (int) *bufptr++;
1452 ga.payload.plc = (StgPtr) *bufptr++;
1455 /* Now unpack the closure body, if there is one */
1457 /* No more to unpack; just set closure to local address */
1459 belch("_* Unpacked PLC at %x", ga.payload.plc));
1461 closure = ga.payload.plc;
1462 } else if (isOffset(&ga)) {
1463 /* No more to unpack; just set closure to cached address */
1465 belch("_* Unpacked indirection to %p (was offset %x)",
1466 (StgClosure *) buffer[ga.payload.gc.slot],
1467 ga.payload.gc.slot));
1468 ASSERT(parent != (StgClosure *)NULL);
1470 closure = (StgClosure *) buffer[ga.payload.gc.slot];
1472 /* Now we have to build something. */
1475 ASSERT(bufsize > 0);
1478 * Close your eyes. You don't want to see where we're looking. You
1479 * can't get closure info until you've unpacked the variable header,
1480 * but you don't know how big it is until you've got closure info.
1481 * So...we trust that the closure in the buffer is organized the
1482 * same way as they will be in the heap...at least up through the
1483 * end of the variable header.
1485 ip = get_closure_info(bufptr, &size, &ptrs, &nonptrs, &vhs, str);
1488 Remember, the generic closure layout is as follows:
1489 +-------------------------------------------------+
1490 | FIXED HEADER | VARIABLE HEADER | PTRS | NON-PRS |
1491 +-------------------------------------------------+
1493 /* Fill in the fixed header */
1494 for (i = 0; i < _HS; i++)
1495 ((StgPtr)graph)[i] = (StgWord)*bufptr++;
1497 if (ip->type == FETCH_ME)
1498 size = ptrs = nonptrs = vhs = 0;
1500 /* Fill in the packed variable header */
1501 for (i = 0; i < vhs; i++)
1502 ((StgPtr)graph)[_HS + i] = (StgWord)*bufptr++;
1504 /* Pointers will be filled in later */
1506 /* Fill in the packed non-pointers */
1507 for (i = 0; i < nonptrs; i++)
1508 ((StgPtr)graph)[_HS + i + vhs + ptrs] = (StgWord)*bufptr++;
1510 /* Indirections are never packed */
1511 // ASSERT(INFO_PTR(graph) != (W_) Ind_info_TO_USE);
1513 /* Add to queue for processing */
1514 QueueClosure(graph);
1517 * Common up the new closure with any existing closure having the same
1521 if ((existing = GALAlookup(&ga)) == NULL) {
1523 /* Just keep the new object */
1525 belch("_* Unpacking new GA ((%x, %d, %x))",
1526 ga.payload.gc.gtid, ga.payload.gc.slot, ga.weight));
1529 newGA = setRemoteGA(graph, &ga, rtsTrue);
1530 if (ip->type == FETCH_ME)
1531 // FETCHME_GA(closure) = newGA;
1532 ((StgFetchMe *)closure)->ga = newGA;
1534 /* Two closures, one global name. Someone loses */
1535 oldip = get_itbl(existing);
1537 if ((oldip->type == FETCH_ME ||
1538 // ToDo: don't pack a GA for these in the first place
1539 oldip->type == CONSTR ||
1540 oldip->type == CONSTR_1_0 ||
1541 oldip->type == CONSTR_0_1 ||
1542 oldip->type == CONSTR_2_0 ||
1543 oldip->type == CONSTR_1_1 ||
1544 oldip->type == CONSTR_0_2 ||
1545 IS_BLACK_HOLE(existing)) &&
1546 ip->type != FETCH_ME) {
1548 /* What we had wasn't worth keeping */
1550 CommonUp(existing, graph);
1555 * Either we already had something worthwhile by this name or
1556 * the new thing is just another FetchMe. However, the thing we
1557 * just unpacked has to be left as-is, or the child unpacking
1558 * code will fail. Remember that the way pointer words are
1559 * filled in depends on the info pointers of the parents being
1560 * the same as when they were packed.
1563 belch("_* Unpacking old GA ((%x, %d, %x)), keeping %#lx",
1564 ga.payload.gc.gtid, ga.payload.gc.slot, ga.weight,
1569 ty = get_itbl(closure)->type;
1576 CommonUp(closure, graph);
1579 /* Pool the total weight in the stored ga */
1580 (void) addWeight(&ga);
1583 /* Sort out the global address mapping */
1584 if (hasGA || // (ip_THUNK(ip) && !ip_UNPOINTED(ip)) ||
1585 (ip_MUTABLE(ip) && ip->type != FETCH_ME)) {
1586 /* Make up new GAs for single-copy closures */
1587 globalAddr *newGA = makeGlobal(closure, rtsTrue);
1589 // keep this assertion!
1590 // ASSERT(closure == graph);
1592 /* Create an old GA to new GA mapping */
1594 splitWeight(gaga, newGA);
1595 ASSERT(gaga->weight == 1L << (BITS_IN(unsigned) - 1));
1598 graph += _HS + (size < MIN_UPD_SIZE ? MIN_UPD_SIZE : size);
1602 * Set parent pointer to point to chosen closure. If we're at the top of
1603 * the graph (our parent is NULL), then we want to arrange to return the
1604 * chosen closure to our caller (possibly in place of the allocated graph
1608 graphroot = closure;
1610 ((StgPtr)parent)[_HS + pvhs + pptr] = (StgWord) closure;
1612 /* Save closure pointer for resolving offsets */
1613 *slotptr = (StgWord) closure;
1615 /* Locate next parent pointer */
1617 while (pptr + 1 > pptrs) {
1618 parent = DeQueueClosure();
1623 (void) get_closure_info(parent, &size, &pptrs, &nonptrs,
1628 } while (parent != NULL);
1630 //ASSERT(bufsize == 0 || graph - 1 <= SAVE_Hp);
1632 *gamap = PendingGABuffer;
1633 *nGAs = (gaga - PendingGABuffer) / 2;
1635 /* ToDo: are we *certain* graphroot has been set??? WDP 95/07 */
1636 ASSERT(graphroot!=NULL);
1641 //@node GranSim Code, , Local Definitions, Unpacking routines
1642 //@subsubsection GranSim Code
1645 For GrAnSim: No actual unpacking should be necessary. We just
1646 have to walk over the graph and set the bitmasks appropriately.
1647 Since we use RBHs similarly to GUM but without an ACK message/event
1648 we have to revert the RBH from within the UnpackGraph routine (good luck!)
1654 CommonUp(StgClosure *src, StgClosure *dst)
1656 barf("CommonUp: should never be entered in a GranSim setup");
1661 rtsPackBuffer* buffer;
1663 nat size, ptrs, nonptrs, vhs,
1665 StgClosure *closure, *graphroot, *graph;
1667 StgWord bufsize, unpackedsize,
1668 pptr = 0, pptrs = 0, pvhs;
1670 char str[240], str1[80];
1674 graphroot = buffer->buffer[0];
1678 /* Unpack the header */
1679 unpackedsize = buffer->unpacked_size;
1680 bufsize = buffer->size;
1683 belch("<<< Unpacking <<%d>> (buffer @ %p):\n (root @ %p, PE %d,size=%d), demanded by TSO %d (%p)[PE %d]",
1684 buffer->id, buffer, graphroot, where_is(graphroot),
1685 bufsize, tso->id, tso,
1686 where_is((StgClosure *)tso)));
1689 closure = buffer->buffer[bufptr++]; /* that's all we need for GrAnSim -- HWL */
1691 /* Actually only ip is needed; rest is useful for TESTING -- HWL */
1692 ip = get_closure_info(closure,
1693 &size, &ptrs, &nonptrs, &vhs, str);
1696 sprintf(str, "** (%p): Changing bitmask[%s]: 0x%x ",
1697 closure, (closure_HNF(closure) ? "NF" : "__"),
1700 if (get_itbl(closure)->type == RBH) {
1701 /* if it's an RBH, we have to revert it into a normal closure, thereby
1702 awakening the blocking queue; not that this is code currently not
1703 needed in GUM, but it should be added with the new features in
1704 GdH (and the implementation of an NACK message)
1706 // closure->header.gran.procs = PE_NUMBER(CurrentProc);
1707 SET_GRAN_HDR(closure, PE_NUMBER(CurrentProc)); /* Move node */
1710 strcat(str, " (converting RBH) "));
1712 convertFromRBH(closure); /* In GUM that's done by convertToFetchMe */
1715 belch(":: closure %p (%s) is a RBH; after reverting: IP=%p",
1716 closure, info_type(closure), get_itbl(closure)));
1717 } else if (IS_BLACK_HOLE(closure)) {
1719 belch(":: closure %p (%s) is a BH; copying node to %d",
1720 closure, info_type(closure), CurrentProc));
1721 closure->header.gran.procs |= PE_NUMBER(CurrentProc); /* Copy node */
1722 } else if ( (closure->header.gran.procs & PE_NUMBER(CurrentProc)) == 0 ) {
1723 if (closure_HNF(closure)) {
1725 belch(":: closure %p (%s) is a HNF; copying node to %d",
1726 closure, info_type(closure), CurrentProc));
1727 closure->header.gran.procs |= PE_NUMBER(CurrentProc); /* Copy node */
1730 belch(":: closure %p (%s) is no (R)BH or HNF; moving node to %d",
1731 closure, info_type(closure), CurrentProc));
1732 closure->header.gran.procs = PE_NUMBER(CurrentProc); /* Move node */
1737 sprintf(str1, "0x%x", PROCS(closure)); strcat(str, str1));
1738 IF_GRAN_DEBUG(pack, belch(str));
1740 } while (bufptr<buffer->size) ; /* (parent != NULL); */
1742 /* In GrAnSim we allocate pack buffers dynamically! -- HWL */
1743 free(buffer->buffer);
1747 belch("PrintGraph of %p is:", graphroot); PrintGraph(graphroot,0));
1753 //@node Aux fcts for packing, Printing Packet Contents, Unpacking routines, Graph packing
1754 //@subsection Aux fcts for packing
1759 //* Types of Global Addresses::
1763 //@node Offset table, Packet size, Aux fcts for packing, Aux fcts for packing
1764 //@subsubsection Offset table
1767 DonePacking is called when we've finished packing. It releases memory
1770 //@cindex DonePacking
1777 freeHashTable(offsetTable, NULL);
1782 AmPacking records that the closure is being packed. Note the abuse of
1783 the data field in the hash table -- this saves calling @malloc@! */
1789 StgClosure *closure;
1791 /* IF_PAR_DEBUG(pack, */
1792 /* fprintf(stderr, "** AmPacking %p (%s)(IP %p) at %u\n", */
1793 /* closure, info_type(closure), get_itbl(closure), pack_locn)); */
1795 insertHashTable(offsetTable, (StgWord) closure, (void *) (StgWord) pack_locn);
1799 OffsetFor returns an offset for a closure which is already being packed. */
1805 StgClosure *closure;
1807 return (int) (StgWord) lookupHashTable(offsetTable, (StgWord) closure);
1811 NotYetPacking determines whether the closure's already being packed.
1812 Offsets $<$ @PACK_HDR_SIZE@ (e.g. 0) mean no. */
1814 //@cindex NotYetPacking
1817 NotYetPacking(offset)
1820 return(offset == 0); // ToDo: what if root is found again?? FIX
1832 NotYetPacking searches through the whole pack buffer for closure. */
1835 NotYetPacking(closure)
1836 StgClosure *closure;
1838 rtsBool found = rtsFalse;
1840 for (i=0; (i<pack_locn) && !found; i++)
1841 found = Bonzo->buffer[i]==closure;
1847 //@node Packet size, Types of Global Addresses, Offset table, Aux fcts for packing
1848 //@subsubsection Packet size
1851 RoomToPack determines whether there's room to pack the closure into
1852 the pack buffer based on
1854 o how full the buffer is already,
1855 o the closures' size and number of pointers (which must be packed as GAs),
1856 o the size and number of pointers held by any primitive arrays that it
1859 It has a *side-effect* (naughty, naughty) in assigning RoomInBuffer
1863 //@cindex RoomToPack
1865 RoomToPack(size, ptrs)
1870 (pack_locn + reservedPAsize + size +
1871 ((clq_size - clq_pos) + ptrs) * PACK_FETCHME_SIZE >= RTS_PACK_BUFFER_SIZE))
1874 fprintf(stderr, "Buffer full\n"));
1876 RoomInBuffer = rtsFalse;
1880 (unpacked_size + reservedPAsize + size +
1881 ((clq_size - clq_pos) + ptrs) * PACK_FETCHME_SIZE >= RTS_PACK_BUFFER_SIZE))
1883 IF_GRAN_DEBUG(packBuffer,
1884 fprintf(stderr, "Buffer full\n"));
1885 RoomInBuffer = rtsFalse;
1888 return (RoomInBuffer);
1891 //@node Types of Global Addresses, Closure Info, Packet size, Aux fcts for packing
1892 //@subsubsection Types of Global Addresses
1895 Types of Global Addresses
1897 These routines determine whether a GA is one of a number of special types
1907 return (ga->weight == 1 && ga->payload.gc.gtid == 0);
1915 return (ga->weight == 0);
1919 //@node Closure Info, , Types of Global Addresses, Aux fcts for packing
1920 //@subsubsection Closure Info
1925 @get_closure_info@ determines the size, number of pointers etc. for this
1926 type of closure -- see @SMInfoTables.lh@ for the legal info. types etc.
1928 [Can someone please keep this function up to date. I keep needing it
1929 (or something similar) for interpretive code, and it keeps
1930 bit-rotting. {\em It really belongs somewhere else too}. KH @@ 17/2/95] */
1934 // {Parallel.h}Daq ngoqvam vIroQpu'
1936 # if defined(GRAN) || defined(PAR)
1937 /* extracting specific info out of closure; currently only used in GRAN -- HWL */
1938 //@cindex get_closure_info
1940 get_closure_info(node, size, ptrs, nonptrs, vhs, info_hdr_ty)
1942 nat *size, *ptrs, *nonptrs, *vhs;
1947 info = get_itbl(node);
1948 /* the switch shouldn't be necessary, really; just use default case */
1949 switch (info->type) {
1954 *size = sizeW_fromITBL(info);
1955 *ptrs = (nat) 1; // (info->layout.payload.ptrs);
1956 *nonptrs = (nat) 0; // (info->layout.payload.nptrs);
1957 *vhs = (nat) 0; // unknown
1958 info_hdr_type(node, info_hdr_ty);
1964 *size = sizeW_fromITBL(info);
1965 *ptrs = (nat) 0; // (info->layout.payload.ptrs);
1966 *nonptrs = (nat) 1; // (info->layout.payload.nptrs);
1967 *vhs = (nat) 0; // unknown
1968 info_hdr_type(node, info_hdr_ty);
1974 *size = sizeW_fromITBL(info);
1975 *ptrs = (nat) 2; // (info->layout.payload.ptrs);
1976 *nonptrs = (nat) 0; // (info->layout.payload.nptrs);
1977 *vhs = (nat) 0; // unknown
1978 info_hdr_type(node, info_hdr_ty);
1984 *size = sizeW_fromITBL(info);
1985 *ptrs = (nat) 1; // (info->layout.payload.ptrs);
1986 *nonptrs = (nat) 1; // (info->layout.payload.nptrs);
1987 *vhs = (nat) 0; // unknown
1988 info_hdr_type(node, info_hdr_ty);
1994 *size = sizeW_fromITBL(info);
1995 *ptrs = (nat) 0; // (info->layout.payload.ptrs);
1996 *nonptrs = (nat) 2; // (info->layout.payload.nptrs);
1997 *vhs = (nat) 0; // unknown
1998 info_hdr_type(node, info_hdr_ty);
2003 StgInfoTable *rip = REVERT_INFOPTR(info); // closure to revert to
2004 *size = sizeW_fromITBL(rip);
2005 *ptrs = (nat) (rip->layout.payload.ptrs);
2006 *nonptrs = (nat) (rip->layout.payload.nptrs);
2007 *vhs = (nat) 0; // unknown
2008 info_hdr_type(node, info_hdr_ty);
2009 return rip; // NB: we return the reverted info ptr for a RBH!!!!!!
2013 *size = sizeW_fromITBL(info);
2014 *ptrs = (nat) (info->layout.payload.ptrs);
2015 *nonptrs = (nat) (info->layout.payload.nptrs);
2016 *vhs = (nat) 0; // unknown
2017 info_hdr_type(node, info_hdr_ty);
2022 //@cindex IS_BLACK_HOLE
2024 IS_BLACK_HOLE(StgClosure* node)
2027 info = get_itbl(node);
2028 return ((info->type == BLACKHOLE || info->type == RBH) ? rtsTrue : rtsFalse);
2031 //@cindex IS_INDIRECTION
2033 IS_INDIRECTION(StgClosure* node)
2036 info = get_itbl(node);
2037 switch (info->type) {
2041 case IND_OLDGEN_PERM:
2043 /* relies on indirectee being at same place for all these closure types */
2044 return (((StgInd*)node) -> indirectee);
2052 IS_THUNK(StgClosure* node)
2055 info = get_itbl(node);
2056 return ((info->type == THUNK ||
2057 info->type == THUNK_STATIC ||
2058 info->type == THUNK_SELECTOR) ? rtsTrue : rtsFalse);
2069 get_closure_info(closure, size, ptrs, nonptrs, vhs, type)
2071 W_ *size, *ptrs, *nonptrs, *vhs;
2074 P_ ip = (P_) INFO_PTR(closure);
2076 if (closure==NULL) {
2077 fprintf(stderr, "Qagh {get_closure_info}Daq: NULL closure\n");
2078 *size = *ptrs = *nonptrs = *vhs = 0;
2079 strcpy(type,"ERROR in get_closure_info");
2081 } else if (closure==PrelBase_Z91Z93_closure) {
2082 /* fprintf(stderr, "Qagh {get_closure_info}Daq: PrelBase_Z91Z93_closure closure\n"); */
2083 *size = *ptrs = *nonptrs = *vhs = 0;
2084 strcpy(type,"PrelBase_Z91Z93_closure");
2088 ip = (P_) INFO_PTR(closure);
2090 switch (INFO_TYPE(ip)) {
2091 case INFO_SPEC_U_TYPE:
2092 case INFO_SPEC_S_TYPE:
2093 case INFO_SPEC_N_TYPE:
2094 *size = SPEC_CLOSURE_SIZE(closure);
2095 *ptrs = SPEC_CLOSURE_NoPTRS(closure);
2096 *nonptrs = SPEC_CLOSURE_NoNONPTRS(closure);
2097 *vhs = 0 /*SPEC_VHS*/;
2098 strcpy(type,"SPEC");
2101 case INFO_GEN_U_TYPE:
2102 case INFO_GEN_S_TYPE:
2103 case INFO_GEN_N_TYPE:
2104 *size = GEN_CLOSURE_SIZE(closure);
2105 *ptrs = GEN_CLOSURE_NoPTRS(closure);
2106 *nonptrs = GEN_CLOSURE_NoNONPTRS(closure);
2112 *size = DYN_CLOSURE_SIZE(closure);
2113 *ptrs = DYN_CLOSURE_NoPTRS(closure);
2114 *nonptrs = DYN_CLOSURE_NoNONPTRS(closure);
2119 case INFO_TUPLE_TYPE:
2120 *size = TUPLE_CLOSURE_SIZE(closure);
2121 *ptrs = TUPLE_CLOSURE_NoPTRS(closure);
2122 *nonptrs = TUPLE_CLOSURE_NoNONPTRS(closure);
2124 strcpy(type,"TUPLE");
2127 case INFO_DATA_TYPE:
2128 *size = DATA_CLOSURE_SIZE(closure);
2129 *ptrs = DATA_CLOSURE_NoPTRS(closure);
2130 *nonptrs = DATA_CLOSURE_NoNONPTRS(closure);
2132 strcpy(type,"DATA");
2135 case INFO_IMMUTUPLE_TYPE:
2136 case INFO_MUTUPLE_TYPE:
2137 *size = MUTUPLE_CLOSURE_SIZE(closure);
2138 *ptrs = MUTUPLE_CLOSURE_NoPTRS(closure);
2139 *nonptrs = MUTUPLE_CLOSURE_NoNONPTRS(closure);
2141 strcpy(type,"(IM)MUTUPLE");
2144 case INFO_STATIC_TYPE:
2145 *size = STATIC_CLOSURE_SIZE(closure);
2146 *ptrs = STATIC_CLOSURE_NoPTRS(closure);
2147 *nonptrs = STATIC_CLOSURE_NoNONPTRS(closure);
2149 strcpy(type,"STATIC");
2154 *size = IND_CLOSURE_SIZE(closure);
2155 *ptrs = IND_CLOSURE_NoPTRS(closure);
2156 *nonptrs = IND_CLOSURE_NoNONPTRS(closure);
2158 strcpy(type,"CAF|IND");
2161 case INFO_CONST_TYPE:
2162 *size = CONST_CLOSURE_SIZE(closure);
2163 *ptrs = CONST_CLOSURE_NoPTRS(closure);
2164 *nonptrs = CONST_CLOSURE_NoNONPTRS(closure);
2166 strcpy(type,"CONST");
2169 case INFO_SPEC_RBH_TYPE:
2170 *size = SPEC_RBH_CLOSURE_SIZE(closure);
2171 *ptrs = SPEC_RBH_CLOSURE_NoPTRS(closure);
2172 *nonptrs = SPEC_RBH_CLOSURE_NoNONPTRS(closure);
2174 *nonptrs -= (2 - *ptrs);
2178 *vhs = SPEC_RBH_VHS;
2179 strcpy(type,"SPEC_RBH");
2182 case INFO_GEN_RBH_TYPE:
2183 *size = GEN_RBH_CLOSURE_SIZE(closure);
2184 *ptrs = GEN_RBH_CLOSURE_NoPTRS(closure);
2185 *nonptrs = GEN_RBH_CLOSURE_NoNONPTRS(closure);
2187 *nonptrs -= (2 - *ptrs);
2192 strcpy(type,"GEN_RBH");
2195 case INFO_CHARLIKE_TYPE:
2196 *size = CHARLIKE_CLOSURE_SIZE(closure);
2197 *ptrs = CHARLIKE_CLOSURE_NoPTRS(closure);
2198 *nonptrs = CHARLIKE_CLOSURE_NoNONPTRS(closure);
2199 *vhs = CHARLIKE_VHS;
2200 strcpy(type,"CHARLIKE");
2203 case INFO_INTLIKE_TYPE:
2204 *size = INTLIKE_CLOSURE_SIZE(closure);
2205 *ptrs = INTLIKE_CLOSURE_NoPTRS(closure);
2206 *nonptrs = INTLIKE_CLOSURE_NoNONPTRS(closure);
2208 strcpy(type,"INTLIKE");
2212 case INFO_FETCHME_TYPE:
2213 *size = FETCHME_CLOSURE_SIZE(closure);
2214 *ptrs = FETCHME_CLOSURE_NoPTRS(closure);
2215 *nonptrs = FETCHME_CLOSURE_NoNONPTRS(closure);
2217 strcpy(type,"FETCHME");
2220 case INFO_FMBQ_TYPE:
2221 *size = FMBQ_CLOSURE_SIZE(closure);
2222 *ptrs = FMBQ_CLOSURE_NoPTRS(closure);
2223 *nonptrs = FMBQ_CLOSURE_NoNONPTRS(closure);
2225 strcpy(type,"FMBQ");
2230 *size = BQ_CLOSURE_SIZE(closure);
2231 *ptrs = BQ_CLOSURE_NoPTRS(closure);
2232 *nonptrs = BQ_CLOSURE_NoNONPTRS(closure);
2238 *size = BH_CLOSURE_SIZE(closure);
2239 *ptrs = BH_CLOSURE_NoPTRS(closure);
2240 *nonptrs = BH_CLOSURE_NoNONPTRS(closure);
2246 *size = 0; /* TSO_CLOSURE_SIZE(closure); */
2247 *ptrs = 0; /* TSO_CLOSURE_NoPTRS(closure); */
2248 *nonptrs = 0; /* TSO_CLOSURE_NoNONPTRS(closure); */
2253 case INFO_STKO_TYPE:
2258 strcpy(type,"STKO");
2262 fprintf(stderr, "get_closure_info: Unexpected closure type (%lu), closure %lx\n",
2263 INFO_TYPE(ip), (StgWord) closure);
2272 // Use allocate in Storage.c instead
2274 @AllocateHeap@ will bump the heap pointer by @size@ words if the space
2275 is available, but it will not perform garbage collection.
2276 ToDo: check whether we can use an existing STG allocation routine -- HWL
2280 //@cindex AllocateHeap
2287 /* Allocate a new closure */
2288 if (Hp + size > HpLim)
2291 newClosure = Hp + 1;
2300 //@cindex doGlobalGC
2304 fprintf(stderr,"Splat -- we just hit global GC!\n");
2305 stg_exit(EXIT_FAILURE);
2306 //fishing = rtsFalse;
2307 outstandingFishes--;
2312 //@node Printing Packet Contents, End of file, Aux fcts for packing, Graph packing
2313 //@subsection Printing Packet Contents
2315 Printing Packet Contents
2318 #if defined(DEBUG) || defined(GRAN_CHECK)
2320 //@cindex PrintPacket
2324 PrintPacket(packBuffer)
2325 rtsPackBuffer *packBuffer;
2327 StgClosure *parent, *graphroot, *closure_start;
2328 StgInfoTable *ip, *oldip;
2330 StgWord **buffer, **bufptr, **slotptr;
2333 nat pptr = 0, pptrs = 0, pvhs;
2334 nat unpack_locn = 0;
2335 nat gastart = unpack_locn;
2336 nat closurestart = unpack_locn;
2338 nat size, ptrs, nonptrs, vhs;
2341 /* NB: this whole routine is more or less a copy of UnpackGraph with all
2342 unpacking components replaced by printing fcts
2343 Long live higher-order fcts!
2345 initPackBuffer(); /* in case it isn't already init'd */
2346 graphroot = (StgClosure *)NULL;
2348 // gaga = PendingGABuffer;
2352 /* Unpack the header */
2353 bufsize = packBuffer->size;
2354 buffer = packBuffer->buffer;
2359 graph = allocate(bufsize);
2360 ASSERT(graph != NULL);
2364 fprintf(stderr, ".* Printing <<%d>> (buffer @ %p):\n",
2365 packBuffer->id, packBuffer);
2366 fprintf(stderr, ".* size: %d; unpacked_size: %d; tso: %p; buffer: %p\n",
2367 packBuffer->size, packBuffer->unpacked_size,
2368 packBuffer->tso, packBuffer->buffer);
2370 parent = (StgClosure *)NULL;
2373 /* This is where we will ultimately save the closure's address */
2376 /* First, unpack the next GA or PLC */
2377 ga.weight = (rtsWeight) *bufptr++;
2379 if (ga.weight > 0) {
2380 ga.payload.gc.gtid = (GlobalTaskId) *bufptr++;
2381 ga.payload.gc.slot = (int) *bufptr++;
2383 ga.payload.plc = (StgPtr) *bufptr++;
2385 /* Now unpack the closure body, if there is one */
2387 fprintf(stderr, ".* [%u]: PLC @ %p\n", gastart, ga.payload.plc);
2388 // closure = ga.payload.plc;
2389 } else if (isOffset(&ga)) {
2390 fprintf(stderr, ".* [%u]: OFFSET TO [%d]\n", gastart, ga.payload.gc.slot);
2391 // closure = (StgClosure *) buffer[ga.payload.gc.slot];
2393 /* Print normal closures */
2395 ASSERT(bufsize > 0);
2397 fprintf(stderr, ".* [%u]: ((%x, %d, %x)) ", gastart,
2398 ga.payload.gc.gtid, ga.payload.gc.slot, ga.weight);
2400 closure_start = bufptr;
2401 ip = get_closure_info(bufptr, &size, &ptrs, &nonptrs, &vhs, str);
2404 Remember, the generic closure layout is as follows:
2405 +-------------------------------------------------+
2406 | FIXED HEADER | VARIABLE HEADER | PTRS | NON-PRS |
2407 +-------------------------------------------------+
2409 /* Print fixed header */
2410 fprintf(stderr, "FH [");
2411 for (i = 0; i < _HS; i++)
2412 fprintf(stderr, " %p", *bufptr++);
2414 if (ip->type == FETCH_ME)
2415 size = ptrs = nonptrs = vhs = 0;
2417 /* Print variable header */
2418 fprintf(stderr, "] VH [");
2419 for (i = 0; i < vhs; i++)
2420 fprintf(stderr, " %p", *bufptr++);
2422 fprintf(stderr, "] %d PTRS [", ptrs);
2424 /* Pointers will be filled in later */
2426 fprintf(stderr, " ] %d NON-PTRS [", nonptrs);
2427 /* Print non-pointers */
2428 for (i = 0; i < nonptrs; i++)
2429 fprintf(stderr, " %p", *bufptr++);
2431 fprintf(stderr, "] (%s)\n", str);
2433 /* Indirections are never packed */
2434 // ASSERT(INFO_PTR(graph) != (W_) Ind_info_TO_USE);
2436 /* Add to queue for processing
2437 When just printing the packet we do not have an unpacked closure
2438 in hand, so we feed it the packet entry;
2439 again, this assumes that at least the fixed header of the closure
2440 has the same layout in the packet; also we may not overwrite entries
2441 in the packet (done in Unpack), but for printing that's a bad idea
2443 QueueClosure((StgClosure *)closure_start);
2445 /* No Common up needed for printing */
2447 /* No Sort out the global address mapping for printing */
2449 } /* normal closure case */
2451 /* Locate next parent pointer */
2453 while (pptr + 1 > pptrs) {
2454 parent = DeQueueClosure();
2459 (void) get_closure_info(parent, &size, &pptrs, &nonptrs,
2464 } while (parent != NULL);
2465 fprintf(stderr, ".* --- End packet <<%d>> ---\n", packBuffer->id);
2470 rtsPackBuffer *buffer;
2472 // extern char *info_hdr_type(P_ infoptr); /* defined in Threads.lc */
2473 // extern char *display_info_type(P_ infoptr); /* defined in Threads.lc */
2476 nat size, ptrs, nonptrs, vhs;
2477 char info_hdr_ty[80];
2478 char str1[80], str2[80], junk_str[80];
2480 /* globalAddr ga; */
2482 nat bufsize, unpacked_size ;
2484 nat pptr = 0, pptrs = 0, pvhs;
2486 nat unpack_locn = 0;
2487 nat gastart = unpack_locn;
2488 nat closurestart = unpack_locn;
2491 StgClosure *closure, *p;
2495 fprintf(stderr, "*** Printing <<%d>> (buffer @ %p):\n", buffer->id, buffer);
2496 fprintf(stderr, " size: %d; unpacked_size: %d; tso: %d (%p); buffer: %p\n",
2497 buffer->size, buffer->unpacked_size, buffer->tso, buffer->buffer);
2498 fputs(" contents: ", stderr);
2499 for (unpack_locn=0; unpack_locn<buffer->size; unpack_locn++) {
2500 closure = buffer->buffer[unpack_locn];
2501 fprintf(stderr, ", %p (%s)",
2502 closure, info_type(closure));
2504 fputc('\n', stderr);
2507 /* traverse all elements of the graph; omitted for now, but might be usefule */
2512 /* Unpack the header */
2513 unpacked_size = buffer->unpacked_size;
2514 bufsize = buffer->size;
2516 fprintf(stderr, "Packet %p, size %u (unpacked size is %u); demanded by TSO %d (%p)[PE %d]\n--- Begin ---\n",
2517 buffer, bufsize, unpacked_size,
2518 tso->id, tso, where_is((StgClosure*)tso));
2521 closurestart = unpack_locn;
2522 closure = buffer->buffer[unpack_locn++];
2524 fprintf(stderr, "[%u]: (%p) ", closurestart, closure);
2526 info = get_closure_info(closure, &size, &ptrs, &nonptrs, &vhs, str1);
2528 fprintf(stderr, "(%s|%s) ", str1, str2);
2530 if (info->type == FETCH_ME || info->type == FETCH_ME_BQ ||
2531 IS_BLACK_HOLE(closure))
2532 size = ptrs = nonptrs = vhs = 0;
2534 if (closure_THUNK(closure)) {
2535 if (closure_UNPOINTED(closure))
2536 fputs("UNPOINTED ", stderr);
2538 fputs("POINTED ", stderr);
2540 if (IS_BLACK_HOLE(closure)) {
2541 fputs("BLACK HOLE\n", stderr);
2544 fprintf(stderr, "FH [");
2545 for (i = 0, p = (StgClosure*)&(closure->header); i < _HS; i++, p++)
2546 fprintf(stderr, " %p", *p);
2550 fprintf(stderr, "] VH [%p", closure->payload[_HS]);
2552 for (i = 1; i < vhs; i++)
2553 fprintf(stderr, " %p", closure->payload[_HS+i]);
2556 fprintf(stderr, "] PTRS %u", ptrs);
2560 fprintf(stderr, " NPTRS [%p", closure->payload[_HS+vhs]);
2562 for (i = 1; i < nonptrs; i++)
2563 fprintf(stderr, " %p", closure->payload[_HS+vhs+i]);
2569 } while (unpack_locn<bufsize) ; /* (parent != NULL); */
2571 fprintf(stderr, "--- End ---\n\n");
2575 #endif /* DEBUG || GRAN_CHECK */
2577 #endif /* PAR || GRAN -- whole file */
2579 //@node End of file, , Printing Packet Contents, Graph packing
2580 //@subsection End of file
2582 //* AllocClosureQueue:: @cindex\s-+AllocClosureQueue
2583 //* AllocateHeap:: @cindex\s-+AllocateHeap
2584 //* AmPacking:: @cindex\s-+AmPacking
2585 //* CommonUp:: @cindex\s-+CommonUp
2586 //* DeQueueClosure:: @cindex\s-+DeQueueClosure
2587 //* DonePacking:: @cindex\s-+DonePacking
2588 //* IS_BLACK_HOLE:: @cindex\s-+IS_BLACK_HOLE
2589 //* IS_INDIRECTION:: @cindex\s-+IS_INDIRECTION
2590 //* InitClosureQueue:: @cindex\s-+InitClosureQueue
2591 //* InitPendingGABuffer:: @cindex\s-+InitPendingGABuffer
2592 //* NotYetPacking:: @cindex\s-+NotYetPacking
2593 //* OffsetFor:: @cindex\s-+OffsetFor
2594 //* Pack:: @cindex\s-+Pack
2595 //* PackClosure:: @cindex\s-+PackClosure
2596 //* PackNearbyGraph:: @cindex\s-+PackNearbyGraph
2597 //* PackOneNode:: @cindex\s-+PackOneNode
2598 //* PackPLC:: @cindex\s-+PackPLC
2599 //* PackStkO:: @cindex\s-+PackStkO
2600 //* PackTSO:: @cindex\s-+PackTSO
2601 //* PendingGABuffer:: @cindex\s-+PendingGABuffer
2602 //* PrintPacket:: @cindex\s-+PrintPacket
2603 //* QueueClosure:: @cindex\s-+QueueClosure
2604 //* QueueEmpty:: @cindex\s-+QueueEmpty
2605 //* RoomToPack:: @cindex\s-+RoomToPack
2606 //* UnpackGraph:: @cindex\s-+UnpackGraph
2607 //* doGlobalGC:: @cindex\s-+doGlobalGC
2608 //* get_closure_info:: @cindex\s-+get_closure_info
2609 //* get_closure_info:: @cindex\s-+get_closure_info
2610 //* initPackBuffer:: @cindex\s-+initPackBuffer
2611 //* isFixed:: @cindex\s-+isFixed
2612 //* isOffset:: @cindex\s-+isOffset
2613 //* offsetTable:: @cindex\s-+offsetTable