diff options
author | Ian Lynagh <ian@well-typed.com> | 2013-03-17 13:56:27 +0000 |
---|---|---|
committer | Ian Lynagh <ian@well-typed.com> | 2013-03-17 13:56:27 +0000 |
commit | cf403b50900648063d99afa160d2091a7d6f58c1 (patch) | |
tree | a8608f1b7ebc1e91d7f73914fa77ba7fec51e67f /rts/parallel | |
parent | 0374cade3d2c08f78f33e1e4c0df1c6340cdea7d (diff) | |
download | haskell-cf403b50900648063d99afa160d2091a7d6f58c1.tar.gz |
Remove some directories that used to be used by GUM
This hasn't been used for some time
Diffstat (limited to 'rts/parallel')
-rw-r--r-- | rts/parallel/0Hash.c | 320 | ||||
-rw-r--r-- | rts/parallel/0Parallel.h | 414 | ||||
-rw-r--r-- | rts/parallel/0Unpack.c | 440 | ||||
-rw-r--r-- | rts/parallel/Dist.c | 117 | ||||
-rw-r--r-- | rts/parallel/Dist.h | 20 | ||||
-rw-r--r-- | rts/parallel/FetchMe.h | 24 | ||||
-rw-r--r-- | rts/parallel/FetchMe.hc | 180 | ||||
-rw-r--r-- | rts/parallel/Global.c | 1090 | ||||
-rw-r--r-- | rts/parallel/GranSim.c | 3015 | ||||
-rw-r--r-- | rts/parallel/GranSimRts.h | 268 | ||||
-rw-r--r-- | rts/parallel/HLC.h | 63 | ||||
-rw-r--r-- | rts/parallel/HLComms.c | 1810 | ||||
-rw-r--r-- | rts/parallel/LLC.h | 130 | ||||
-rw-r--r-- | rts/parallel/LLComms.c | 489 | ||||
-rw-r--r-- | rts/parallel/PEOpCodes.h | 58 | ||||
-rw-r--r-- | rts/parallel/Pack.c | 4293 | ||||
-rw-r--r-- | rts/parallel/ParInit.c | 322 | ||||
-rw-r--r-- | rts/parallel/ParInit.h | 19 | ||||
-rw-r--r-- | rts/parallel/ParTicky.c | 450 | ||||
-rw-r--r-- | rts/parallel/ParTicky.h | 60 | ||||
-rw-r--r-- | rts/parallel/ParTypes.h | 38 | ||||
-rw-r--r-- | rts/parallel/Parallel.c | 1140 | ||||
-rw-r--r-- | rts/parallel/ParallelDebug.c | 1955 | ||||
-rw-r--r-- | rts/parallel/ParallelDebug.h | 79 | ||||
-rw-r--r-- | rts/parallel/ParallelRts.h | 253 | ||||
-rw-r--r-- | rts/parallel/RBH.c | 337 | ||||
-rw-r--r-- | rts/parallel/SysMan.c | 650 |
27 files changed, 0 insertions, 18034 deletions
diff --git a/rts/parallel/0Hash.c b/rts/parallel/0Hash.c deleted file mode 100644 index a471e30a66..0000000000 --- a/rts/parallel/0Hash.c +++ /dev/null @@ -1,320 +0,0 @@ -/*----------------------------------------------------------------------------- - * - * (c) The AQUA Project, Glasgow University, 1995-1998 - * (c) The GHC Team, 1999 - * - * Dynamically expanding linear hash tables, as described in - * Per-\AAke Larson, ``Dynamic Hash Tables,'' CACM 31(4), April 1988, - * pp. 446 -- 457. - * -------------------------------------------------------------------------- */ - -/* - Replaced with ghc/rts/Hash.c in the new RTS -*/ - -#if 0 - -#include "Rts.h" -#include "Hash.h" -#include "RtsUtils.h" - -#define HSEGSIZE 1024 /* Size of a single hash table segment */ - /* Also the minimum size of a hash table */ -#define HDIRSIZE 1024 /* Size of the segment directory */ - /* Maximum hash table size is HSEGSIZE * HDIRSIZE */ -#define HLOAD 5 /* Maximum average load of a single hash bucket */ - -#define HCHUNK (1024 * sizeof(W_) / sizeof(HashList)) - /* Number of HashList cells to allocate in one go */ - - -/* Linked list of (key, data) pairs for separate chaining */ -struct hashlist { - StgWord key; - void *data; - struct hashlist *next; /* Next cell in bucket chain (same hash value) */ -}; - -typedef struct hashlist HashList; - -struct hashtable { - int split; /* Next bucket to split when expanding */ - int max; /* Max bucket of smaller table */ - int mask1; /* Mask for doing the mod of h_1 (smaller table) */ - int mask2; /* Mask for doing the mod of h_2 (larger table) */ - int kcount; /* Number of keys */ - int bcount; /* Number of buckets */ - HashList **dir[HDIRSIZE]; /* Directory of segments */ -}; - -/* ----------------------------------------------------------------------------- - * Hash first using the smaller table. If the bucket is less than the - * next bucket to be split, re-hash using the larger table. - * -------------------------------------------------------------------------- */ - -static int -hash(HashTable *table, W_ key) -{ - int bucket; - - /* Strip the boring zero bits */ - key /= sizeof(StgWord); - - /* Mod the size of the hash table (a power of 2) */ - bucket = key & table->mask1; - - if (bucket < table->split) { - /* Mod the size of the expanded hash table (also a power of 2) */ - bucket = key & table->mask2; - } - return bucket; -} - -/* ----------------------------------------------------------------------------- - * Allocate a new segment of the dynamically growing hash table. - * -------------------------------------------------------------------------- */ - -static void -allocSegment(HashTable *table, int segment) -{ - table->dir[segment] = stgMallocBytes(HSEGSIZE * sizeof(HashList *), - "allocSegment"); -} - - -/* ----------------------------------------------------------------------------- - * Expand the larger hash table by one bucket, and split one bucket - * from the smaller table into two parts. Only the bucket referenced - * by @table->split@ is affected by the expansion. - * -------------------------------------------------------------------------- */ - -static void -expand(HashTable *table) -{ - int oldsegment; - int oldindex; - int newbucket; - int newsegment; - int newindex; - HashList *hl; - HashList *next; - HashList *old, *new; - - if (table->split + table->max >= HDIRSIZE * HSEGSIZE) - /* Wow! That's big. Too big, so don't expand. */ - return; - - /* Calculate indices of bucket to split */ - oldsegment = table->split / HSEGSIZE; - oldindex = table->split % HSEGSIZE; - - newbucket = table->max + table->split; - - /* And the indices of the new bucket */ - newsegment = newbucket / HSEGSIZE; - newindex = newbucket % HSEGSIZE; - - if (newindex == 0) - allocSegment(table, newsegment); - - if (++table->split == table->max) { - table->split = 0; - table->max *= 2; - table->mask1 = table->mask2; - table->mask2 = table->mask2 << 1 | 1; - } - table->bcount++; - - /* Split the bucket, paying no attention to the original order */ - - old = new = NULL; - for (hl = table->dir[oldsegment][oldindex]; hl != NULL; hl = next) { - next = hl->next; - if (hash(table, hl->key) == newbucket) { - hl->next = new; - new = hl; - } else { - hl->next = old; - old = hl; - } - } - table->dir[oldsegment][oldindex] = old; - table->dir[newsegment][newindex] = new; - - return; -} - -void * -lookupHashTable(HashTable *table, StgWord key) -{ - int bucket; - int segment; - int index; - HashList *hl; - - bucket = hash(table, key); - segment = bucket / HSEGSIZE; - index = bucket % HSEGSIZE; - - for (hl = table->dir[segment][index]; hl != NULL; hl = hl->next) - if (hl->key == key) - return hl->data; - - /* It's not there */ - return NULL; -} - -/* ----------------------------------------------------------------------------- - * We allocate the hashlist cells in large chunks to cut down on malloc - * overhead. Although we keep a free list of hashlist cells, we make - * no effort to actually return the space to the malloc arena. - * -------------------------------------------------------------------------- */ - -static HashList *freeList = NULL; - -static HashList * -allocHashList(void) -{ - HashList *hl, *p; - - if ((hl = freeList) != NULL) { - freeList = hl->next; - } else { - hl = stgMallocBytes(HCHUNK * sizeof(HashList), "allocHashList"); - - freeList = hl + 1; - for (p = freeList; p < hl + HCHUNK - 1; p++) - p->next = p + 1; - p->next = NULL; - } - return hl; -} - -static void -freeHashList(HashList *hl) -{ - hl->next = freeList; - freeList = hl; -} - -void -insertHashTable(HashTable *table, StgWord key, void *data) -{ - int bucket; - int segment; - int index; - HashList *hl; - - /* We want no duplicates */ - ASSERT(lookupHashTable(table, key) == NULL); - - /* When the average load gets too high, we expand the table */ - if (++table->kcount >= HLOAD * table->bcount) - expand(table); - - bucket = hash(table, key); - segment = bucket / HSEGSIZE; - index = bucket % HSEGSIZE; - - hl = allocHashList(); - - hl->key = key; - hl->data = data; - hl->next = table->dir[segment][index]; - table->dir[segment][index] = hl; - -} - -void * -removeHashTable(HashTable *table, StgWord key, void *data) -{ - int bucket; - int segment; - int index; - HashList *hl; - HashList *prev = NULL; - - bucket = hash(table, key); - segment = bucket / HSEGSIZE; - index = bucket % HSEGSIZE; - - for (hl = table->dir[segment][index]; hl != NULL; hl = hl->next) { - if (hl->key == key && (data == NULL || hl->data == data)) { - if (prev == NULL) - table->dir[segment][index] = hl->next; - else - prev->next = hl->next; - table->kcount--; - return hl->data; - } - prev = hl; - } - - /* It's not there */ - ASSERT(data == NULL); - return NULL; -} - -/* ----------------------------------------------------------------------------- - * When we free a hash table, we are also good enough to free the - * data part of each (key, data) pair, as long as our caller can tell - * us how to do it. - * -------------------------------------------------------------------------- */ - -void -freeHashTable(HashTable *table, void (*freeDataFun)(void *) ) -{ - long segment; - long index; - HashList *hl; - HashList *next; - - /* The last bucket with something in it is table->max + table->split - 1 */ - segment = (table->max + table->split - 1) / HSEGSIZE; - index = (table->max + table->split - 1) % HSEGSIZE; - - while (segment >= 0) { - while (index >= 0) { - for (hl = table->dir[segment][index]; hl != NULL; hl = next) { - next = hl->next; - if (freeDataFun != NULL) - (*freeDataFun)(hl->data); - freeHashList(hl); - } - index--; - } - free(table->dir[segment]); - segment--; - index = HSEGSIZE - 1; - } - free(table); -} - -/* ----------------------------------------------------------------------------- - * When we initialize a hash table, we set up the first segment as well, - * initializing all of the first segment's hash buckets to NULL. - * -------------------------------------------------------------------------- */ - -HashTable * -allocHashTable(void) -{ - HashTable *table; - HashList **hb; - - table = stgMallocBytes(sizeof(HashTable),"allocHashTable"); - - allocSegment(table, 0); - - for (hb = table->dir[0]; hb < table->dir[0] + HSEGSIZE; hb++) - *hb = NULL; - - table->split = 0; - table->max = HSEGSIZE; - table->mask1 = HSEGSIZE - 1; - table->mask2 = 2 * HSEGSIZE - 1; - table->kcount = 0; - table->bcount = HSEGSIZE; - - return table; -} -#endif diff --git a/rts/parallel/0Parallel.h b/rts/parallel/0Parallel.h deleted file mode 100644 index de84fca054..0000000000 --- a/rts/parallel/0Parallel.h +++ /dev/null @@ -1,414 +0,0 @@ -/* - Time-stamp: <Mon Oct 04 1999 14:50:28 Stardate: [-30]3692.88 hwloidl> - - Definitions for parallel machines. - -This section contains definitions applicable only to programs compiled -to run on a parallel machine, i.e. on GUM. Some of these definitions -are also used when simulating parallel execution, i.e. on GranSim. - */ - -/* - ToDo: Check the PAR specfic part of this file - Move stuff into Closures.h and ClosureMacros.h - Clean-up GRAN specific code - -- HWL - */ - -#ifndef PARALLEL_H -#define PARALLEL_H - -#if defined(PAR) || defined(GRAN) /* whole file */ - -#include "Rts.h" -#include "GranSim.h" -//#include "ClosureTypes.h" - -//@menu -//* Basic definitions:: -//* Externs and types:: -//* Dummy defs:: -//* Par specific fixed headers:: -//* Parallel only heap objects:: -//* Packing definitions:: -//* End of File:: -//@end menu -//*/ - -//@node Basic definitions, Externs and types -//@section Basic definitions - -/* SET_PAR_HDR and SET_STATIC_PAR_HDR now live in ClosureMacros.h */ - -/* Needed for dumping routines */ -#if defined(PAR) -# define TIME StgWord64 -# define CURRENT_TIME msTime() -# define TIME_ON_PROC(p) msTime() -# define CURRENT_PROC thisPE -# define BINARY_STATS RtsFlags.ParFlags.granSimStats_Binary -#elif defined(GRAN) -# define TIME rtsTime -# define CURRENT_TIME CurrentTime[CurrentProc] -# define TIME_ON_PROC(p) CurrentTime[p] -# define CURRENT_PROC CurrentProc -# define BINARY_STATS RtsFlags.GranFlags.granSimStats_Binary -#endif - -#if defined(PAR) -# define MAX_PES 256 /* Maximum number of processors */ - /* MAX_PES is enforced by SysMan, which does not - allow more than this many "processors". - This is important because PackGA [GlobAddr.lc] - **assumes** that a PE# can fit in 8+ bits. - */ -#endif - -//@node Externs and types, Dummy defs, Basic definitions -//@section Externs and types - -#if defined(PAR) -/* GUM: one spark queue on each PE, and each PE sees only its own spark queue */ -extern rtsSparkQ pending_sparks_hd; -extern rtsSparkQ pending_sparks_tl; -#elif defined(GRAN) -/* GranSim: a globally visible array of spark queues */ -extern rtsSparkQ pending_sparks_hds[]; -extern rtsSparkQ pending_sparks_tls[]; -#endif -extern unsigned int /* nat */ spark_queue_len(PEs proc); - -extern StgInt SparksAvail; /* How many sparks are available */ - -/* prototypes of spark routines */ -/* ToDo: check whether all have to be visible -- HWL */ -#if defined(GRAN) -rtsSpark *newSpark(StgClosure *node, StgInt name, StgInt gran_info, StgInt size_info, StgInt par_info, StgInt local); -void disposeSpark(rtsSpark *spark); -void disposeSparkQ(rtsSparkQ spark); -void add_to_spark_queue(rtsSpark *spark); -void delete_from_spark_queue (rtsSpark *spark); -#endif - -#define STATS_FILENAME_MAXLEN 128 - -/* Where to write the log file */ -//extern FILE *gr_file; -extern char gr_filename[STATS_FILENAME_MAXLEN]; - -#if defined(GRAN) -int init_gr_simulation(char *rts_argv[], int rts_argc, char *prog_argv[], int prog_argc); -void end_gr_simulation(void); -#endif - -#if defined(PAR) -extern I_ do_sp_profile; - -extern P_ PendingFetches; -extern GLOBAL_TASK_ID *PEs; - -extern rtsBool IAmMainThread, GlobalStopPending; -extern rtsBool fishing; -extern GLOBAL_TASK_ID SysManTask; -extern int seed; /*pseudo-random-number generator seed:*/ - /*Initialised in ParInit*/ -extern I_ threadId; /*Number of Threads that have existed on a PE*/ -extern GLOBAL_TASK_ID mytid; - -extern int nPEs; - -extern rtsBool InGlobalGC; /* Are we in the midst of performing global GC */ - -extern HashTable *pGAtoGALAtable; -extern HashTable *LAtoGALAtable; -extern GALA *freeIndirections; -extern GALA *liveIndirections; -extern GALA *freeGALAList; -extern GALA *liveRemoteGAs; -extern int thisPE; - -void RunParallelSystem (StgPtr program_closure); -void initParallelSystem(); -void SynchroniseSystem(); - -void registerTask (GLOBAL_TASK_ID gtid); -globalAddr *LAGAlookup (P_ addr); -P_ GALAlookup (globalAddr *ga); -globalAddr *MakeGlobal (P_ addr, rtsBool preferred); -globalAddr *setRemoteGA (P_ addr, globalAddr *ga, rtsBool preferred); -void splitWeight (globalAddr *to, globalAddr *from); -globalAddr *addWeight (globalAddr *ga); -void initGAtables(); -W_ taskIDtoPE (GLOBAL_TASK_ID gtid); -void RebuildLAGAtable(); - -void *lookupHashTable (HashTable *table, StgWord key); -void insertHashTable (HashTable *table, StgWord key, void *data); -void freeHashTable (HashTable *table, void (*freeDataFun) ((void *data))); -HashTable *allocHashTable(); -void *removeHashTable (HashTable *table, StgWord key, void *data); -#endif /* PAR */ - -/* Interface for dumping routines (i.e. writing to log file) */ -void DumpGranEvent(GranEventType name, StgTSO *tso); -void DumpRawGranEvent(PEs proc, PEs p, GranEventType name, - StgTSO *tso, StgClosure *node, StgInt sparkname, StgInt len); -//void DumpEndEvent(PEs proc, StgTSO *tso, rtsBool mandatory_thread); - -//@node Dummy defs, Par specific fixed headers, Externs and types -//@section Dummy defs - -/* -Get this out of the way. These are all null definitions. -*/ - - -//# define GA_HDR_SIZE 0 -//# define GA(closure) /*nothing */ - -//# define SET_GA(closure,ga) /* nothing */ -//# define SET_STATIC_GA(closure) /* nothing */ -//# define SET_GRAN_HDR(closure,pe) /* nothing */ -//# define SET_STATIC_PROCS(closure) /* nothing */ - -//# define SET_TASK_ACTIVITY(act) /* nothing */ - -#if defined(GRAN) - -# define GA_HDR_SIZE 1 - -# define PROCS_HDR_POSN PAR_HDR_POSN -# define PROCS_HDR_SIZE 1 - -/* Accessing components of the field */ -# define PROCS(closure) ((closure)->header.gran.procs) -/* SET_PROCS is now SET_GRAN_HEADER in ClosureMacros.h. */ -#endif - - -//@node Par specific fixed headers, Parallel only heap objects, Dummy defs -//@section Par specific fixed headers - -/* -Definitions relating to the entire parallel-only fixed-header field. - -On GUM, the global addresses for each local closure are stored in a separate -hash table, rather then with the closure in the heap. We call @getGA@ to -look up the global address associated with a local closure (0 is returned -for local closures that have no global address), and @setGA@ to store a new -global address for a local closure which did not previously have one. -*/ - -#if defined(PAR) - -# define GA_HDR_SIZE 0 - -# define GA(closure) getGA(closure) - -# define SET_GA(closure, ga) setGA(closure,ga) -# define SET_STATIC_GA(closure) -# define SET_GRAN_HDR(closure,pe) -# define SET_STATIC_PROCS(closure) - -# define MAX_GA_WEIGHT 0 /* Treat as 2^n */ - -W_ PackGA ((W_, int)); - /* There was a PACK_GA macro here; but we turned it into the PackGA - routine [GlobAddr.lc] (because it needs to do quite a bit of - paranoia checking. Phil & Will (95/08) - */ - -/* At the moment, there is no activity profiling for GUM. This may change. */ -# define SET_TASK_ACTIVITY(act) /* nothing */ -#endif - -//@node Parallel only heap objects, Packing definitions, Par specific fixed headers -//@section Parallel only heap objects - -// NB: The following definitons are BOTH for GUM and GrAnSim -- HWL - -/* All in Closures.h and CLosureMacros.h */ - -//@node Packing definitions, End of File, Parallel only heap objects -//@section Packing definitions - -//@menu -//* GUM:: -//* GranSim:: -//@end menu -//*/ - -//@node GUM, GranSim, Packing definitions, Packing definitions -//@subsection GUM - -#if defined(PAR) -/* -Symbolic constants for the packing code. - -This constant defines how many words of data we can pack into a single -packet in the parallel (GUM) system. -*/ - -//@menu -//* Externs:: -//* Prototypes:: -//* Macros:: -//@end menu -//*/ - -//@node Externs, Prototypes, GUM, GUM -//@subsubsection Externs - -extern W_ *PackBuffer; /* size: can be set via option */ -extern long *buffer; /* HWL_ */ -extern W_ *freeBuffer; /* HWL_ */ -extern W_ *packBuffer; /* HWL_ */ - -extern void InitPackBuffer(STG_NO_ARGS); -extern void InitMoreBuffers(STG_NO_ARGS); -extern void InitPendingGABuffer(W_ size); -extern void AllocClosureQueue(W_ size); - -//@node Prototypes, Macros, Externs, GUM -//@subsubsection Prototypes - -void InitPackBuffer(); -P_ PackTSO (P_ tso, W_ *size); -P_ PackStkO (P_ stko, W_ *size); -P_ AllocateHeap (W_ size); /* Doesn't belong */ - -void InitClosureQueue (); -P_ DeQueueClosure(); -void QueueClosure (P_ closure); -rtsBool QueueEmpty(); -void PrintPacket (P_ buffer); - -P_ get_closure_info (P_ closure, W_ *size, W_ *ptrs, W_ *nonptrs, W_ *vhs, char *type); - -rtsBool isOffset (globalAddr *ga), - isFixed (globalAddr *ga); - -void doGlobalGC(); - -P_ PackNearbyGraph (P_ closure,W_ *size); -P_ UnpackGraph (W_ *buffer, globalAddr **gamap, W_ *nGAs); - - -//@node Macros, , Prototypes, GUM -//@subsubsection Macros - -# define PACK_HEAP_REQUIRED \ - ((RtsFlags.ParFlags.packBufferSize - PACK_HDR_SIZE) / (PACK_GA_SIZE + _FHS) * (SPEC_HS + 2)) - -# define MAX_GAS (RtsFlags.ParFlags.packBufferSize / PACK_GA_SIZE) - - -# define PACK_GA_SIZE 3 /* Size of a packed GA in words */ - /* Size of a packed fetch-me in words */ -# define PACK_FETCHME_SIZE (PACK_GA_SIZE + FIXED_HS) - -# define PACK_HDR_SIZE 1 /* Words of header in a packet */ - -# define PACK_PLC_SIZE 2 /* Size of a packed PLC in words */ - -#endif /* PAR */ - -//@node GranSim, , GUM, Packing definitions -//@subsection GranSim - -#if defined(GRAN) -/* ToDo: Check which of the PAR routines are needed in GranSim -- HWL */ - -//@menu -//* Types:: -//* Prototypes:: -//* Macros:: -//@end menu -//*/ - -//@node Types, Prototypes, GranSim, GranSim -//@subsubsection Types - -typedef struct rtsPackBuffer_ { - StgInt /* nat */ size; - StgInt /* nat */ unpacked_size; - StgTSO *tso; - StgClosure **buffer; -} rtsPackBuffer; - -//@node Prototypes, Macros, Types, GranSim -//@subsubsection Prototypes - - -/* main packing functions */ -/* -rtsPackBuffer *PackNearbyGraph(StgClosure* closure, StgTSO* tso, nat *packbuffersize); -rtsPackBuffer *PackOneNode(StgClosure* closure, StgTSO* tso, nat *packbuffersize); -void PrintPacket(rtsPackBuffer *buffer); -StgClosure *UnpackGraph(rtsPackBuffer* buffer); -*/ -/* important auxiliary functions */ - -//StgInfoTable *get_closure_info(StgClosure* node, nat *size, nat *ptrs, nat *nonptrs, nat *vhs, char *info_hdr_ty); -int IS_BLACK_HOLE(StgClosure* node); -StgClosure *IS_INDIRECTION(StgClosure* node); -int IS_THUNK(StgClosure* closure); -char *display_info_type(StgClosure* closure, char *str); - -/* -OLD CODE -- HWL -void InitPackBuffer(void); -P_ AllocateHeap (W_ size); -P_ PackNearbyGraph (P_ closure, P_ tso, W_ *packbuffersize); -P_ PackOneNode (P_ closure, P_ tso, W_ *packbuffersize); -P_ UnpackGraph (P_ buffer); - -void InitClosureQueue (void); -P_ DeQueueClosure(void); -void QueueClosure (P_ closure); -// rtsBool QueueEmpty(); -void PrintPacket (P_ buffer); -*/ - -// StgInfoTable *get_closure_info(StgClosure* node, unsigned int /* nat */ *size, unsigned int /* nat */ *ptrs, unsigned int /* nat */ *nonptrs, unsigned int /* nat */ *vhs, char *info_hdr_ty); -// int /* rtsBool */ IS_BLACK_HOLE(StgClosure* node) ; - -//@node Macros, , Prototypes, GranSim -//@subsubsection Macros - -/* These are needed in the packing code to get the size of the packet - right. The closures itself are never built in GrAnSim. */ -# define FETCHME_VHS IND_VHS -# define FETCHME_HS IND_HS - -# define FETCHME_GA_LOCN FETCHME_HS - -# define FETCHME_CLOSURE_SIZE(closure) IND_CLOSURE_SIZE(closure) -# define FETCHME_CLOSURE_NoPTRS(closure) 0L -# define FETCHME_CLOSURE_NoNONPTRS(closure) (IND_CLOSURE_SIZE(closure)-IND_VHS) - -# define MAX_GAS (RtsFlags.GranFlags.packBufferSize / PACK_GA_SIZE) -# define PACK_GA_SIZE 3 /* Size of a packed GA in words */ - /* Size of a packed fetch-me in words */ -# define PACK_FETCHME_SIZE (PACK_GA_SIZE + FIXED_HS) -# define PACK_HDR_SIZE 4 /* Words of header in a packet */ - -# define PACK_HEAP_REQUIRED \ - (RtsFlags.GranFlags.packBufferSize * sizeofW(StgClosure*) + \ - 2 * sizeofW(StgInt) + sizeofW(StgTSO*)) - -# define PACK_FLAG_LOCN 0 -# define PACK_TSO_LOCN 1 -# define PACK_UNPACKED_SIZE_LOCN 2 -# define PACK_SIZE_LOCN 3 -# define MAGIC_PACK_FLAG 0xfabc - -#endif /* GRAN */ - -//@node End of File, , Packing definitions -//@section End of File - -#endif /* defined(PAR) || defined(GRAN) whole file */ -#endif /* Parallel_H */ - - diff --git a/rts/parallel/0Unpack.c b/rts/parallel/0Unpack.c deleted file mode 100644 index fc4a8e50c3..0000000000 --- a/rts/parallel/0Unpack.c +++ /dev/null @@ -1,440 +0,0 @@ -/* - Time-stamp: <Wed Jan 12 2000 13:29:08 Stardate: [-30]4193.85 hwloidl> - - Unpacking closures which have been exported to remote processors - - This module defines routines for unpacking closures in the parallel - runtime system (GUM). - - In the case of GrAnSim, this module defines routines for *simulating* the - unpacking of closures as it is done in the parallel runtime system. -*/ - -/* - Code in this file has been merged with Pack.c -*/ - -#if 0 - -//@node Unpacking closures, , , -//@section Unpacking closures - -//@menu -//* Includes:: -//* Prototypes:: -//* GUM code:: -//* GranSim Code:: -//* Index:: -//@end menu -//*/ - -//@node Includes, Prototypes, Unpacking closures, Unpacking closures -//@subsection Includes - -#include "Rts.h" -#include "RtsFlags.h" -#include "GranSimRts.h" -#include "ParallelRts.h" -#include "ParallelDebug.h" -#include "FetchMe.h" -#include "Storage.h" - -//@node Prototypes, GUM code, Includes, Unpacking closures -//@subsection Prototypes - -void InitPacking(void); -# if defined(PAR) -void InitPackBuffer(void); -# endif -/* Interface for ADT of closure queues */ -void AllocClosureQueue(nat size); -void InitClosureQueue(void); -rtsBool QueueEmpty(void); -void QueueClosure(StgClosure *closure); -StgClosure *DeQueueClosure(void); - -StgPtr AllocateHeap(nat size); - -//@node GUM code, GranSim Code, Prototypes, Unpacking closures -//@subsection GUM code - -#if defined(PAR) - -//@node Local Definitions, , GUM code, GUM code -//@subsubsection Local Definitions - -//@cindex PendingGABuffer -static globalAddr *PendingGABuffer; -/* is initialised in main; */ - -//@cindex InitPendingGABuffer -void -InitPendingGABuffer(size) -nat size; -{ - PendingGABuffer = (globalAddr *) - stgMallocBytes((size-PACK_HDR_SIZE)*2*sizeof(globalAddr), - "InitPendingGABuffer"); -} - -/* - @CommonUp@ commons up two closures which we have discovered to be - variants of the same object. One is made an indirection to the other. */ - -//@cindex CommonUp -void -CommonUp(StgClosure *src, StgClosure *dst) -{ - StgBlockingQueueElement *bqe; - - ASSERT(src != dst); - switch (get_itbl(src)->type) { - case BLACKHOLE_BQ: - bqe = ((StgBlockingQueue *)src)->blocking_queue; - break; - - case FETCH_ME_BQ: - bqe = ((StgFetchMeBlockingQueue *)src)->blocking_queue; - break; - - case RBH: - bqe = ((StgRBH *)src)->blocking_queue; - break; - - case BLACKHOLE: - case FETCH_ME: - bqe = END_BQ_QUEUE; - break; - - default: - /* Don't common up anything else */ - return; - } - /* We do not use UPD_IND because that would awaken the bq, too */ - // UPD_IND(src, dst); - updateWithIndirection(get_itbl(src), src, dst); - //ASSERT(!IS_BIG_MOTHER(INFO_PTR(dst))); - if (bqe != END_BQ_QUEUE) - awaken_blocked_queue(bqe, src); -} - -/* - @UnpackGraph@ unpacks the graph contained in a message buffer. It - returns a pointer to the new graph. The @gamap@ parameter is set to - point to an array of (oldGA,newGA) pairs which were created as a result - of unpacking the buffer; @nGAs@ is set to the number of GA pairs which - were created. - - The format of graph in the pack buffer is as defined in @Pack.lc@. */ - -//@cindex UnpackGraph -StgClosure * -UnpackGraph(packBuffer, gamap, nGAs) -rtsPackBuffer *packBuffer; -globalAddr **gamap; -nat *nGAs; -{ - nat size, ptrs, nonptrs, vhs; - StgWord **buffer, **bufptr, **slotptr; - globalAddr ga, *gaga; - StgClosure *closure, *existing, - *graphroot, *graph, *parent; - StgInfoTable *ip, *oldip; - nat bufsize, i, - pptr = 0, pptrs = 0, pvhs; - char str[80]; - - InitPackBuffer(); /* in case it isn't already init'd */ - graphroot = (StgClosure *)NULL; - - gaga = PendingGABuffer; - - InitClosureQueue(); - - /* Unpack the header */ - bufsize = packBuffer->size; - buffer = packBuffer->buffer; - bufptr = buffer; - - /* allocate heap */ - if (bufsize > 0) { - graph = allocate(bufsize); - ASSERT(graph != NULL); - } - - parent = (StgClosure *)NULL; - - do { - /* This is where we will ultimately save the closure's address */ - slotptr = bufptr; - - /* First, unpack the next GA or PLC */ - ga.weight = (rtsWeight) *bufptr++; - - if (ga.weight > 0) { - ga.payload.gc.gtid = (GlobalTaskId) *bufptr++; - ga.payload.gc.slot = (int) *bufptr++; - } else - ga.payload.plc = (StgPtr) *bufptr++; - - /* Now unpack the closure body, if there is one */ - if (isFixed(&ga)) { - /* No more to unpack; just set closure to local address */ - IF_PAR_DEBUG(pack, - belch("Unpacked PLC at %x", ga.payload.plc)); - closure = ga.payload.plc; - } else if (isOffset(&ga)) { - /* No more to unpack; just set closure to cached address */ - ASSERT(parent != (StgClosure *)NULL); - closure = (StgClosure *) buffer[ga.payload.gc.slot]; - } else { - /* Now we have to build something. */ - - ASSERT(bufsize > 0); - - /* - * Close your eyes. You don't want to see where we're looking. You - * can't get closure info until you've unpacked the variable header, - * but you don't know how big it is until you've got closure info. - * So...we trust that the closure in the buffer is organized the - * same way as they will be in the heap...at least up through the - * end of the variable header. - */ - ip = get_closure_info(bufptr, &size, &ptrs, &nonptrs, &vhs, str); - - /* - Remember, the generic closure layout is as follows: - +-------------------------------------------------+ - | FIXED HEADER | VARIABLE HEADER | PTRS | NON-PRS | - +-------------------------------------------------+ - */ - /* Fill in the fixed header */ - for (i = 0; i < FIXED_HS; i++) - ((StgPtr)graph)[i] = *bufptr++; - - if (ip->type == FETCH_ME) - size = ptrs = nonptrs = vhs = 0; - - /* Fill in the packed variable header */ - for (i = 0; i < vhs; i++) - ((StgPtr)graph)[FIXED_HS + i] = *bufptr++; - - /* Pointers will be filled in later */ - - /* Fill in the packed non-pointers */ - for (i = 0; i < nonptrs; i++) - ((StgPtr)graph)[FIXED_HS + i + vhs + ptrs] = *bufptr++; - - /* Indirections are never packed */ - // ASSERT(INFO_PTR(graph) != (W_) Ind_info_TO_USE); - - /* Add to queue for processing */ - QueueClosure(graph); - - /* - * Common up the new closure with any existing closure having the same - * GA - */ - - if ((existing = GALAlookup(&ga)) == NULL) { - globalAddr *newGA; - /* Just keep the new object */ - IF_PAR_DEBUG(pack, - belch("Unpacking new (%x, %d, %x)\n", - ga.payload.gc.gtid, ga.payload.gc.slot, ga.weight)); - - closure = graph; - newGA = setRemoteGA(graph, &ga, rtsTrue); - if (ip->type == FETCH_ME) - // FETCHME_GA(closure) = newGA; - ((StgFetchMe *)closure)->ga = newGA; - } else { - /* Two closures, one global name. Someone loses */ - oldip = get_itbl(existing); - - if ((oldip->type == FETCH_ME || IS_BLACK_HOLE(existing)) && - ip->type != FETCH_ME) { - - /* What we had wasn't worth keeping */ - closure = graph; - CommonUp(existing, graph); - } else { - - /* - * Either we already had something worthwhile by this name or - * the new thing is just another FetchMe. However, the thing we - * just unpacked has to be left as-is, or the child unpacking - * code will fail. Remember that the way pointer words are - * filled in depends on the info pointers of the parents being - * the same as when they were packed. - */ - IF_PAR_DEBUG(pack, - belch("Unpacking old (%x, %d, %x), keeping %#lx", - ga.payload.gc.gtid, ga.payload.gc.slot, ga.weight, - existing)); - - closure = existing; - } - /* Pool the total weight in the stored ga */ - (void) addWeight(&ga); - } - - /* Sort out the global address mapping */ - if ((ip_THUNK(ip) && !ip_UNPOINTED(ip)) || - (ip_MUTABLE(ip) && ip->type != FETCH_ME)) { - /* Make up new GAs for single-copy closures */ - globalAddr *newGA = makeGlobal(closure, rtsTrue); - - ASSERT(closure == graph); - - /* Create an old GA to new GA mapping */ - *gaga++ = ga; - splitWeight(gaga, newGA); - ASSERT(gaga->weight == 1L << (BITS_IN(unsigned) - 1)); - gaga++; - } - graph += FIXED_HS + (size < MIN_UPD_SIZE ? MIN_UPD_SIZE : size); - } - - /* - * Set parent pointer to point to chosen closure. If we're at the top of - * the graph (our parent is NULL), then we want to arrange to return the - * chosen closure to our caller (possibly in place of the allocated graph - * root.) - */ - if (parent == NULL) - graphroot = closure; - else - ((StgPtr)parent)[FIXED_HS + pvhs + pptr] = (StgWord) closure; - - /* Save closure pointer for resolving offsets */ - *slotptr = (StgWord) closure; - - /* Locate next parent pointer */ - pptr++; - while (pptr + 1 > pptrs) { - parent = DeQueueClosure(); - - if (parent == NULL) - break; - else { - (void) get_closure_info(parent, &size, &pptrs, &nonptrs, - &pvhs, str); - pptr = 0; - } - } - } while (parent != NULL); - - ASSERT(bufsize == 0 || graph - 1 <= SAVE_Hp); - - *gamap = PendingGABuffer; - *nGAs = (gaga - PendingGABuffer) / 2; - - /* ToDo: are we *certain* graphroot has been set??? WDP 95/07 */ - ASSERT(graphroot!=NULL); - return (graphroot); -} -#endif /* PAR */ - -//@node GranSim Code, Index, GUM code, Unpacking closures -//@subsection GranSim Code - -/* - For GrAnSim: In general no actual unpacking should be necessary. We just - have to walk over the graph and set the bitmasks appropriately. -- HWL */ - -//@node Unpacking, , GranSim Code, GranSim Code -//@subsubsection Unpacking - -#if defined(GRAN) -void -CommonUp(StgClosure *src, StgClosure *dst) -{ - barf("CommonUp: should never be entered in a GranSim setup"); -} - -/* This code fakes the unpacking of a somewhat virtual buffer */ -StgClosure* -UnpackGraph(buffer) -rtsPackBuffer* buffer; -{ - nat size, ptrs, nonptrs, vhs, - bufptr = 0; - StgClosure *closure, *graphroot, *graph; - StgInfoTable *ip; - StgWord bufsize, unpackedsize, - pptr = 0, pptrs = 0, pvhs; - StgTSO* tso; - char str[240], str1[80]; - int i; - - bufptr = 0; - graphroot = buffer->buffer[0]; - - tso = buffer->tso; - - /* Unpack the header */ - unpackedsize = buffer->unpacked_size; - bufsize = buffer->size; - - IF_GRAN_DEBUG(pack, - belch("<<< Unpacking <<%d>> (buffer @ %p):\n (root @ %p, PE %d,size=%d), demanded by TSO %d (%p)[PE %d]", - buffer->id, buffer, graphroot, where_is(graphroot), - bufsize, tso->id, tso, - where_is((StgClosure *)tso))); - - do { - closure = buffer->buffer[bufptr++]; /* that's all we need for GrAnSim -- HWL */ - - /* Actually only ip is needed; rest is useful for TESTING -- HWL */ - ip = get_closure_info(closure, - &size, &ptrs, &nonptrs, &vhs, str); - - IF_GRAN_DEBUG(pack, - sprintf(str, "** (%p): Changing bitmask[%s]: 0x%x ", - closure, (closure_HNF(closure) ? "NF" : "__"), - PROCS(closure))); - - if (ip->type == RBH) { - closure->header.gran.procs = PE_NUMBER(CurrentProc); /* Move node */ - - IF_GRAN_DEBUG(pack, - strcat(str, " (converting RBH) ")); - - convertFromRBH(closure); /* In GUM that's done by convertToFetchMe */ - } else if (IS_BLACK_HOLE(closure)) { - closure->header.gran.procs |= PE_NUMBER(CurrentProc); /* Copy node */ - } else if ( closure->header.gran.procs & PE_NUMBER(CurrentProc) == 0 ) { - if (closure_HNF(closure)) - closure->header.gran.procs |= PE_NUMBER(CurrentProc); /* Copy node */ - else - closure->header.gran.procs = PE_NUMBER(CurrentProc); /* Move node */ - } - - IF_GRAN_DEBUG(pack, - sprintf(str1, "0x%x", PROCS(closure)); strcat(str, str1)); - IF_GRAN_DEBUG(pack, belch(str)); - - } while (bufptr<buffer->size) ; /* (parent != NULL); */ - - /* In GrAnSim we allocate pack buffers dynamically! -- HWL */ - free(buffer->buffer); - free(buffer); - - IF_GRAN_DEBUG(pack, - belch("PrintGraph of %p is:", graphroot); PrintGraph(graphroot,0)); - - return (graphroot); -} -#endif /* GRAN */ -#endif - -//@node Index, , GranSim Code, Unpacking closures -//@subsection Index - -//@index -//* CommonUp:: @cindex\s-+CommonUp -//* InitPendingGABuffer:: @cindex\s-+InitPendingGABuffer -//* PendingGABuffer:: @cindex\s-+PendingGABuffer -//* UnpackGraph:: @cindex\s-+UnpackGraph -//@end index diff --git a/rts/parallel/Dist.c b/rts/parallel/Dist.c deleted file mode 100644 index eeec780716..0000000000 --- a/rts/parallel/Dist.c +++ /dev/null @@ -1,117 +0,0 @@ -#include "Dist.h" - -#ifdef DIST /* whole file */ - -#include "RtsFlags.h" -#include "RtsUtils.h" -#include "ParallelRts.h" -#include "Parallel.h" // nPEs,allPEs,mytid -#include "HLC.h" //for sendReval -#include "LLC.h" //for pvm stuff -#include "FetchMe.h" // for BLOCKED_FETCH_info -#include "Storage.h" // for recordMutable - -/* hopefully the result>0 */ -StgWord32 cGetPECount(void) -{ return nPEs; -} - -/* return taskID, n is 1..count, n=1 is always the mainPE */ -StgPEId cGetPEId(StgWord32 n) -{ return allPEs[n-1]; -} - -/* return the taskID */ -StgPEId cGetMyPEId(void) -{ return mytid; -} - -/* return the taskID of the owning PE of an MVar/TSO: -- MVAR/TSOs get converted to REMOTE_REFs when shipped, and - there is no mechanism for using these REMOTE_REFs - apart from this code. -*/ - -StgPEId cGetCertainOwner(StgClosure *mv) -{ globalAddr *ga; - switch(get_itbl(mv)->type) - { case TSO: - case MVAR: - return mytid; // must be local - case REMOTE_REF: - ga = LAGAlookup(mv); - ASSERT(ga); - return ga->payload.gc.gtid; // I know its global address - } - barf("Dist.c:cGetCertainOwner() wrong closure type %s",info_type(mv)); -} - -/* for some additional fun, lets look up a certain host... */ -StgPEId cGetHostOwner(StgByteArray h) //okay h is a C string -{ int nArch,nHost,nTask,i; - StgPEId dtid; - struct pvmhostinfo *host; - struct pvmtaskinfo *task; - - dtid=0; - pvm_config(&nHost,&nArch,&host); - for(i=0;i<nHost;i++) - if(strcmp(host[i].hi_name,h)==0) - { dtid=host[i].hi_tid; - break; - } - if(dtid==0) return 0; // no host of that name - - for(i=0;i<nPEs;i++) - { pvm_tasks(allPEs[i],&nTask,&task); - ASSERT(nTask==1); //cause we lookup a single task - if(task[0].ti_host==dtid) - return allPEs[i]; - } - return 0; //know host, put no PE on it -} - -void cRevalIO(StgClosure *job,StgPEId p) -{ nat size; - rtsPackBuffer *buffer=NULL; - - ASSERT(get_itbl(job)->type==MVAR); - job=((StgMVar*)job)->value; // extract the job from the MVar - - ASSERT(closure_THUNK(job)); // must be a closure!!!!! - ASSERT(p!=mytid); - - buffer = PackNearbyGraph(job, END_TSO_QUEUE, &size,p); - ASSERT(buffer != (rtsPackBuffer *)NULL); - ASSERT(get_itbl(job)->type==RBH); - - IF_PAR_DEBUG(verbose, - belch("@;~) %x doing revalIO to %x\n", - mytid,p)); - - sendReval(p,size,buffer); - - if (RtsFlags.ParFlags.ParStats.Global && - RtsFlags.GcFlags.giveStats > NO_GC_STATS) { - globalParStats.tot_reval_mess++; - } - - /* - We turn job into a FETCHME_BQ so that the thread will block - when it enters it. - - Note: it will not receive an ACK, thus no GA. - */ - - ASSERT(get_itbl(job)->type==RBH); - - /* put closure on mutables list, while it is still a RBH */ - recordMutable((StgMutClosure *)job); - - /* actually turn it into a FETCH_ME_BQ */ - SET_INFO(job, &FETCH_ME_BQ_info); - ((StgFetchMe *)job)->ga = 0; //hope this won't make anyone barf!!! - ((StgBlockingQueue*)job)->blocking_queue=END_BQ_QUEUE; -} - -#endif diff --git a/rts/parallel/Dist.h b/rts/parallel/Dist.h deleted file mode 100644 index c67cce2748..0000000000 --- a/rts/parallel/Dist.h +++ /dev/null @@ -1,20 +0,0 @@ -#ifndef __DIST_H -#define __DIST_H - -#ifdef DIST - -#include "Rts.h" - -typedef StgWord32 StgPEId; - -// interface functions for Haskell Language calls -StgWord32 cGetPECount(void); -StgPEId cGetPEId(StgWord32 n); -StgPEId cGetMyPEId(void); -StgPEId cGetCertainOwner(StgClosure *mv); -void cRevalIO(StgClosure *job,StgPEId p); -StgPEId cGetHostOwner(StgByteArray h); - -#endif /* DIST */ - -#endif /* __DIST_H */ diff --git a/rts/parallel/FetchMe.h b/rts/parallel/FetchMe.h deleted file mode 100644 index be5cbf6b54..0000000000 --- a/rts/parallel/FetchMe.h +++ /dev/null @@ -1,24 +0,0 @@ -/* ----------------------------------------------------------------------------- - * - * Closure types for the parallel system. - * - * ---------------------------------------------------------------------------*/ - -EI_(stg_FETCH_ME_info); -EF_(stg_FETCH_ME_entry); - -EI_(stg_FETCH_ME_BQ_info); -EF_(stg_FETCH_ME_BQ_entry); - -EI_(stg_BLOCKED_FETCH_info); -EF_(stg_BLOCKED_FETCH_entry); - -EI_(stg_REMOTE_REF_info); -EF_(stg_REMOTE_REF_entry); - -EI_(stg_RBH_Save_0_info); -EF_(stg_RBH_Save_0_entry); -EI_(stg_RBH_Save_1_info); -EF_(stg_RBH_Save_1_entry); -EI_(stg_RBH_Save_2_info); -EF_(stg_RBH_Save_2_entry); diff --git a/rts/parallel/FetchMe.hc b/rts/parallel/FetchMe.hc deleted file mode 100644 index f142e9e514..0000000000 --- a/rts/parallel/FetchMe.hc +++ /dev/null @@ -1,180 +0,0 @@ -/* ---------------------------------------------------------------------------- - Time-stamp: <Tue Mar 06 2001 17:01:46 Stardate: [-30]6288.54 hwloidl> - - Entry code for a FETCH_ME closure - - This module defines routines for handling remote pointers (@FetchMe@s) - in GUM. It is threaded (@.hc@) because @FetchMe_entry@ will be - called during evaluation. - - * --------------------------------------------------------------------------*/ - -#ifdef PAR /* all of it */ - -//@menu -//* Includes:: -//* Info tables:: -//* Index:: -//@end menu - -//@node Includes, Info tables -//@subsection Includes - -#include "Stg.h" -#include "Rts.h" -#include "RtsFlags.h" -#include "RtsUtils.h" -#include "Storage.h" -#include "GranSim.h" -#include "GranSimRts.h" -#include "Parallel.h" -#include "ParallelRts.h" -#include "FetchMe.h" -#include "HLC.h" -#include "StgRun.h" /* for StgReturn and register saving */ - -/* -------------------------------------------------------------------------- - FETCH_ME closures. - - A FETCH_ME closure represents data that currently resides on - another PE. We issue a fetch message, and wait for the data to be - retrieved. - - A word on the ptr/nonptr fields in the macros: they are unused at the - moment; all closures defined here have constant size (ie. no payload - that varies from closure to closure). Therefore, all routines that - need to know the size of these closures have to do a sizeofW(StgFetchMe) - etc to get the closure size. See get_closure_info(), evacuate() and - checkClosure() (using the same fcts for determining the size of the - closures would be a good idea; at least it would be a nice step towards - making this code bug free). - ------------------------------------------------------------------------ */ - -//@node Info tables, Index, Includes -//@subsection Info tables - -//@cindex FETCH_ME_info -INFO_TABLE(stg_FETCH_ME_info, stg_FETCH_ME_entry, 0,2, FETCH_ME,, EF_,"FETCH_ME","FETCH_ME"); -//@cindex FETCH_ME_entry -STGFUN(stg_FETCH_ME_entry) -{ - FB_ - TICK_ENT_BH(); - - ASSERT(((StgFetchMe *)R1.p)->ga->payload.gc.gtid != mytid); - - /* Turn the FETCH_ME into a FETCH_ME_BQ, and place the current thread - * on the blocking queue. - */ - // ((StgFetchMeBlockingQueue *)R1.cl)->header.info = &FETCH_ME_BQ_info; // does the same as SET_INFO - SET_INFO((StgClosure *)R1.cl, &stg_FETCH_ME_BQ_info); - - /* Remember GA as a global var (used in blockThread); NB: not thread safe! */ - ASSERT(theGlobalFromGA.payload.gc.gtid == (GlobalTaskId)0); - theGlobalFromGA = *((StgFetchMe *)R1.p)->ga; - - /* Put ourselves on the blocking queue for this black hole */ - ASSERT(looks_like_ga(((StgFetchMe *)R1.p)->ga)); - CurrentTSO->link = END_BQ_QUEUE; - ((StgFetchMeBlockingQueue *)R1.cl)->blocking_queue = (StgBlockingQueueElement *)CurrentTSO; - - /* jot down why and on what closure we are blocked */ - CurrentTSO->why_blocked = BlockedOnGA; - CurrentTSO->block_info.closure = R1.cl; - /* closure is mutable since something has just been added to its BQ */ - //recordMutable((StgMutClosure *)R1.cl); - - /* sendFetch etc is now done in blockThread, which is called from the - scheduler -- HWL */ - - BLOCK_NP(1); - FE_ -} - -/* --------------------------------------------------------------------------- - FETCH_ME_BQ - - On the first entry of a FETCH_ME closure, we turn the closure into - a FETCH_ME_BQ, which behaves just like a BLACKHOLE_BQ. Any thread - entering the FETCH_ME_BQ will be placed in the blocking queue. - When the data arrives from the remote PE, all waiting threads are - woken up and the FETCH_ME_BQ is overwritten with the fetched data. - - FETCH_ME_BQ_entry is almost identical to BLACKHOLE_BQ_entry -- HWL - ------------------------------------------------------------------------ */ - -INFO_TABLE(stg_FETCH_ME_BQ_info, stg_FETCH_ME_BQ_entry,0,2,FETCH_ME_BQ,,EF_,"FETCH_ME_BQ","FETCH_ME_BQ"); -//@cindex FETCH_ME_BQ_info -STGFUN(stg_FETCH_ME_BQ_entry) -{ - FB_ - TICK_ENT_BH(); - - /* Put ourselves on the blocking queue for this node */ - CurrentTSO->link = (StgTSO*)((StgBlockingQueue *)R1.p)->blocking_queue; - ((StgBlockingQueue *)R1.p)->blocking_queue = (StgBlockingQueueElement *)CurrentTSO; - - /* jot down why and on what closure we are blocked */ - CurrentTSO->why_blocked = BlockedOnGA_NoSend; - CurrentTSO->block_info.closure = R1.cl; - - /* stg_gen_block is too heavyweight, use a specialised one */ - BLOCK_NP(1); - FE_ -} - -/* --------------------------------------------------------------------------- - BLOCKED_FETCH_BQ - - A BLOCKED_FETCH closure only ever exists in the blocking queue of a - globally visible closure i.e. one with a GA. A BLOCKED_FETCH closure - indicates that a TSO on another PE is waiting for the result of this - computation. Thus, when updating the closure, the result has to be sent - to that PE. The relevant routines handling that are awakenBlockedQueue - and blockFetch (for putting BLOCKED_FETCH closure into a BQ). - ------------------------------------------------------------------------ */ - -//@cindex BLOCKED_FETCH_info -INFO_TABLE(stg_BLOCKED_FETCH_info, stg_BLOCKED_FETCH_entry,0,2,BLOCKED_FETCH,,EF_,"BLOCKED_FETCH","BLOCKED_FETCH"); -//@cindex BLOCKED_FETCH_entry -STGFUN(stg_BLOCKED_FETCH_entry) -{ - FB_ - /* see NON_ENTERABLE_ENTRY_CODE in StgMiscClosures.hc */ - STGCALL2(fprintf,stderr,"BLOCKED_FETCH object entered!\n"); - STGCALL1(shutdownHaskellAndExit, EXIT_FAILURE); - FE_ -} - - -/* --------------------------------------------------------------------------- - REMOTE_REF - - A REMOTE_REF closure is generated whenever we wish to refer to a sticky - object on another PE. - ------------------------------------------------------------------------ */ - -//@cindex REMOTE_REF_info -INFO_TABLE(stg_REMOTE_REF_info, stg_REMOTE_REF_entry,0,2,REMOTE_REF,,EF_,"REMOTE_REF","REMOTE_REF"); -//@cindex REMOTE_REF_entry -STGFUN(stg_REMOTE_REF_entry) -{ - FB_ - /* see NON_ENTERABLE_ENTRY_CODE in StgMiscClosures.hc */ - STGCALL2(fprintf,stderr,"REMOTE REF object entered!\n"); - STGCALL1(shutdownHaskellAndExit, EXIT_FAILURE); - FE_ -} - -#endif /* PAR */ - -//@node Index, , Info tables -//@subsection Index - -//@index -//* BLOCKED_FETCH_entry:: @cindex\s-+BLOCKED_FETCH_entry -//* BLOCKED_FETCH_info:: @cindex\s-+BLOCKED_FETCH_info -//* FETCH_ME_BQ_info:: @cindex\s-+FETCH_ME_BQ_info -//* FETCH_ME_entry:: @cindex\s-+FETCH_ME_entry -//* FETCH_ME_info:: @cindex\s-+FETCH_ME_info -//@end index diff --git a/rts/parallel/Global.c b/rts/parallel/Global.c deleted file mode 100644 index aea3f8aba4..0000000000 --- a/rts/parallel/Global.c +++ /dev/null @@ -1,1090 +0,0 @@ -/* --------------------------------------------------------------------------- - Time-stamp: <2009-12-02 12:26:23 simonmar> - - (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 "sm/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 diff --git a/rts/parallel/GranSim.c b/rts/parallel/GranSim.c deleted file mode 100644 index 7f7ad4424f..0000000000 --- a/rts/parallel/GranSim.c +++ /dev/null @@ -1,3015 +0,0 @@ -/* - Time-stamp: <2009-07-06 21:48:36 simonmar> - - Variables and functions specific to GranSim the parallelism simulator - for GPH. -*/ - -//@node GranSim specific code, , , -//@section GranSim specific code - -/* - Macros for dealing with the new and improved GA field for simulating - parallel execution. Based on @CONCURRENT@ package. The GA field now - contains a mask, where the n-th bit stands for the n-th processor, where - this data can be found. In case of multiple copies, several bits are - set. The total number of processors is bounded by @MAX_PROC@, which - should be <= the length of a word in bits. -- HWL -*/ - -//@menu -//* Includes:: -//* Prototypes and externs:: -//* Constants and Variables:: -//* Initialisation:: -//* Global Address Operations:: -//* Global Event Queue:: -//* Spark queue functions:: -//* Scheduling functions:: -//* Thread Queue routines:: -//* GranSim functions:: -//* GranSimLight routines:: -//* Code for Fetching Nodes:: -//* Idle PEs:: -//* Routines directly called from Haskell world:: -//* Emiting profiling info for GrAnSim:: -//* Dumping routines:: -//* Index:: -//@end menu - -//@node Includes, Prototypes and externs, GranSim specific code, GranSim specific code -//@subsection Includes - -#if defined(GRAN) - -#include "Rts.h" -#include "RtsFlags.h" -#include "RtsUtils.h" -#include "StgMiscClosures.h" -#include "StgTypes.h" -#include "Storage.h" // for recordMutable -#include "Schedule.h" -#include "SchedAPI.h" // for pushClosure -#include "GranSimRts.h" -#include "GranSim.h" -#include "ParallelRts.h" -#include "ParallelDebug.h" -#include "Sparks.h" - - -//@node Prototypes and externs, Constants and Variables, Includes, GranSim specific code -//@subsection Prototypes and externs - -/* Prototypes */ -static inline PEs ga_to_proc(StgWord); -static inline rtsBool any_idle(void); -static inline nat idlers(void); - PEs where_is(StgClosure *node); - -static rtsBool stealSomething(PEs proc, rtsBool steal_spark, rtsBool steal_thread); -static rtsBool stealSpark(PEs proc); -static rtsBool stealThread(PEs proc); -static rtsBool stealSparkMagic(PEs proc); -static rtsBool stealThreadMagic(PEs proc); -/* subsumed by stealSomething -static void stealThread(PEs proc); -static void stealSpark(PEs proc); -*/ -static rtsTime sparkStealTime(void); -static nat natRandom(nat from, nat to); -static PEs findRandomPE(PEs proc); -static void sortPEsByTime (PEs proc, PEs *pes_by_time, - nat *firstp, nat *np); - -void GetRoots(void); - -#endif /* GRAN */ - -//@node Constants and Variables, Initialisation, Prototypes and externs, GranSim specific code -//@subsection Constants and Variables - -#if defined(GRAN) || defined(PAR) -/* See GranSim.h for the definition of the enum gran_event_types */ -char *gran_event_names[] = { - "START", "START(Q)", - "STEALING", "STOLEN", "STOLEN(Q)", - "FETCH", "REPLY", "BLOCK", "RESUME", "RESUME(Q)", - "SCHEDULE", "DESCHEDULE", - "END", - "SPARK", "SPARKAT", "USED", "PRUNED", "EXPORTED", "ACQUIRED", - "ALLOC", - "TERMINATE", - "SYSTEM_START", "SYSTEM_END", /* only for debugging */ - "??" -}; -#endif - -#if defined(GRAN) /* whole file */ -char *proc_status_names[] = { - "Idle", "Sparking", "Starting", "Fetching", "Fishing", "Busy", - "UnknownProcStatus" -}; - -/* For internal use (event statistics) only */ -char *event_names[] = - { "ContinueThread", "StartThread", "ResumeThread", - "MoveSpark", "MoveThread", "FindWork", - "FetchNode", "FetchReply", - "GlobalBlock", "UnblockThread" - }; - -//@cindex CurrentProc -PEs CurrentProc = 0; - -/* - ToDo: Create a structure for the processor status and put all the - arrays below into it. - -- HWL */ - -//@cindex CurrentTime -/* One clock for each PE */ -rtsTime CurrentTime[MAX_PROC]; - -/* Useful to restrict communication; cf fishing model in GUM */ -nat OutstandingFetches[MAX_PROC], OutstandingFishes[MAX_PROC]; - -/* Status of each PE (new since but independent of GranSim Light) */ -rtsProcStatus procStatus[MAX_PROC]; - -# if defined(GRAN) && defined(GRAN_CHECK) -/* To check if the RTS ever tries to run a thread that should be blocked - because of fetching remote data */ -StgTSO *BlockedOnFetch[MAX_PROC]; -# define FETCH_MASK_TSO 0x08000000 /* only bits 0, 1, 2 should be used */ -# endif - -nat SparksAvail = 0; /* How many sparks are available */ -nat SurplusThreads = 0; /* How many excess threads are there */ - -/* Do we need to reschedule following a fetch? */ -rtsBool NeedToReSchedule = rtsFalse, IgnoreEvents = rtsFalse, IgnoreYields = rtsFalse; -rtsTime TimeOfNextEvent, TimeOfLastEvent, EndOfTimeSlice; /* checked from the threaded world! */ - -//@cindex spark queue -/* GranSim: a globally visible array of spark queues */ -rtsSparkQ pending_sparks_hds[MAX_PROC]; -rtsSparkQ pending_sparks_tls[MAX_PROC]; - -nat sparksIgnored = 0, sparksCreated = 0; - -GlobalGranStats globalGranStats; - -nat gran_arith_cost, gran_branch_cost, gran_load_cost, - gran_store_cost, gran_float_cost; - -/* -Old comment from 0.29. ToDo: Check and update -- HWL - -The following variables control the behaviour of GrAnSim. In general, there -is one RTS option for enabling each of these features. In getting the -desired setup of GranSim the following questions have to be answered: -\begin{itemize} -\item {\em Which scheduling algorithm} to use (@RtsFlags.GranFlags.DoFairSchedule@)? - Currently only unfair scheduling is supported. -\item What to do when remote data is fetched (@RtsFlags.GranFlags.DoAsyncFetch@)? - Either block and wait for the - data or reschedule and do some other work. - Thus, if this variable is true, asynchronous communication is - modelled. Block on fetch mainly makes sense for incremental fetching. - - There is also a simplified fetch variant available - (@RtsFlags.GranFlags.SimplifiedFetch@). This variant does not use events to model - communication. It is faster but the results will be less accurate. -\item How aggressive to be in getting work after a reschedule on fetch - (@RtsFlags.GranFlags.FetchStrategy@)? - This is determined by the so-called {\em fetching - strategy\/}. Currently, there are four possibilities: - \begin{enumerate} - \item Only run a runnable thread. - \item Turn a spark into a thread, if necessary. - \item Steal a remote spark, if necessary. - \item Steal a runnable thread from another processor, if necessary. - \end{itemize} - The variable @RtsFlags.GranFlags.FetchStrategy@ determines how far to go in this list - when rescheduling on a fetch. -\item Should sparks or threads be stolen first when looking for work - (@RtsFlags.GranFlags.DoStealThreadsFirst@)? - The default is to steal sparks first (much cheaper). -\item Should the RTS use a lazy thread creation scheme - (@RtsFlags.GranFlags.DoAlwaysCreateThreads@)? By default yes i.e.\ sparks are only - turned into threads when work is needed. Also note, that sparks - can be discarded by the RTS (this is done in the case of an overflow - of the spark pool). Setting @RtsFlags.GranFlags.DoAlwaysCreateThreads@ to @True@ forces - the creation of threads at the next possibility (i.e.\ when new work - is demanded the next time). -\item Should data be fetched closure-by-closure or in packets - (@RtsFlags.GranFlags.DoBulkFetching@)? The default strategy is a GRIP-like incremental - (i.e.\ closure-by-closure) strategy. This makes sense in a - low-latency setting but is bad in a high-latency system. Setting - @RtsFlags.GranFlags.DoBulkFetching@ to @True@ enables bulk (packet) fetching. Other - parameters determine the size of the packets (@pack_buffer_size@) and the number of - thunks that should be put into one packet (@RtsFlags.GranFlags.ThunksToPack@). -\item If there is no other possibility to find work, should runnable threads - be moved to an idle processor (@RtsFlags.GranFlags.DoThreadMigration@)? In any case, the - RTS tried to get sparks (either local or remote ones) first. Thread - migration is very expensive, since a whole TSO has to be transferred - and probably data locality becomes worse in the process. Note, that - the closure, which will be evaluated next by that TSO is not - transferred together with the TSO (that might block another thread). -\item Should the RTS distinguish between sparks created by local nodes and - stolen sparks (@RtsFlags.GranFlags.PreferSparksOfLocalNodes@)? The idea is to improve - data locality by preferring sparks of local nodes (it is more likely - that the data for those sparks is already on the local processor). - However, such a distinction also imposes an overhead on the spark - queue management, and typically a large number of sparks are - generated during execution. By default this variable is set to @False@. -\item Should the RTS use granularity control mechanisms? The idea of a - granularity control mechanism is to make use of granularity - information provided via annotation of the @par@ construct in order - to prefer bigger threads when either turning a spark into a thread or - when choosing the next thread to schedule. Currently, three such - mechanisms are implemented: - \begin{itemize} - \item Cut-off: The granularity information is interpreted as a - priority. If a threshold priority is given to the RTS, then - only those sparks with a higher priority than the threshold - are actually created. Other sparks are immediately discarded. - This is similar to a usual cut-off mechanism often used in - parallel programs, where parallelism is only created if the - input data is lage enough. With this option, the choice is - hidden in the RTS and only the threshold value has to be - provided as a parameter to the runtime system. - \item Priority Sparking: This mechanism keeps priorities for sparks - and chooses the spark with the highest priority when turning - a spark into a thread. After that the priority information is - discarded. The overhead of this mechanism comes from - maintaining a sorted spark queue. - \item Priority Scheduling: This mechanism keeps the granularity - information for threads, to. Thus, on each reschedule the - largest thread is chosen. This mechanism has a higher - overhead, as the thread queue is sorted, too. - \end{itemize} -\end{itemize} -*/ - -//@node Initialisation, Global Address Operations, Constants and Variables, GranSim specific code -//@subsection Initialisation - -void -init_gr_stats (void) { - memset(&globalGranStats, '\0', sizeof(GlobalGranStats)); -#if 0 - /* event stats */ - globalGranStats.noOfEvents = 0; - for (i=0; i<MAX_EVENT; i++) globalGranStats.event_counts[i]=0; - - /* communication stats */ - globalGranStats.fetch_misses = 0; - globalGranStats.tot_low_pri_sparks = 0; - - /* obscure stats */ - globalGranStats.rs_sp_count = 0; - globalGranStats.rs_t_count = 0; - globalGranStats.ntimes_total = 0, - globalGranStats.fl_total = 0; - globalGranStats.no_of_steals = 0; - - /* spark queue stats */ - globalGranStats.tot_sq_len = 0, - globalGranStats.tot_sq_probes = 0; - globalGranStats.tot_sparks = 0; - globalGranStats.withered_sparks = 0; - globalGranStats.tot_add_threads = 0; - globalGranStats.tot_tq_len = 0; - globalGranStats.non_end_add_threads = 0; - - /* thread stats */ - globalGranStats.tot_threads_created = 0; - for (i=0; i<MAX_PROC; i++) globalGranStats.threads_created_on_PE[i]=0; -#endif /* 0 */ -} - -//@node Global Address Operations, Global Event Queue, Initialisation, GranSim specific code -//@subsection Global Address Operations -/* - ---------------------------------------------------------------------- - Global Address Operations - - These functions perform operations on the global-address (ga) part of a - closure. The ga is the only new field (1 word) in a closure introduced by - GrAnSim. It serves as a bitmask, indicating on which processor the - closure is residing. Since threads are described by Thread State Object - (TSO), which is nothing but another kind of closure, this scheme allows - gives placement information about threads. - - A ga is just a bitmask, so the operations on them are mainly bitmask - manipulating functions. Note, that there are important macros like PROCS, - IS_LOCAL_TO etc. They are defined in @GrAnSim.lh@. - - NOTE: In GrAnSim-light we don't maintain placement information. This - allows to simulate an arbitrary number of processors. The price we have - to be is the lack of costing any communication properly. In short, - GrAnSim-light is meant to reveal the maximal parallelism in a program. - From an implementation point of view the important thing is: {\em - GrAnSim-light does not maintain global-addresses}. */ - -/* ga_to_proc returns the first processor marked in the bitmask ga. - Normally only one bit in ga should be set. But for PLCs all bits - are set. That shouldn't hurt since we only need IS_LOCAL_TO for PLCs */ - -//@cindex ga_to_proc - -static inline PEs -ga_to_proc(StgWord ga) -{ - PEs i; - for (i = 0; i < RtsFlags.GranFlags.proc && !IS_LOCAL_TO(ga, i); i++); - ASSERT(i<RtsFlags.GranFlags.proc); - return (i); -} - -/* NB: This takes a *node* rather than just a ga as input */ -//@cindex where_is -PEs -where_is(StgClosure *node) -{ return (ga_to_proc(PROCS(node))); } - -// debugging only -//@cindex is_unique -rtsBool -is_unique(StgClosure *node) -{ - PEs i; - rtsBool unique = rtsFalse; - - for (i = 0; i < RtsFlags.GranFlags.proc ; i++) - if (IS_LOCAL_TO(PROCS(node), i)) - if (unique) // exactly 1 instance found so far - return rtsFalse; // found a 2nd instance => not unique - else - unique = rtsTrue; // found 1st instance - ASSERT(unique); // otherwise returned from within loop - return (unique); -} - -//@cindex any_idle -static inline rtsBool -any_idle(void) { /* any (map (\ i -> procStatus[i] == Idle)) [0,..,MAX_PROC] */ - PEs i; - rtsBool any_idle; - for(i=0, any_idle=rtsFalse; - !any_idle && i<RtsFlags.GranFlags.proc; - any_idle = any_idle || procStatus[i] == Idle, i++) - {} ; -} - -//@cindex idlers -static inline nat -idlers(void) { /* number of idle PEs */ - PEs i, j; - for(i=0, j=0; - i<RtsFlags.GranFlags.proc; - j += (procStatus[i] == Idle) ? 1 : 0, i++) - {} ; - return j; -} - -//@node Global Event Queue, Spark queue functions, Global Address Operations, GranSim specific code -//@subsection Global Event Queue -/* -The following routines implement an ADT of an event-queue (FIFO). -ToDo: Put that in an own file(?) -*/ - -/* Pointer to the global event queue; events are currently malloc'ed */ -rtsEventQ EventHd = NULL; - -//@cindex get_next_event -rtsEvent * -get_next_event(void) -{ - static rtsEventQ entry = NULL; - - if (EventHd == NULL) { - barf("No next event. This may be caused by a circular data dependency in the program."); - } - - if (entry != NULL) - free((char *)entry); - - if (RtsFlags.GranFlags.GranSimStats.Global) { /* count events */ - globalGranStats.noOfEvents++; - globalGranStats.event_counts[EventHd->evttype]++; - } - - entry = EventHd; - - IF_GRAN_DEBUG(event_trace, - print_event(entry)); - - EventHd = EventHd->next; - return(entry); -} - -/* When getting the time of the next event we ignore CONTINUETHREAD events: - we don't want to be interrupted before the end of the current time slice - unless there is something important to handle. -*/ -//@cindex get_time_of_next_event -rtsTime -get_time_of_next_event(void) -{ - rtsEventQ event = EventHd; - - while (event != NULL && event->evttype==ContinueThread) { - event = event->next; - } - if(event == NULL) - return ((rtsTime) 0); - else - return (event->time); -} - -/* ToDo: replace malloc/free with a free list */ -//@cindex insert_event -void -insert_event(newentry) -rtsEvent *newentry; -{ - rtsEventType evttype = newentry->evttype; - rtsEvent *event, **prev; - - /* if(evttype >= CONTINUETHREAD1) evttype = CONTINUETHREAD; */ - - /* Search the queue and insert at the right point: - FINDWORK before everything, CONTINUETHREAD after everything. - - This ensures that we find any available work after all threads have - executed the current cycle. This level of detail would normally be - irrelevant, but matters for ridiculously low latencies... - */ - - /* Changed the ordering: Now FINDWORK comes after everything but - CONTINUETHREAD. This makes sure that a MOVESPARK comes before a - FINDWORK. This is important when a GranSimSparkAt happens and - DoAlwaysCreateThreads is turned on. Also important if a GC occurs - when trying to build a new thread (see much_spark) -- HWL 02/96 */ - - if(EventHd == NULL) - EventHd = newentry; - else { - for (event = EventHd, prev=(rtsEvent**)&EventHd; - event != NULL; - prev = (rtsEvent**)&(event->next), event = event->next) { - switch (evttype) { - case FindWork: if ( event->time < newentry->time || - ( (event->time == newentry->time) && - (event->evttype != ContinueThread) ) ) - continue; - else - break; - case ContinueThread: if ( event->time <= newentry->time ) - continue; - else - break; - default: if ( event->time < newentry->time || - ((event->time == newentry->time) && - (event->evttype == newentry->evttype)) ) - continue; - else - break; - } - /* Insert newentry here (i.e. before event) */ - *prev = newentry; - newentry->next = event; - break; - } - if (event == NULL) - *prev = newentry; - } -} - -//@cindex new_event -void -new_event(proc,creator,time,evttype,tso,node,spark) -PEs proc, creator; -rtsTime time; -rtsEventType evttype; -StgTSO *tso; -StgClosure *node; -rtsSpark *spark; -{ - rtsEvent *newentry = (rtsEvent *) stgMallocBytes(sizeof(rtsEvent), "new_event"); - - newentry->proc = proc; - newentry->creator = creator; - newentry->time = time; - newentry->evttype = evttype; - newentry->tso = tso; - newentry->node = node; - newentry->spark = spark; - newentry->gc_info = 0; - newentry->next = NULL; - - insert_event(newentry); - - IF_DEBUG(gran, - fprintf(stderr, "GRAN: new_event: \n"); - print_event(newentry)); -} - -//@cindex prepend_event -void -prepend_event(event) /* put event at beginning of EventQueue */ -rtsEvent *event; -{ /* only used for GC! */ - event->next = EventHd; - EventHd = event; -} - -//@cindex grab_event -rtsEventQ -grab_event(void) /* undo prepend_event i.e. get the event */ -{ /* at the head of EventQ but don't free anything */ - rtsEventQ event = EventHd; - - if (EventHd == NULL) { - barf("No next event (in grab_event). This may be caused by a circular data dependency in the program."); - } - - EventHd = EventHd->next; - return (event); -} - -//@cindex traverse_eventq_for_gc -void -traverse_eventq_for_gc(void) -{ - rtsEventQ event = EventHd; - StgWord bufsize; - StgClosure *closurep; - StgTSO *tsop; - StgPtr buffer, bufptr; - PEs proc, creator; - - /* Traverse eventq and replace every FETCHREPLY by a FETCHNODE for the - orig closure (root of packed graph). This means that a graph, which is - between processors at the time of GC is fetched again at the time when - it would have arrived, had there been no GC. Slightly inaccurate but - safe for GC. - This is only needed for GUM style fetchng. -- HWL */ - if (!RtsFlags.GranFlags.DoBulkFetching) - return; - - for(event = EventHd; event!=NULL; event=event->next) { - if (event->evttype==FetchReply) { - buffer = stgCast(StgPtr,event->node); - ASSERT(buffer[PACK_FLAG_LOCN]==MAGIC_PACK_FLAG); /* It's a pack buffer */ - bufsize = buffer[PACK_SIZE_LOCN]; - closurep = stgCast(StgClosure*,buffer[PACK_HDR_SIZE]); - tsop = stgCast(StgTSO*,buffer[PACK_TSO_LOCN]); - proc = event->proc; - creator = event->creator; /* similar to unpacking */ - for (bufptr=buffer+PACK_HDR_SIZE; - bufptr<(buffer+bufsize); - bufptr++) { - // if ( (INFO_TYPE(INFO_PTR(*bufptr)) == INFO_SPEC_RBH_TYPE) || - // (INFO_TYPE(INFO_PTR(*bufptr)) == INFO_GEN_RBH_TYPE) ) { - if ( GET_INFO(stgCast(StgClosure*,bufptr)) ) { - convertFromRBH(stgCast(StgClosure *,bufptr)); - } - } - free(buffer); - event->evttype = FetchNode; - event->proc = creator; - event->creator = proc; - event->node = closurep; - event->tso = tsop; - event->gc_info = 0; - } - } -} - -void -markEventQueue(void) -{ - StgClosure *MarkRoot(StgClosure *root); // prototype - - rtsEventQ event = EventHd; - nat len; - - /* iterate over eventq and register relevant fields in event as roots */ - for(event = EventHd, len = 0; event!=NULL; event=event->next, len++) { - switch (event->evttype) { - case ContinueThread: - event->tso = (StgTSO *)MarkRoot((StgClosure *)event->tso); - break; - case StartThread: - event->tso = (StgTSO *)MarkRoot((StgClosure *)event->tso); - event->node = (StgClosure *)MarkRoot((StgClosure *)event->node); - break; - case ResumeThread: - event->tso = (StgTSO *)MarkRoot((StgClosure *)event->tso); - event->node = (StgClosure *)MarkRoot((StgClosure *)event->node); - break; - case MoveSpark: - event->spark->node = (StgClosure *)MarkRoot((StgClosure *)event->spark->node); - break; - case MoveThread: - event->tso = (StgTSO *)MarkRoot((StgClosure *)event->tso); - break; - case FindWork: - break; - case FetchNode: - event->tso = (StgTSO *)MarkRoot((StgClosure *)event->tso); - event->node = (StgClosure *)MarkRoot((StgClosure *)event->node); - break; - case FetchReply: - event->tso = (StgTSO *)MarkRoot((StgClosure *)event->tso); - if (RtsFlags.GranFlags.DoBulkFetching) - // ToDo: traverse_eventw_for_gc if GUM-Fetching!!! HWL - belch("ghuH: packets in BulkFetching not marked as roots; mayb be fatal"); - else - event->node = (StgClosure *)MarkRoot((StgClosure *)event->node); - break; - case GlobalBlock: - event->tso = (StgTSO *)MarkRoot((StgClosure *)event->tso); - event->node = (StgClosure *)MarkRoot((StgClosure *)event->node); - break; - case UnblockThread: - event->tso = (StgTSO *)MarkRoot((StgClosure *)event->tso); - event->node = (StgClosure *)MarkRoot((StgClosure *)event->node); - break; - default: - barf("markEventQueue: trying to mark unknown event @ %p", event); - }} - IF_DEBUG(gc, - belch("GC: markEventQueue: %d events in queue", len)); -} - -/* - Prune all ContinueThread events related to tso or node in the eventq. - Currently used if a thread leaves STG land with ThreadBlocked status, - i.e. it blocked on a closure and has been put on its blocking queue. It - will be reawakended via a call to awakenBlockedQueue. Until then no - event effecting this tso should appear in the eventq. A bit of a hack, - because ideally we shouldn't generate such spurious ContinueThread events - in the first place. -*/ -//@cindex prune_eventq -void -prune_eventq(tso, node) -StgTSO *tso; -StgClosure *node; -{ rtsEventQ prev = (rtsEventQ)NULL, event = EventHd; - - /* node unused for now */ - ASSERT(node==NULL); - /* tso must be valid, then */ - ASSERT(tso!=END_TSO_QUEUE); - while (event != NULL) { - if (event->evttype==ContinueThread && - (event->tso==tso)) { - IF_GRAN_DEBUG(event_trace, // ToDo: use another debug flag - belch("prune_eventq: pruning ContinueThread event for TSO %d (%p) on PE %d @ %lx (%p)", - event->tso->id, event->tso, event->proc, event->time, event)); - if (prev==(rtsEventQ)NULL) { // beginning of eventq - EventHd = event->next; - free(event); - event = EventHd; - } else { - prev->next = event->next; - free(event); - event = prev->next; - } - } else { // no pruning necessary; go to next event - prev = event; - event = event->next; - } - } -} - -//@cindex print_event -void -print_event(event) -rtsEvent *event; -{ - char str_tso[16], str_node[16]; - StgThreadID tso_id; - - if (event->tso==END_TSO_QUEUE) { - strcpy(str_tso, "______"); - tso_id = 0; - } else { - sprintf(str_tso, "%p", event->tso); - tso_id = (event->tso==NULL) ? 0 : event->tso->id; - } - if (event->node==(StgClosure*)NULL) { - strcpy(str_node, "______"); - } else { - sprintf(str_node, "%p", event->node); - } - // HWL: shouldn't be necessary; ToDo: nuke - //str_tso[6]='\0'; - //str_node[6]='\0'; - - if (event==NULL) - fprintf(stderr,"Evt: NIL\n"); - else - fprintf(stderr, "Evt: %s (%u), PE %u [%u], Time %lu, TSO %d (%s), Node %s\n", //"Evt: %s (%u), PE %u [%u], Time %u, TSO %s (%#l), Node %s\n", - event_names[event->evttype], event->evttype, - event->proc, event->creator, event->time, - tso_id, str_tso, str_node - /*, event->spark, event->next */ ); - -} - -//@cindex print_eventq -void -print_eventq(hd) -rtsEvent *hd; -{ - rtsEvent *x; - - fprintf(stderr,"Event Queue with root at %p:\n", hd); - for (x=hd; x!=NULL; x=x->next) { - print_event(x); - } -} - -/* - Spark queue functions are now all in Sparks.c!! -*/ -//@node Scheduling functions, Thread Queue routines, Spark queue functions, GranSim specific code -//@subsection Scheduling functions - -/* - These functions are variants of thread initialisation and therefore - related to initThread and friends in Schedule.c. However, they are - specific to a GranSim setup in storing more info in the TSO's statistics - buffer and sorting the thread queues etc. -*/ - -/* - A large portion of startThread deals with maintaining a sorted thread - queue, which is needed for the Priority Sparking option. Without that - complication the code boils down to FIFO handling. -*/ -//@cindex insertThread -void -insertThread(tso, proc) -StgTSO* tso; -PEs proc; -{ - StgTSO *prev = NULL, *next = NULL; - nat count = 0; - rtsBool found = rtsFalse; - - ASSERT(CurrentProc==proc); - ASSERT(!is_on_queue(tso,proc)); - /* Idle proc: put the thread on the run queue - same for pri spark and basic version */ - if (run_queue_hds[proc] == END_TSO_QUEUE) - { - /* too strong! - ASSERT((CurrentProc==MainProc && - CurrentTime[MainProc]==0 && - procStatus[MainProc]==Idle) || - procStatus[proc]==Starting); - */ - run_queue_hds[proc] = run_queue_tls[proc] = tso; - - CurrentTime[proc] += RtsFlags.GranFlags.Costs.threadqueuetime; - - /* new_event of ContinueThread has been moved to do_the_startthread */ - - /* too strong! - ASSERT(procStatus[proc]==Idle || - procStatus[proc]==Fishing || - procStatus[proc]==Starting); - procStatus[proc] = Busy; - */ - return; - } - - if (RtsFlags.GranFlags.Light) - GranSimLight_insertThread(tso, proc); - - /* Only for Pri Scheduling: find place where to insert tso into queue */ - if (RtsFlags.GranFlags.DoPriorityScheduling && tso->gran.pri!=0) - /* {add_to_spark_queue}vo' jInIHta'; Qu' wa'DIch yIleghQo' */ - for (prev = run_queue_hds[proc], next = run_queue_hds[proc]->link, count=0; - (next != END_TSO_QUEUE) && - !(found = tso->gran.pri >= next->gran.pri); - prev = next, next = next->link, count++) - { - ASSERT((prev!=(StgTSO*)NULL || next==run_queue_hds[proc]) && - (prev==(StgTSO*)NULL || prev->link==next)); - } - - ASSERT(!found || next != END_TSO_QUEUE); - ASSERT(procStatus[proc]!=Idle); - - if (found) { - /* found can only be rtsTrue if pri scheduling enabled */ - ASSERT(RtsFlags.GranFlags.DoPriorityScheduling); - if (RtsFlags.GranFlags.GranSimStats.Global) - globalGranStats.non_end_add_threads++; - /* Add tso to ThreadQueue between prev and next */ - tso->link = next; - if ( next == (StgTSO*)END_TSO_QUEUE ) { - run_queue_tl = tso; - } else { - /* no back link for TSO chain */ - } - - if ( prev == (StgTSO*)END_TSO_QUEUE ) { - /* Never add TSO as first elem of thread queue; the first */ - /* element should be the one that is currently running -- HWL */ - IF_DEBUG(gran, - belch("GRAN: Qagh: NewThread (w/ PriorityScheduling): Trying to add TSO %p (PRI=%d) as first elem of threadQ (%p) on proc %u (@ %u)\n", - tso, tso->gran.pri, run_queue_hd, proc, - CurrentTime[proc])); - } else { - prev->link = tso; - } - } else { /* !found */ /* or not pri sparking! */ - /* Add TSO to the end of the thread queue on that processor */ - run_queue_tls[proc]->link = tso; - run_queue_tls[proc] = tso; - } - ASSERT(RtsFlags.GranFlags.DoPriorityScheduling || count==0); - CurrentTime[proc] += count * RtsFlags.GranFlags.Costs.pri_sched_overhead + - RtsFlags.GranFlags.Costs.threadqueuetime; - - /* ToDo: check if this is still needed -- HWL - if (RtsFlags.GranFlags.DoThreadMigration) - ++SurplusThreads; - - if (RtsFlags.GranFlags.GranSimStats.Full && - !(( event_type == GR_START || event_type == GR_STARTQ) && - RtsFlags.GranFlags.labelling) ) - DumpRawGranEvent(proc, creator, event_type+1, tso, node, - tso->gran.sparkname, spark_queue_len(proc)); - */ - -# if defined(GRAN_CHECK) - /* Check if thread queue is sorted. Only for testing, really! HWL */ - if ( RtsFlags.GranFlags.DoPriorityScheduling && - (RtsFlags.GranFlags.Debug.sortedQ) ) { - rtsBool sorted = rtsTrue; - StgTSO *prev, *next; - - if (run_queue_hds[proc]==END_TSO_QUEUE || - run_queue_hds[proc]->link==END_TSO_QUEUE) { - /* just 1 elem => ok */ - } else { - /* Qu' wa'DIch yIleghQo' (ignore first elem)! */ - for (prev = run_queue_hds[proc]->link, next = prev->link; - (next != END_TSO_QUEUE) ; - prev = next, next = prev->link) { - ASSERT((prev!=(StgTSO*)NULL || next==run_queue_hds[proc]) && - (prev==(StgTSO*)NULL || prev->link==next)); - sorted = sorted && - (prev->gran.pri >= next->gran.pri); - } - } - if (!sorted) { - fprintf(stderr,"Qagh: THREADQ on PE %d is not sorted:\n", - CurrentProc); - G_THREADQ(run_queue_hd,0x1); - } - } -# endif -} - -/* - insertThread, which is only used for GranSim Light, is similar to - startThread in that it adds a TSO to a thread queue. However, it assumes - that the thread queue is sorted by local clocks and it inserts the TSO at - the right place in the queue. Don't create any event, just insert. -*/ -//@cindex GranSimLight_insertThread -rtsBool -GranSimLight_insertThread(tso, proc) -StgTSO* tso; -PEs proc; -{ - StgTSO *prev, *next; - nat count = 0; - rtsBool found = rtsFalse; - - ASSERT(RtsFlags.GranFlags.Light); - - /* In GrAnSim-Light we always have an idle `virtual' proc. - The semantics of the one-and-only thread queue is different here: - all threads in the queue are running (each on its own virtual processor); - the queue is only needed internally in the simulator to interleave the - reductions of the different processors. - The one-and-only thread queue is sorted by the local clocks of the TSOs. - */ - ASSERT(run_queue_hds[proc] != END_TSO_QUEUE); - ASSERT(tso->link == END_TSO_QUEUE); - - /* If only one thread in queue so far we emit DESCHEDULE in debug mode */ - if (RtsFlags.GranFlags.GranSimStats.Full && - (RtsFlags.GranFlags.Debug.checkLight) && - (run_queue_hd->link == END_TSO_QUEUE)) { - DumpRawGranEvent(proc, proc, GR_DESCHEDULE, - run_queue_hds[proc], (StgClosure*)NULL, - tso->gran.sparkname, spark_queue_len(proc)); // ToDo: check spar_queue_len - // resched = rtsTrue; - } - - /* this routine should only be used in a GrAnSim Light setup */ - /* && CurrentProc must be 0 in GrAnSim Light setup */ - ASSERT(RtsFlags.GranFlags.Light && CurrentProc==0); - - /* Idle proc; same for pri spark and basic version */ - if (run_queue_hd==END_TSO_QUEUE) - { - run_queue_hd = run_queue_tl = tso; - /* MAKE_BUSY(CurrentProc); */ - return rtsTrue; - } - - for (prev = run_queue_hds[proc], next = run_queue_hds[proc]->link, count = 0; - (next != END_TSO_QUEUE) && - !(found = (tso->gran.clock < next->gran.clock)); - prev = next, next = next->link, count++) - { - ASSERT((prev!=(StgTSO*)NULL || next==run_queue_hds[proc]) && - (prev==(StgTSO*)NULL || prev->link==next)); - } - - /* found can only be rtsTrue if pri sparking enabled */ - if (found) { - /* Add tso to ThreadQueue between prev and next */ - tso->link = next; - if ( next == END_TSO_QUEUE ) { - run_queue_tls[proc] = tso; - } else { - /* no back link for TSO chain */ - } - - if ( prev == END_TSO_QUEUE ) { - run_queue_hds[proc] = tso; - } else { - prev->link = tso; - } - } else { /* !found */ /* or not pri sparking! */ - /* Add TSO to the end of the thread queue on that processor */ - run_queue_tls[proc]->link = tso; - run_queue_tls[proc] = tso; - } - - if ( prev == END_TSO_QUEUE ) { /* new head of queue */ - new_event(proc, proc, CurrentTime[proc], - ContinueThread, - tso, (StgClosure*)NULL, (rtsSpark*)NULL); - } - /* - if (RtsFlags.GranFlags.GranSimStats.Full && - !(( event_type == GR_START || event_type == GR_STARTQ) && - RtsFlags.GranFlags.labelling) ) - DumpRawGranEvent(proc, creator, gr_evttype, tso, node, - tso->gran.sparkname, spark_queue_len(proc)); - */ - return rtsTrue; -} - -/* - endThread is responsible for general clean-up after the thread tso has - finished. This includes emitting statistics into the profile etc. -*/ -void -endThread(StgTSO *tso, PEs proc) -{ - ASSERT(procStatus[proc]==Busy); // coming straight out of STG land - ASSERT(tso->what_next==ThreadComplete); - // ToDo: prune ContinueThreads for this TSO from event queue - DumpEndEvent(proc, tso, rtsFalse /* not mandatory */); - - /* if this was the last thread on this PE then make it Idle */ - if (run_queue_hds[proc]==END_TSO_QUEUE) { - procStatus[CurrentProc] = Idle; - } -} - -//@node Thread Queue routines, GranSim functions, Scheduling functions, GranSim specific code -//@subsection Thread Queue routines - -/* - Check whether given tso resides on the run queue of the current processor. - Only used for debugging. -*/ - -//@cindex is_on_queue -rtsBool -is_on_queue (StgTSO *tso, PEs proc) -{ - StgTSO *t; - rtsBool found; - - for (t=run_queue_hds[proc], found=rtsFalse; - t!=END_TSO_QUEUE && !(found = t==tso); - t=t->link) - /* nothing */ ; - - return found; -} - -/* This routine is only used for keeping a statistics of thread queue - lengths to evaluate the impact of priority scheduling. -- HWL - {spark_queue_len}vo' jInIHta' -*/ -//@cindex thread_queue_len -nat -thread_queue_len(PEs proc) -{ - StgTSO *prev, *next; - nat len; - - for (len = 0, prev = END_TSO_QUEUE, next = run_queue_hds[proc]; - next != END_TSO_QUEUE; - len++, prev = next, next = prev->link) - {} - - return (len); -} - -//@node GranSim functions, GranSimLight routines, Thread Queue routines, GranSim specific code -//@subsection GranSim functions - -/* ----------------------------------------------------------------- */ -/* The main event handling functions; called from Schedule.c (schedule) */ -/* ----------------------------------------------------------------- */ - -//@cindex do_the_globalblock - -void -do_the_globalblock(rtsEvent* event) -{ - PEs proc = event->proc; /* proc that requested node */ - StgTSO *tso = event->tso; /* tso that requested node */ - StgClosure *node = event->node; /* requested, remote node */ - - IF_DEBUG(gran, fprintf(stderr, "GRAN: doing the GlobalBlock\n")); - /* There should be no GLOBALBLOCKs in GrAnSim Light setup */ - ASSERT(!RtsFlags.GranFlags.Light); - /* GlobalBlock events only valid with GUM fetching */ - ASSERT(RtsFlags.GranFlags.DoBulkFetching); - - IF_GRAN_DEBUG(bq, // globalBlock, - if (IS_LOCAL_TO(PROCS(node),proc)) { - belch("## Qagh: GlobalBlock: Blocking TSO %d (%p) on LOCAL node %p (PE %d).\n", - tso->id, tso, node, proc); - }); - - /* CurrentTime[CurrentProc] += RtsFlags.GranFlags.Costs.munpacktime; */ - if ( blockFetch(tso,proc,node) != 0 ) - return; /* node has become local by now */ - -#if 0 - ToDo: check whether anything has to be done at all after blockFetch -- HWL - - if (!RtsFlags.GranFlags.DoAsyncFetch) { /* head of queue is next thread */ - StgTSO* tso = run_queue_hds[proc]; /* awaken next thread */ - if (tso != (StgTSO*)NULL) { - new_event(proc, proc, CurrentTime[proc], - ContinueThread, - tso, (StgClosure*)NULL, (rtsSpark*)NULL); - CurrentTime[proc] += RtsFlags.GranFlags.Costs.threadcontextswitchtime; - if (RtsFlags.GranFlags.GranSimStats.Full) - DumpRawGranEvent(proc, CurrentProc, GR_SCHEDULE, tso, - (StgClosure*)NULL, tso->gran.sparkname, spark_queue_len(CurrentProc)); // ToDo: check sparkname and spar_queue_len - procStatus[proc] = Busy; /* might have been fetching */ - } else { - procStatus[proc] = Idle; /* no work on proc now */ - } - } else { /* RtsFlags.GranFlags.DoAsyncFetch i.e. block-on-fetch */ - /* other thread is already running */ - /* 'oH 'utbe' 'e' vIHar ; I think that's not needed -- HWL - new_event(proc,proc,CurrentTime[proc], - CONTINUETHREAD,EVENT_TSO(event), - (RtsFlags.GranFlags.DoBulkFetching ? closure : - EVENT_NODE(event)),NULL); - */ - } -#endif -} - -//@cindex do_the_unblock - -void -do_the_unblock(rtsEvent* event) -{ - PEs proc = event->proc, /* proc that requested node */ - creator = event->creator; /* proc that requested node */ - StgTSO* tso = event->tso; /* tso that requested node */ - StgClosure* node = event->node; /* requested, remote node */ - - IF_DEBUG(gran, fprintf(stderr, "GRAN: doing the UnBlock\n")) - /* There should be no UNBLOCKs in GrAnSim Light setup */ - ASSERT(!RtsFlags.GranFlags.Light); - /* UnblockThread means either FetchReply has arrived or - a blocking queue has been awakened; - ToDo: check with assertions - ASSERT(procStatus[proc]==Fetching || IS_BLACK_HOLE(event->node)); - */ - if (!RtsFlags.GranFlags.DoAsyncFetch) { /* block-on-fetch */ - /* We count block-on-fetch as normal block time */ - tso->gran.blocktime += CurrentTime[proc] - tso->gran.blockedat; - /* Dumping now done when processing the event - No costs for contextswitch or thread queueing in this case - if (RtsFlags.GranFlags.GranSimStats.Full) - DumpRawGranEvent(proc, CurrentProc, GR_RESUME, tso, - (StgClosure*)NULL, tso->gran.sparkname, spark_queue_len(CurrentProc)); - */ - /* Maybe do this in FetchReply already - if (procStatus[proc]==Fetching) - procStatus[proc] = Busy; - */ - /* - new_event(proc, proc, CurrentTime[proc], - ContinueThread, - tso, node, (rtsSpark*)NULL); - */ - } else { - /* Asynchr comm causes additional costs here: */ - /* Bring the TSO from the blocked queue into the threadq */ - } - /* In all cases, the UnblockThread causes a ResumeThread to be scheduled */ - new_event(proc, proc, - CurrentTime[proc]+RtsFlags.GranFlags.Costs.threadqueuetime, - ResumeThread, - tso, node, (rtsSpark*)NULL); -} - -//@cindex do_the_fetchnode - -void -do_the_fetchnode(rtsEvent* event) -{ - PEs proc = event->proc, /* proc that holds the requested node */ - creator = event->creator; /* proc that requested node */ - StgTSO* tso = event->tso; - StgClosure* node = event->node; /* requested, remote node */ - rtsFetchReturnCode rc; - - ASSERT(CurrentProc==proc); - /* There should be no FETCHNODEs in GrAnSim Light setup */ - ASSERT(!RtsFlags.GranFlags.Light); - - IF_DEBUG(gran, fprintf(stderr, "GRAN: doing the FetchNode\n")); - - CurrentTime[proc] += RtsFlags.GranFlags.Costs.munpacktime; - - /* ToDo: check whether this is the right place for dumping the event */ - if (RtsFlags.GranFlags.GranSimStats.Full) - DumpRawGranEvent(creator, proc, GR_FETCH, tso, node, (StgInt)0, 0); - - do { - rc = handleFetchRequest(node, proc, creator, tso); - if (rc == OutOfHeap) { /* trigger GC */ -# if defined(GRAN_CHECK) && defined(GRAN) - if (RtsFlags.GcFlags.giveStats) - fprintf(RtsFlags.GcFlags.statsFile,"***** veQ boSwI' PackNearbyGraph(node %p, tso %p (%d))\n", - node, tso, tso->id); -# endif - barf("//// do_the_fetchnode: out of heap after handleFetchRequest; ToDo: call GarbageCollect()"); - prepend_event(event); - GarbageCollect(GetRoots, rtsFalse); - // HWL: ToDo: check whether a ContinueThread has to be issued - // HWL old: ReallyPerformThreadGC(PACK_HEAP_REQUIRED, rtsFalse); -# if 0 && defined(GRAN_CHECK) && defined(GRAN) - if (RtsFlags.GcFlags.giveStats) { - fprintf(RtsFlags.GcFlags.statsFile,"***** SAVE_Hp=%p, SAVE_HpLim=%p, PACK_HEAP_REQUIRED=%d\n", - Hp, HpLim, 0) ; // PACK_HEAP_REQUIRED); ??? - fprintf(stderr,"***** No. of packets so far: %d (total size: %d)\n", - globalGranStats.tot_packets, globalGranStats.tot_packet_size); - } -# endif - event = grab_event(); - // Hp -= PACK_HEAP_REQUIRED; // ??? - - /* GC knows that events are special and follows the pointer i.e. */ - /* events are valid even if they moved. An EXIT is triggered */ - /* if there is not enough heap after GC. */ - } - } while (rc == OutOfHeap); -} - -//@cindex do_the_fetchreply -void -do_the_fetchreply(rtsEvent* event) -{ - PEs proc = event->proc, /* proc that requested node */ - creator = event->creator; /* proc that holds the requested node */ - StgTSO* tso = event->tso; - StgClosure* node = event->node; /* requested, remote node */ - StgClosure* closure=(StgClosure*)NULL; - - ASSERT(CurrentProc==proc); - ASSERT(RtsFlags.GranFlags.DoAsyncFetch || procStatus[proc]==Fetching); - - IF_DEBUG(gran, fprintf(stderr, "GRAN: doing the FetchReply\n")); - /* There should be no FETCHREPLYs in GrAnSim Light setup */ - ASSERT(!RtsFlags.GranFlags.Light); - - /* assign message unpack costs *before* dumping the event */ - CurrentTime[proc] += RtsFlags.GranFlags.Costs.munpacktime; - - /* ToDo: check whether this is the right place for dumping the event */ - if (RtsFlags.GranFlags.GranSimStats.Full) - DumpRawGranEvent(proc, creator, GR_REPLY, tso, node, - tso->gran.sparkname, spark_queue_len(proc)); - - /* THIS SHOULD NEVER HAPPEN - If tso is in the BQ of node this means that it actually entered the - remote closure, due to a missing GranSimFetch at the beginning of the - entry code; therefore, this is actually a faked fetch, triggered from - within GranSimBlock; - since tso is both in the EVQ and the BQ for node, we have to take it out - of the BQ first before we can handle the FetchReply; - ToDo: special cases in awakenBlockedQueue, since the BQ magically moved. - */ - if (tso->block_info.closure!=(StgClosure*)NULL) { - IF_GRAN_DEBUG(bq, - belch("## ghuH: TSO %d (%p) in FetchReply is blocked on node %p (shouldn't happen AFAIK)", - tso->id, tso, node)); - // unlink_from_bq(tso, node); - } - - if (RtsFlags.GranFlags.DoBulkFetching) { /* bulk (packet) fetching */ - rtsPackBuffer *buffer = (rtsPackBuffer*)node; - nat size = buffer->size; - - /* NB: Fetch misses can't occur with GUM fetching, as */ - /* updatable closure are turned into RBHs and therefore locked */ - /* for other processors that try to grab them. */ - - closure = UnpackGraph(buffer); - CurrentTime[proc] += size * RtsFlags.GranFlags.Costs.munpacktime; - } else // incremental fetching - /* Copy or move node to CurrentProc */ - if (fetchNode(node, creator, proc)) { - /* Fetch has failed i.e. node has been grabbed by another PE */ - PEs p = where_is(node); - rtsTime fetchtime; - - if (RtsFlags.GranFlags.GranSimStats.Global) - globalGranStats.fetch_misses++; - - IF_GRAN_DEBUG(thunkStealing, - belch("== Qu'vatlh! fetch miss @ %u: node %p is at proc %u (rather than proc %u)\n", - CurrentTime[proc],node,p,creator)); - - CurrentTime[CurrentProc] += RtsFlags.GranFlags.Costs.mpacktime; - - /* Count fetch again !? */ - ++(tso->gran.fetchcount); - tso->gran.fetchtime += RtsFlags.GranFlags.Costs.fetchtime; - - fetchtime = stg_max(CurrentTime[CurrentProc],CurrentTime[p]) + - RtsFlags.GranFlags.Costs.latency; - - /* Chase the grabbed node */ - new_event(p, proc, fetchtime, - FetchNode, - tso, node, (rtsSpark*)NULL); - -# if 0 && defined(GRAN_CHECK) && defined(GRAN) /* Just for testing */ - IF_GRAN_DEBUG(blockOnFetch, - BlockedOnFetch[CurrentProc] = tso;) /*-rtsTrue;-*/ - - IF_GRAN_DEBUG(blockOnFetch_sanity, - tso->type |= FETCH_MASK_TSO;) -# endif - - CurrentTime[proc] += RtsFlags.GranFlags.Costs.mtidytime; - - return; /* NB: no REPLy has been processed; tso still sleeping */ - } - - /* -- Qapla'! Fetch has been successful; node is here, now */ - ++(event->tso->gran.fetchcount); - event->tso->gran.fetchtime += RtsFlags.GranFlags.Costs.fetchtime; - - /* this is now done at the beginning of this routine - if (RtsFlags.GranFlags.GranSimStats.Full) - DumpRawGranEvent(proc,event->creator, GR_REPLY, event->tso, - (RtsFlags.GranFlags.DoBulkFetching ? - closure : - event->node), - tso->gran.sparkname, spark_queue_len(proc)); - */ - - ASSERT(OutstandingFetches[proc] > 0); - --OutstandingFetches[proc]; - new_event(proc, proc, CurrentTime[proc], - ResumeThread, - event->tso, (RtsFlags.GranFlags.DoBulkFetching ? - closure : - event->node), - (rtsSpark*)NULL); -} - -//@cindex do_the_movethread - -void -do_the_movethread(rtsEvent* event) { - PEs proc = event->proc, /* proc that requested node */ - creator = event->creator; /* proc that holds the requested node */ - StgTSO* tso = event->tso; - - IF_DEBUG(gran, fprintf(stderr, "GRAN: doing the MoveThread\n")); - - ASSERT(CurrentProc==proc); - /* There should be no MOVETHREADs in GrAnSim Light setup */ - ASSERT(!RtsFlags.GranFlags.Light); - /* MOVETHREAD events should never occur without -bM */ - ASSERT(RtsFlags.GranFlags.DoThreadMigration); - /* Bitmask of moved thread should be 0 */ - ASSERT(PROCS(tso)==0); - ASSERT(procStatus[proc] == Fishing || - RtsFlags.GranFlags.DoAsyncFetch); - ASSERT(OutstandingFishes[proc]>0); - - /* ToDo: exact costs for unpacking the whole TSO */ - CurrentTime[proc] += 5l * RtsFlags.GranFlags.Costs.munpacktime; - - /* ToDo: check whether this is the right place for dumping the event */ - if (RtsFlags.GranFlags.GranSimStats.Full) - DumpRawGranEvent(proc, creator, - GR_STOLEN, tso, (StgClosure*)NULL, (StgInt)0, 0); - - // ToDo: check cost functions - --OutstandingFishes[proc]; - SET_GRAN_HDR(tso, ThisPE); // adjust the bitmask for the TSO - insertThread(tso, proc); - - if (procStatus[proc]==Fishing) - procStatus[proc] = Idle; - - if (RtsFlags.GranFlags.GranSimStats.Global) - globalGranStats.tot_TSOs_migrated++; -} - -//@cindex do_the_movespark - -void -do_the_movespark(rtsEvent* event) { - PEs proc = event->proc, /* proc that requested spark */ - creator = event->creator; /* proc that holds the requested spark */ - StgTSO* tso = event->tso; - rtsSparkQ spark = event->spark; - - IF_DEBUG(gran, fprintf(stderr, "GRAN: doing the MoveSpark\n")) - - ASSERT(CurrentProc==proc); - ASSERT(spark!=NULL); - ASSERT(procStatus[proc] == Fishing || - RtsFlags.GranFlags.DoAsyncFetch); - ASSERT(OutstandingFishes[proc]>0); - - CurrentTime[proc] += RtsFlags.GranFlags.Costs.munpacktime; - - /* record movement of spark only if spark profiling is turned on */ - if (RtsFlags.GranFlags.GranSimStats.Sparks) - DumpRawGranEvent(proc, creator, - SP_ACQUIRED, - tso, spark->node, spark->name, spark_queue_len(proc)); - - /* global statistics */ - if ( RtsFlags.GranFlags.GranSimStats.Global && - !closure_SHOULD_SPARK(spark->node)) - globalGranStats.withered_sparks++; - /* Not adding the spark to the spark queue would be the right */ - /* thing here, but it also would be cheating, as this info can't be */ - /* available in a real system. -- HWL */ - - --OutstandingFishes[proc]; - - add_to_spark_queue(spark); - - IF_GRAN_DEBUG(randomSteal, // ToDo: spark-distribution flag - print_sparkq_stats()); - - /* Should we treat stolen sparks specially? Currently, we don't. */ - - if (procStatus[proc]==Fishing) - procStatus[proc] = Idle; - - /* add_to_spark_queue will increase the time of the current proc. */ - /* - If proc was fishing, it is Idle now with the new spark in its spark - pool. This means that the next time handleIdlePEs is called, a local - FindWork will be created on this PE to turn the spark into a thread. Of - course another PE might steal the spark in the meantime (that's why we - are using events rather than inlining all the operations in the first - place). */ -} - -/* - In the Constellation class version of GranSim the semantics of StarThread - events has changed. Now, StartThread has to perform 3 basic operations: - - create a new thread (previously this was done in ActivateSpark); - - insert the thread into the run queue of the current processor - - generate a new event for actually running the new thread - Note that the insertThread is called via createThread. -*/ - -//@cindex do_the_startthread - -void -do_the_startthread(rtsEvent *event) -{ - PEs proc = event->proc; /* proc that requested node */ - StgTSO *tso = event->tso; /* tso that requested node */ - StgClosure *node = event->node; /* requested, remote node */ - rtsSpark *spark = event->spark; - GranEventType gr_evttype; - - ASSERT(CurrentProc==proc); - ASSERT(!RtsFlags.GranFlags.Light || CurrentProc==0); - ASSERT(event->evttype == ResumeThread || event->evttype == StartThread); - /* if this was called via StartThread: */ - ASSERT(event->evttype!=StartThread || tso == END_TSO_QUEUE); // not yet created - // ToDo: check: ASSERT(event->evttype!=StartThread || procStatus[proc]==Starting); - /* if this was called via ResumeThread: */ - ASSERT(event->evttype!=ResumeThread || - RtsFlags.GranFlags.DoAsyncFetch ||!is_on_queue(tso,proc)); - - /* startThread may have been called from the main event handler upon - finding either a ResumeThread or a StartThread event; set the - gr_evttype (needed for writing to .gr file) accordingly */ - // gr_evttype = (event->evttype == ResumeThread) ? GR_RESUME : GR_START; - - if ( event->evttype == StartThread ) { - GranEventType gr_evttype = (run_queue_hds[proc]==END_TSO_QUEUE) ? - GR_START : GR_STARTQ; - - tso = createThread(BLOCK_SIZE_W, spark->gran_info);// implicit insertThread! - pushClosure(tso, node); - - // ToDo: fwd info on local/global spark to thread -- HWL - // tso->gran.exported = spark->exported; - // tso->gran.locked = !spark->global; - tso->gran.sparkname = spark->name; - - ASSERT(CurrentProc==proc); - if (RtsFlags.GranFlags.GranSimStats.Full) - DumpGranEvent(gr_evttype,tso); - - CurrentTime[proc] += RtsFlags.GranFlags.Costs.threadcreatetime; - } else { // event->evttype == ResumeThread - GranEventType gr_evttype = (run_queue_hds[proc]==END_TSO_QUEUE) ? - GR_RESUME : GR_RESUMEQ; - - insertThread(tso, proc); - - ASSERT(CurrentProc==proc); - if (RtsFlags.GranFlags.GranSimStats.Full) - DumpGranEvent(gr_evttype,tso); - } - - ASSERT(run_queue_hds[proc]!=END_TSO_QUEUE); // non-empty run queue - procStatus[proc] = Busy; - /* make sure that this thread is actually run */ - new_event(proc, proc, - CurrentTime[proc], - ContinueThread, - tso, node, (rtsSpark*)NULL); - - /* A wee bit of statistics gathering */ - if (RtsFlags.GranFlags.GranSimStats.Global) { - globalGranStats.tot_add_threads++; - globalGranStats.tot_tq_len += thread_queue_len(CurrentProc); - } - -} - -//@cindex do_the_findwork -void -do_the_findwork(rtsEvent* event) -{ - PEs proc = event->proc, /* proc to search for work */ - creator = event->creator; /* proc that requested work */ - rtsSparkQ spark = event->spark; - /* ToDo: check that this size is safe -- HWL */ -#if 0 - ToDo: check available heap - - nat req_heap = sizeofW(StgTSO) + MIN_STACK_WORDS; - // add this? -- HWL:RtsFlags.ConcFlags.stkChunkSize; -#endif - - IF_DEBUG(gran, fprintf(stderr, "GRAN: doing the Findwork\n")); - - /* If GUM style fishing is enabled, the contents of the spark field says - what to steal (spark(1) or thread(2)); */ - ASSERT(!(RtsFlags.GranFlags.Fishing && event->spark==(rtsSpark*)0)); - - /* Make sure that we have enough heap for creating a new - thread. This is a conservative estimate of the required heap. - This eliminates special checks for GC around NewThread within - ActivateSpark. */ - -#if 0 - ToDo: check available heap - - if (Hp + req_heap > HpLim ) { - IF_DEBUG(gc, - belch("GC: Doing GC from within Findwork handling (that's bloody dangerous if you ask me)");) - GarbageCollect(GetRoots); - // ReallyPerformThreadGC(req_heap, rtsFalse); old -- HWL - Hp -= req_heap; - if (procStatus[CurrentProc]==Sparking) - procStatus[CurrentProc]=Idle; - return; - } -#endif - - if ( RtsFlags.GranFlags.DoAlwaysCreateThreads || - RtsFlags.GranFlags.Fishing || - ((procStatus[proc]==Idle || procStatus[proc]==Sparking) && - (RtsFlags.GranFlags.FetchStrategy >= 2 || - OutstandingFetches[proc] == 0)) ) - { - rtsBool found; - rtsSparkQ prev, spark; - - /* ToDo: check */ - ASSERT(procStatus[proc]==Sparking || - RtsFlags.GranFlags.DoAlwaysCreateThreads || - RtsFlags.GranFlags.Fishing); - - /* SImmoHwI' yInej! Search spark queue! */ - /* gimme_spark (event, &found, &spark); */ - findLocalSpark(event, &found, &spark); - - if (!found) { /* pagh vumwI' */ - /* - If no spark has been found this can mean 2 things: - 1/ The FindWork was a fish (i.e. a message sent by another PE) and - the spark pool of the receiver is empty - --> the fish has to be forwarded to another PE - 2/ The FindWork was local to this PE (i.e. no communication; in this - case creator==proc) and the spark pool of the PE is not empty - contains only sparks of closures that should not be sparked - (note: if the spark pool were empty, handleIdlePEs wouldn't have - generated a FindWork in the first place) - --> the PE has to be made idle to trigger stealing sparks the next - time handleIdlePEs is performed - */ - - ASSERT(pending_sparks_hds[proc]==(rtsSpark*)NULL); - if (creator==proc) { - /* local FindWork */ - if (procStatus[proc]==Busy) { - belch("ghuH: PE %d in Busy state while processing local FindWork (spark pool is empty!) @ %lx", - proc, CurrentTime[proc]); - procStatus[proc] = Idle; - } - } else { - /* global FindWork i.e. a Fish */ - ASSERT(RtsFlags.GranFlags.Fishing); - /* actually this generates another request from the originating PE */ - ASSERT(OutstandingFishes[creator]>0); - OutstandingFishes[creator]--; - /* ToDo: assign costs for sending fish to proc not to creator */ - stealSpark(creator); /* might steal from same PE; ToDo: fix */ - ASSERT(RtsFlags.GranFlags.maxFishes!=1 || procStatus[creator] == Fishing); - /* any assertions on state of proc possible here? */ - } - } else { - /* DaH chu' Qu' yIchen! Now create new work! */ - IF_GRAN_DEBUG(findWork, - belch("+- munching spark %p; creating thread for node %p", - spark, spark->node)); - activateSpark (event, spark); - ASSERT(spark != (rtsSpark*)NULL); - spark = delete_from_sparkq (spark, proc, rtsTrue); - } - - IF_GRAN_DEBUG(findWork, - belch("+- Contents of spark queues at the end of FindWork @ %lx", - CurrentTime[proc]); - print_sparkq_stats()); - - /* ToDo: check ; not valid if GC occurs in ActivateSpark */ - ASSERT(!found || - /* forward fish or */ - (proc!=creator || - /* local spark or */ - (proc==creator && procStatus[proc]==Starting)) || - //(!found && procStatus[proc]==Idle) || - RtsFlags.GranFlags.DoAlwaysCreateThreads); - } else { - IF_GRAN_DEBUG(findWork, - belch("+- RTS refuses to findWork on PE %d @ %lx", - proc, CurrentTime[proc]); - belch(" procStatus[%d]=%s, fetch strategy=%d, outstanding fetches[%d]=%d", - proc, proc_status_names[procStatus[proc]], - RtsFlags.GranFlags.FetchStrategy, - proc, OutstandingFetches[proc])); - } -} - -//@node GranSimLight routines, Code for Fetching Nodes, GranSim functions, GranSim specific code -//@subsection GranSimLight routines - -/* - This code is called from the central scheduler after having rgabbed a - new event and is only needed for GranSim-Light. It mainly adjusts the - ActiveTSO so that all costs that have to be assigned from within the - scheduler are assigned to the right TSO. The choice of ActiveTSO depends - on the type of event that has been found. -*/ - -void -GranSimLight_enter_system(event, ActiveTSOp) -rtsEvent *event; -StgTSO **ActiveTSOp; -{ - StgTSO *ActiveTSO = *ActiveTSOp; - - ASSERT (RtsFlags.GranFlags.Light); - - /* Restore local clock of the virtual processor attached to CurrentTSO. - All costs will be associated to the `virt. proc' on which the tso - is living. */ - if (ActiveTSO != NULL) { /* already in system area */ - ActiveTSO->gran.clock = CurrentTime[CurrentProc]; - if (RtsFlags.GranFlags.DoFairSchedule) - { - if (RtsFlags.GranFlags.GranSimStats.Full && - RtsFlags.GranFlags.Debug.checkLight) - DumpGranEvent(GR_SYSTEM_END,ActiveTSO); - } - } - switch (event->evttype) - { - case ContinueThread: - case FindWork: /* inaccurate this way */ - ActiveTSO = run_queue_hd; - break; - case ResumeThread: - case StartThread: - case MoveSpark: /* has tso of virt proc in tso field of event */ - ActiveTSO = event->tso; - break; - default: barf("Illegal event type %s (%d) in GrAnSim Light setup\n", - event_names[event->evttype],event->evttype); - } - CurrentTime[CurrentProc] = ActiveTSO->gran.clock; - if (RtsFlags.GranFlags.DoFairSchedule) { - if (RtsFlags.GranFlags.GranSimStats.Full && - RtsFlags.GranFlags.Debug.checkLight) - DumpGranEvent(GR_SYSTEM_START,ActiveTSO); - } -} - -void -GranSimLight_leave_system(event, ActiveTSOp) -rtsEvent *event; -StgTSO **ActiveTSOp; -{ - StgTSO *ActiveTSO = *ActiveTSOp; - - ASSERT(RtsFlags.GranFlags.Light); - - /* Save time of `virt. proc' which was active since last getevent and - restore time of `virt. proc' where CurrentTSO is living on. */ - if(RtsFlags.GranFlags.DoFairSchedule) { - if (RtsFlags.GranFlags.GranSimStats.Full && - RtsFlags.GranFlags.Debug.checkLight) // ToDo: clean up flags - DumpGranEvent(GR_SYSTEM_END,ActiveTSO); - } - ActiveTSO->gran.clock = CurrentTime[CurrentProc]; - ActiveTSO = (StgTSO*)NULL; - CurrentTime[CurrentProc] = CurrentTSO->gran.clock; - if (RtsFlags.GranFlags.DoFairSchedule /* && resched */ ) { - // resched = rtsFalse; - if (RtsFlags.GranFlags.GranSimStats.Full && - RtsFlags.GranFlags.Debug.checkLight) - DumpGranEvent(GR_SCHEDULE,run_queue_hd); - } - /* - if (TSO_LINK(ThreadQueueHd)!=PrelBase_Z91Z93_closure && - (TimeOfNextEvent == 0 || - TSO_CLOCK(TSO_LINK(ThreadQueueHd))+1000<TimeOfNextEvent)) { - new_event(CurrentProc,CurrentProc,TSO_CLOCK(TSO_LINK(ThreadQueueHd))+1000, - CONTINUETHREAD,TSO_LINK(ThreadQueueHd),PrelBase_Z91Z93_closure,NULL); - TimeOfNextEvent = get_time_of_next_event(); - } - */ -} - -//@node Code for Fetching Nodes, Idle PEs, GranSimLight routines, GranSim specific code -//@subsection Code for Fetching Nodes - -/* - The following GrAnSim routines simulate the fetching of nodes from a - remote processor. We use a 1 word bitmask to indicate on which processor - a node is lying. Thus, moving or copying a node from one processor to - another just requires an appropriate change in this bitmask (using - @SET_GA@). Additionally, the clocks have to be updated. - - A special case arises when the node that is needed by processor A has - been moved from a processor B to a processor C between sending out a - @FETCH@ (from A) and its arrival at B. In that case the @FETCH@ has to - be forwarded to C. This is simulated by issuing another FetchNode event - on processor C with A as creator. -*/ - -/* ngoqvam che' {GrAnSim}! */ - -/* Fetch node "node" to processor "p" */ - -//@cindex fetchNode - -rtsFetchReturnCode -fetchNode(node,from,to) -StgClosure* node; -PEs from, to; -{ - /* In case of RtsFlags.GranFlags.DoBulkFetching this fct should never be - entered! Instead, UnpackGraph is used in ReSchedule */ - StgClosure* closure; - - ASSERT(to==CurrentProc); - /* Should never be entered in GrAnSim Light setup */ - ASSERT(!RtsFlags.GranFlags.Light); - /* fetchNode should never be entered with DoBulkFetching */ - ASSERT(!RtsFlags.GranFlags.DoBulkFetching); - - /* Now fetch the node */ - if (!IS_LOCAL_TO(PROCS(node),from) && - !IS_LOCAL_TO(PROCS(node),to) ) - return NodeHasMoved; - - if (closure_HNF(node)) /* node already in head normal form? */ - node->header.gran.procs |= PE_NUMBER(to); /* Copy node */ - else - node->header.gran.procs = PE_NUMBER(to); /* Move node */ - - return Ok; -} - -/* - Process a fetch request. - - Cost of sending a packet of size n = C + P*n - where C = packet construction constant, - P = cost of packing one word into a packet - [Should also account for multiple packets]. -*/ - -//@cindex handleFetchRequest - -rtsFetchReturnCode -handleFetchRequest(node,to,from,tso) -StgClosure* node; // the node which is requested -PEs to, from; // fetch request: from -> to -StgTSO* tso; // the tso which needs the node -{ - ASSERT(!RtsFlags.GranFlags.Light); - /* ToDo: check assertion */ - ASSERT(OutstandingFetches[from]>0); - - /* probably wrong place; */ - ASSERT(CurrentProc==to); - - if (IS_LOCAL_TO(PROCS(node), from)) /* Somebody else moved node already => */ - { /* start tso */ - IF_GRAN_DEBUG(thunkStealing, - fprintf(stderr,"ghuH: handleFetchRequest entered with local node %p (%s) (PE %d)\n", - node, info_type(node), from)); - - if (RtsFlags.GranFlags.DoBulkFetching) { - nat size; - rtsPackBuffer *graph; - - /* Create a 1-node-buffer and schedule a FETCHREPLY now */ - graph = PackOneNode(node, tso, &size); - new_event(from, to, CurrentTime[to], - FetchReply, - tso, (StgClosure *)graph, (rtsSpark*)NULL); - } else { - new_event(from, to, CurrentTime[to], - FetchReply, - tso, node, (rtsSpark*)NULL); - } - IF_GRAN_DEBUG(thunkStealing, - belch("== majQa'! closure %p is local on PE %d already (this is a good thing)", node, from)); - return (NodeIsLocal); - } - else if (IS_LOCAL_TO(PROCS(node), to) ) /* Is node still here? */ - { - if (RtsFlags.GranFlags.DoBulkFetching) { /* {GUM}vo' ngoqvam vInIHta' */ - nat size; /* (code from GUM) */ - StgClosure* graph; - - if (IS_BLACK_HOLE(node)) { /* block on BH or RBH */ - new_event(from, to, CurrentTime[to], - GlobalBlock, - tso, node, (rtsSpark*)NULL); - /* Note: blockFetch is done when handling GLOBALBLOCK event; - make sure the TSO stays out of the run queue */ - /* When this thread is reawoken it does the usual: it tries to - enter the updated node and issues a fetch if it's remote. - It has forgotten that it has sent a fetch already (i.e. a - FETCHNODE is swallowed by a BH, leaving the thread in a BQ) */ - --OutstandingFetches[from]; - - IF_GRAN_DEBUG(thunkStealing, - belch("== majQa'! closure %p on PE %d is a BH (demander=PE %d); faking a FMBQ", - node, to, from)); - if (RtsFlags.GranFlags.GranSimStats.Global) { - globalGranStats.tot_FMBQs++; - } - return (NodeIsBH); - } - - /* The tso requesting the node is blocked and cannot be on a run queue */ - ASSERT(!is_on_queue(tso, from)); - - // ToDo: check whether graph is ever used as an rtsPackBuffer!! - if ((graph = (StgClosure *)PackNearbyGraph(node, tso, &size, 0)) == NULL) - return (OutOfHeap); /* out of heap */ - - /* Actual moving/copying of node is done on arrival; see FETCHREPLY */ - /* Send a reply to the originator */ - /* ToDo: Replace that by software costs for doing graph packing! */ - CurrentTime[to] += size * RtsFlags.GranFlags.Costs.mpacktime; - - new_event(from, to, - CurrentTime[to]+RtsFlags.GranFlags.Costs.latency, - FetchReply, - tso, (StgClosure *)graph, (rtsSpark*)NULL); - - CurrentTime[to] += RtsFlags.GranFlags.Costs.mtidytime; - return (Ok); - } else { /* incremental (single closure) fetching */ - /* Actual moving/copying of node is done on arrival; see FETCHREPLY */ - /* Send a reply to the originator */ - CurrentTime[to] += RtsFlags.GranFlags.Costs.mpacktime; - - new_event(from, to, - CurrentTime[to]+RtsFlags.GranFlags.Costs.latency, - FetchReply, - tso, node, (rtsSpark*)NULL); - - CurrentTime[to] += RtsFlags.GranFlags.Costs.mtidytime; - return (Ok); - } - } - else /* Qu'vatlh! node has been grabbed by another proc => forward */ - { - PEs node_loc = where_is(node); - rtsTime fetchtime; - - IF_GRAN_DEBUG(thunkStealing, - belch("== Qu'vatlh! node %p has been grabbed by PE %d from PE %d (demander=%d) @ %d\n", - node,node_loc,to,from,CurrentTime[to])); - if (RtsFlags.GranFlags.GranSimStats.Global) { - globalGranStats.fetch_misses++; - } - - /* Prepare FORWARD message to proc p_new */ - CurrentTime[to] += RtsFlags.GranFlags.Costs.mpacktime; - - fetchtime = stg_max(CurrentTime[to], CurrentTime[node_loc]) + - RtsFlags.GranFlags.Costs.latency; - - new_event(node_loc, from, fetchtime, - FetchNode, - tso, node, (rtsSpark*)NULL); - - CurrentTime[to] += RtsFlags.GranFlags.Costs.mtidytime; - - return (NodeHasMoved); - } -} - -/* - blockFetch blocks a BlockedFetch node on some kind of black hole. - - Taken from gum/HLComms.lc. [find a better place for that ?] -- HWL - - {\bf Note:} In GranSim we don't have @FETCHME@ nodes and therefore don't - create @FMBQ@'s (FetchMe blocking queues) to cope with global - blocking. Instead, non-local TSO are put into the BQ in the same way as - local TSOs. However, we have to check if a TSO is local or global in - order to account for the latencies involved and for keeping track of the - number of fetches that are really going on. -*/ - -//@cindex blockFetch - -rtsFetchReturnCode -blockFetch(tso, proc, bh) -StgTSO* tso; /* TSO which gets blocked */ -PEs proc; /* PE where that tso was running */ -StgClosure* bh; /* closure to block on (BH, RBH, BQ) */ -{ - StgInfoTable *info; - - IF_GRAN_DEBUG(bq, - fprintf(stderr,"## blockFetch: blocking TSO %p (%d)[PE %d] on node %p (%s) [PE %d]. No graph is packed!\n", - tso, tso->id, proc, bh, info_type(bh), where_is(bh))); - - if (!IS_BLACK_HOLE(bh)) { /* catches BHs and RBHs */ - IF_GRAN_DEBUG(bq, - fprintf(stderr,"## blockFetch: node %p (%s) is not a BH => awakening TSO %p (%d) [PE %u]\n", - bh, info_type(bh), tso, tso->id, proc)); - - /* No BH anymore => immediately unblock tso */ - new_event(proc, proc, CurrentTime[proc], - UnblockThread, - tso, bh, (rtsSpark*)NULL); - - /* Is this always a REPLY to a FETCH in the profile ? */ - if (RtsFlags.GranFlags.GranSimStats.Full) - DumpRawGranEvent(proc, proc, GR_REPLY, tso, bh, (StgInt)0, 0); - return (NodeIsNoBH); - } - - /* DaH {BQ}Daq Qu' Suq 'e' wISov! - Now we know that we have to put the tso into the BQ. - 2 cases: If block-on-fetch, tso is at head of threadq => - => take it out of threadq and into BQ - If reschedule-on-fetch, tso is only pointed to be event - => just put it into BQ - - ngoq ngo'!! - if (!RtsFlags.GranFlags.DoAsyncFetch) { - GranSimBlock(tso, proc, bh); - } else { - if (RtsFlags.GranFlags.GranSimStats.Full) - DumpRawGranEvent(proc, where_is(bh), GR_BLOCK, tso, bh, (StgInt)0, 0); - ++(tso->gran.blockcount); - tso->gran.blockedat = CurrentTime[proc]; - } - */ - - /* after scheduling the GlobalBlock event the TSO is not put into the - run queue again; it is only pointed to via the event we are - processing now; in GranSim 4.xx there is no difference between - synchr and asynchr comm here */ - ASSERT(!is_on_queue(tso, proc)); - ASSERT(tso->link == END_TSO_QUEUE); - - GranSimBlock(tso, proc, bh); /* GranSim statistics gathering */ - - /* Now, put tso into BQ (similar to blocking entry codes) */ - info = get_itbl(bh); - switch (info -> type) { - case RBH: - case BLACKHOLE: - case CAF_BLACKHOLE: // ToDo: check whether this is a possibly ITBL here - case SE_BLACKHOLE: // ToDo: check whether this is a possibly ITBL here - case SE_CAF_BLACKHOLE:// ToDo: check whether this is a possibly ITBL here - /* basically an inlined version of BLACKHOLE_entry -- HWL */ - /* Change the BLACKHOLE into a BLACKHOLE_BQ */ - ((StgBlockingQueue *)bh)->header.info = &BLACKHOLE_BQ_info; - /* Put ourselves on the blocking queue for this black hole */ - // tso->link=END_TSO_QUEUE; not necessary; see assertion above - ((StgBlockingQueue *)bh)->blocking_queue = (StgBlockingQueueElement *)tso; - tso->block_info.closure = bh; - recordMutable((StgMutClosure *)bh); - break; - - case BLACKHOLE_BQ: - /* basically an inlined version of BLACKHOLE_BQ_entry -- HWL */ - tso->link = (StgTSO *) (((StgBlockingQueue*)bh)->blocking_queue); - ((StgBlockingQueue*)bh)->blocking_queue = (StgBlockingQueueElement *)tso; - recordMutable((StgMutClosure *)bh); - -# if 0 && defined(GC_MUT_REQUIRED) - ToDo: check whether recordMutable is necessary -- HWL - /* - * If we modify a black hole in the old generation, we have to make - * sure it goes on the mutables list - */ - - if (bh <= StorageMgrInfo.OldLim) { - MUT_LINK(bh) = (W_) StorageMgrInfo.OldMutables; - StorageMgrInfo.OldMutables = bh; - } else - MUT_LINK(bh) = MUT_NOT_LINKED; -# endif - break; - - case FETCH_ME_BQ: - barf("Qagh: FMBQ closure (%p) found in GrAnSim (TSO=%p (%d))\n", - bh, tso, tso->id); - - default: - { - G_PRINT_NODE(bh); - barf("Qagh: thought %p was a black hole (IP %p (%s))", - bh, info, info_type(bh)); - } - } - return (Ok); -} - - -//@node Idle PEs, Routines directly called from Haskell world, Code for Fetching Nodes, GranSim specific code -//@subsection Idle PEs - -/* - Export work to idle PEs. This function is called from @ReSchedule@ - before dispatching on the current event. @HandleIdlePEs@ iterates over - all PEs, trying to get work for idle PEs. Note, that this is a - simplification compared to GUM's fishing model. We try to compensate for - that by making the cost for stealing work dependent on the number of - idle processors and thereby on the probability with which a randomly - sent fish would find work. -*/ - -//@cindex handleIdlePEs - -void -handleIdlePEs(void) -{ - PEs p; - - IF_DEBUG(gran, fprintf(stderr, "GRAN: handling Idle PEs\n")) - - /* Should never be entered in GrAnSim Light setup */ - ASSERT(!RtsFlags.GranFlags.Light); - - /* Could check whether there are idle PEs if it's a cheap check */ - for (p = 0; p < RtsFlags.GranFlags.proc; p++) - if (procStatus[p]==Idle) /* && IS_SPARKING(p) && IS_STARTING(p) */ - /* First look for local work i.e. examine local spark pool! */ - if (pending_sparks_hds[p]!=(rtsSpark *)NULL) { - new_event(p, p, CurrentTime[p], - FindWork, - (StgTSO*)NULL, (StgClosure*)NULL, (rtsSpark*)NULL); - procStatus[p] = Sparking; - } else if ((RtsFlags.GranFlags.maxFishes==0 || - OutstandingFishes[p]<RtsFlags.GranFlags.maxFishes) ) { - - /* If no local work then try to get remote work! - Qu' Hopbe' pagh tu'lu'pu'chugh Qu' Hop yISuq ! */ - if (RtsFlags.GranFlags.DoStealThreadsFirst && - (RtsFlags.GranFlags.FetchStrategy >= 4 || OutstandingFetches[p] == 0)) - { - if (SurplusThreads > 0l) /* Steal a thread */ - stealThread(p); - - if (procStatus[p]!=Idle) - break; - } - - if (SparksAvail > 0 && - (RtsFlags.GranFlags.FetchStrategy >= 3 || OutstandingFetches[p] == 0)) /* Steal a spark */ - stealSpark(p); - - if (SurplusThreads > 0 && - (RtsFlags.GranFlags.FetchStrategy >= 4 || OutstandingFetches[p] == 0)) /* Steal a thread */ - stealThread(p); - } -} - -/* - Steal a spark and schedule moving it to proc. We want to look at PEs in - clock order -- most retarded first. Currently sparks are only stolen - from the @ADVISORY_POOL@ never from the @REQUIRED_POOL@. Eventually, - this should be changed to first steal from the former then from the - latter. - - We model a sort of fishing mechanism by counting the number of sparks - and threads we are currently stealing. */ - -/* - Return a random nat value in the intervall [from, to) -*/ -static nat -natRandom(from, to) -nat from, to; -{ - nat r, d; - - ASSERT(from<=to); - d = to - from; - /* random returns a value in [0, RAND_MAX] */ - r = (nat) ((float)from + ((float)random()*(float)d)/(float)RAND_MAX); - r = (r==to) ? from : r; - ASSERT(from<=r && (r<to || from==to)); - return r; -} - -/* - Find any PE other than proc. Used for GUM style fishing only. -*/ -static PEs -findRandomPE (proc) -PEs proc; -{ - nat p; - - ASSERT(RtsFlags.GranFlags.Fishing); - if (RtsFlags.GranFlags.RandomSteal) { - p = natRandom(0,RtsFlags.GranFlags.proc); /* full range of PEs */ - } else { - p = 0; - } - IF_GRAN_DEBUG(randomSteal, - belch("^^ RANDOM_STEAL (fishing): stealing from PE %d (current proc is %d)", - p, proc)); - - return (PEs)p; -} - -/* - Magic code for stealing sparks/threads makes use of global knowledge on - spark queues. -*/ -static void -sortPEsByTime (proc, pes_by_time, firstp, np) -PEs proc; -PEs *pes_by_time; -nat *firstp, *np; -{ - PEs p, temp, n, i, j; - nat first, upb, r=0, q=0; - - ASSERT(!RtsFlags.GranFlags.Fishing); - -#if 0 - upb = RtsFlags.GranFlags.proc; /* full range of PEs */ - - if (RtsFlags.GranFlags.RandomSteal) { - r = natRandom(0,RtsFlags.GranFlags.proc); /* full range of PEs */ - } else { - r = 0; - } -#endif - - /* pes_by_time shall contain processors from which we may steal sparks */ - for(n=0, p=0; p < RtsFlags.GranFlags.proc; ++p) - if ((proc != p) && // not the current proc - (pending_sparks_hds[p] != (rtsSpark *)NULL) && // non-empty spark pool - (CurrentTime[p] <= CurrentTime[CurrentProc])) - pes_by_time[n++] = p; - - /* sort pes_by_time */ - for(i=0; i < n; ++i) - for(j=i+1; j < n; ++j) - if (CurrentTime[pes_by_time[i]] > CurrentTime[pes_by_time[j]]) { - rtsTime temp = pes_by_time[i]; - pes_by_time[i] = pes_by_time[j]; - pes_by_time[j] = temp; - } - - /* Choose random processor to steal spark from; first look at processors */ - /* that are earlier than the current one (i.e. proc) */ - for(first=0; - (first < n) && (CurrentTime[pes_by_time[first]] <= CurrentTime[proc]); - ++first) - /* nothing */ ; - - /* if the assertion below is true we can get rid of first */ - /* ASSERT(first==n); */ - /* ToDo: check if first is really needed; find cleaner solution */ - - *firstp = first; - *np = n; -} - -/* - Steal a spark (piece of work) from any processor and bring it to proc. -*/ -//@cindex stealSpark -static rtsBool -stealSpark(PEs proc) { stealSomething(proc, rtsTrue, rtsFalse); } - -/* - Steal a thread from any processor and bring it to proc i.e. thread migration -*/ -//@cindex stealThread -static rtsBool -stealThread(PEs proc) { stealSomething(proc, rtsFalse, rtsTrue); } - -/* - Steal a spark or a thread and schedule moving it to proc. -*/ -//@cindex stealSomething -static rtsBool -stealSomething(proc, steal_spark, steal_thread) -PEs proc; // PE that needs work (stealer) -rtsBool steal_spark, steal_thread; // should a spark and/or thread be stolen -{ - PEs p; - rtsTime fish_arrival_time; - rtsSpark *spark, *prev, *next; - rtsBool stolen = rtsFalse; - - ASSERT(steal_spark || steal_thread); - - /* Should never be entered in GrAnSim Light setup */ - ASSERT(!RtsFlags.GranFlags.Light); - ASSERT(!steal_thread || RtsFlags.GranFlags.DoThreadMigration); - - if (!RtsFlags.GranFlags.Fishing) { - // ToDo: check if stealing threads is prefered over stealing sparks - if (steal_spark) { - if (stealSparkMagic(proc)) - return rtsTrue; - else // no spark found - if (steal_thread) - return stealThreadMagic(proc); - else // no thread found - return rtsFalse; - } else { // ASSERT(steal_thread); - return stealThreadMagic(proc); - } - barf("stealSomething: never reached"); - } - - /* The rest of this function does GUM style fishing */ - - p = findRandomPE(proc); /* find a random PE other than proc */ - - /* Message packing costs for sending a Fish; qeq jabbI'ID */ - CurrentTime[proc] += RtsFlags.GranFlags.Costs.mpacktime; - - /* use another GranEvent for requesting a thread? */ - if (steal_spark && RtsFlags.GranFlags.GranSimStats.Sparks) - DumpRawGranEvent(p, proc, SP_REQUESTED, - (StgTSO*)NULL, (StgClosure *)NULL, (StgInt)0, 0); - - /* time of the fish arrival on the remote PE */ - fish_arrival_time = CurrentTime[proc] + RtsFlags.GranFlags.Costs.latency; - - /* Phps use an own Fish event for that? */ - /* The contents of the spark component is a HACK: - 1 means give me a spark; - 2 means give me a thread - 0 means give me nothing (this should never happen) - */ - new_event(p, proc, fish_arrival_time, - FindWork, - (StgTSO*)NULL, (StgClosure*)NULL, - (steal_spark ? (rtsSpark*)1 : steal_thread ? (rtsSpark*)2 : (rtsSpark*)0)); - - ++OutstandingFishes[proc]; - /* only with Async fetching? */ - if (procStatus[proc]==Idle) - procStatus[proc]=Fishing; - - /* time needed to clean up buffers etc after sending a message */ - CurrentTime[proc] += RtsFlags.GranFlags.Costs.mtidytime; - - /* If GUM style fishing stealing always succeeds because it only consists - of sending out a fish; of course, when the fish may return - empty-handed! */ - return rtsTrue; -} - -/* - This version of stealing a spark makes use of the global info on all - spark pools etc which is not available in a real parallel system. - This could be extended to test e.g. the impact of perfect load information. -*/ -//@cindex stealSparkMagic -static rtsBool -stealSparkMagic(proc) -PEs proc; -{ - PEs p=0, i=0, j=0, n=0, first, upb; - rtsSpark *spark=NULL, *next; - PEs pes_by_time[MAX_PROC]; - rtsBool stolen = rtsFalse; - rtsTime stealtime; - - /* Should never be entered in GrAnSim Light setup */ - ASSERT(!RtsFlags.GranFlags.Light); - - sortPEsByTime(proc, pes_by_time, &first, &n); - - while (!stolen && n>0) { - upb = (first==0) ? n : first; - i = natRandom(0,upb); /* choose a random eligible PE */ - p = pes_by_time[i]; - - IF_GRAN_DEBUG(randomSteal, - belch("^^ stealSparkMagic (random_steal, not fishing): stealing spark from PE %d (current proc is %d)", - p, proc)); - - ASSERT(pending_sparks_hds[p]!=(rtsSpark *)NULL); /* non-empty spark pool */ - - /* Now go through rtsSparkQ and steal the first eligible spark */ - - spark = pending_sparks_hds[p]; - while (!stolen && spark != (rtsSpark*)NULL) - { - /* NB: no prev pointer is needed here because all sparks that are not - chosen are pruned - */ - if ((procStatus[p]==Idle || procStatus[p]==Sparking || procStatus[p] == Fishing) && - spark->next==(rtsSpark*)NULL) - { - /* Be social! Don't steal the only spark of an idle processor - not {spark} neH yInIH !! */ - break; /* next PE */ - } - else if (closure_SHOULD_SPARK(spark->node)) - { - /* Don't Steal local sparks; - ToDo: optionally prefer local over global sparks - if (!spark->global) { - prev=spark; - continue; next spark - } - */ - /* found a spark! */ - - /* Prepare message for sending spark */ - CurrentTime[p] += RtsFlags.GranFlags.Costs.mpacktime; - - if (RtsFlags.GranFlags.GranSimStats.Sparks) - DumpRawGranEvent(p, (PEs)0, SP_EXPORTED, - (StgTSO*)NULL, spark->node, - spark->name, spark_queue_len(p)); - - stealtime = (CurrentTime[p] > CurrentTime[proc] ? - CurrentTime[p] : - CurrentTime[proc]) - + sparkStealTime(); - - new_event(proc, p /* CurrentProc */, stealtime, - MoveSpark, - (StgTSO*)NULL, spark->node, spark); - - stolen = rtsTrue; - ++OutstandingFishes[proc]; /* no. of sparks currently on the fly */ - if (procStatus[proc]==Idle) - procStatus[proc] = Fishing; - ++(spark->global); /* record that this is a global spark */ - ASSERT(SparksAvail>0); - --SparksAvail; /* on-the-fly sparks are not available */ - next = delete_from_sparkq(spark, p, rtsFalse); // don't dispose! - CurrentTime[p] += RtsFlags.GranFlags.Costs.mtidytime; - } - else /* !(closure_SHOULD_SPARK(SPARK_NODE(spark))) */ - { - IF_GRAN_DEBUG(checkSparkQ, - belch("^^ pruning spark %p (node %p) in stealSparkMagic", - spark, spark->node)); - - /* if the spark points to a node that should not be sparked, - prune the spark queue at this point */ - if (RtsFlags.GranFlags.GranSimStats.Sparks) - DumpRawGranEvent(p, (PEs)0, SP_PRUNED, - (StgTSO*)NULL, spark->node, - spark->name, spark_queue_len(p)); - if (RtsFlags.GranFlags.GranSimStats.Global) - globalGranStats.pruned_sparks++; - - ASSERT(SparksAvail>0); - --SparksAvail; - spark = delete_from_sparkq(spark, p, rtsTrue); - } - /* unlink spark (may have been freed!) from sparkq; - if (prev == NULL) // spark was head of spark queue - pending_sparks_hds[p] = spark->next; - else - prev->next = spark->next; - if (spark->next == NULL) - pending_sparks_tls[p] = prev; - else - next->prev = prev; - */ - } /* while ... iterating over sparkq */ - - /* ToDo: assert that PE p still has work left after stealing the spark */ - - if (!stolen && (n>0)) { /* nothing stealable from proc p :( */ - ASSERT(pes_by_time[i]==p); - - /* remove p from the list (at pos i) */ - for (j=i; j+1<n; j++) - pes_by_time[j] = pes_by_time[j+1]; - n--; - - /* update index to first proc which is later (or equal) than proc */ - for ( ; - (first>0) && - (CurrentTime[pes_by_time[first-1]]>CurrentTime[proc]); - first--) - /* nothing */ ; - } - } /* while ... iterating over PEs in pes_by_time */ - - IF_GRAN_DEBUG(randomSteal, - if (stolen) - belch("^^ stealSparkMagic: spark %p (node=%p) stolen by PE %d from PE %d (SparksAvail=%d; idlers=%d)", - spark, spark->node, proc, p, - SparksAvail, idlers()); - else - belch("^^ stealSparkMagic: nothing stolen by PE %d (sparkq len after pruning=%d)(SparksAvail=%d; idlers=%d)", - proc, SparksAvail, idlers())); - - if (RtsFlags.GranFlags.GranSimStats.Global && - stolen && (i!=0)) { /* only for statistics */ - globalGranStats.rs_sp_count++; - globalGranStats.ntimes_total += n; - globalGranStats.fl_total += first; - globalGranStats.no_of_steals++; - } - - return stolen; -} - -/* - The old stealThread code, which makes use of global info and does not - send out fishes. - NB: most of this is the same as in stealSparkMagic; - only the pieces specific to processing thread queues are different; - long live polymorphism! -*/ - -//@cindex stealThreadMagic -static rtsBool -stealThreadMagic(proc) -PEs proc; -{ - PEs p=0, i=0, j=0, n=0, first, upb; - StgTSO *tso=END_TSO_QUEUE; - PEs pes_by_time[MAX_PROC]; - rtsBool stolen = rtsFalse; - rtsTime stealtime; - - /* Should never be entered in GrAnSim Light setup */ - ASSERT(!RtsFlags.GranFlags.Light); - - sortPEsByTime(proc, pes_by_time, &first, &n); - - while (!stolen && n>0) { - upb = (first==0) ? n : first; - i = natRandom(0,upb); /* choose a random eligible PE */ - p = pes_by_time[i]; - - IF_GRAN_DEBUG(randomSteal, - belch("^^ stealThreadMagic (random_steal, not fishing): stealing thread from PE %d (current proc is %d)", - p, proc)); - - /* Steal the first exportable thread in the runnable queue but - never steal the first in the queue for social reasons; - not Qu' wa'DIch yInIH !! - */ - /* Would be better to search through queue and have options which of - the threads to pick when stealing */ - if (run_queue_hds[p] == END_TSO_QUEUE) { - IF_GRAN_DEBUG(randomSteal, - belch("^^ stealThreadMagic: No thread to steal from PE %d (stealer=PE %d)", - p, proc)); - } else { - tso = run_queue_hds[p]->link; /* tso is *2nd* thread in thread queue */ - /* Found one */ - stolen = rtsTrue; - - /* update links in queue */ - run_queue_hds[p]->link = tso->link; - if (run_queue_tls[p] == tso) - run_queue_tls[p] = run_queue_hds[p]; - - /* ToDo: Turn magic constants into params */ - - CurrentTime[p] += 5l * RtsFlags.GranFlags.Costs.mpacktime; - - stealtime = (CurrentTime[p] > CurrentTime[proc] ? - CurrentTime[p] : - CurrentTime[proc]) - + sparkStealTime() - + 4l * RtsFlags.GranFlags.Costs.additional_latency - + 5l * RtsFlags.GranFlags.Costs.munpacktime; - - /* Move the thread; set bitmask to 0 while TSO is `on-the-fly' */ - SET_GRAN_HDR(tso,Nowhere /* PE_NUMBER(proc) */); - - /* Move from one queue to another */ - new_event(proc, p, stealtime, - MoveThread, - tso, (StgClosure*)NULL, (rtsSpark*)NULL); - - /* MAKE_BUSY(proc); not yet; only when thread is in threadq */ - ++OutstandingFishes[proc]; - if (procStatus[proc]) - procStatus[proc] = Fishing; - --SurplusThreads; - - if(RtsFlags.GranFlags.GranSimStats.Full) - DumpRawGranEvent(p, proc, - GR_STEALING, - tso, (StgClosure*)NULL, (StgInt)0, 0); - - /* costs for tidying up buffer after having sent it */ - CurrentTime[p] += 5l * RtsFlags.GranFlags.Costs.mtidytime; - } - - /* ToDo: assert that PE p still has work left after stealing the spark */ - - if (!stolen && (n>0)) { /* nothing stealable from proc p :( */ - ASSERT(pes_by_time[i]==p); - - /* remove p from the list (at pos i) */ - for (j=i; j+1<n; j++) - pes_by_time[j] = pes_by_time[j+1]; - n--; - - /* update index to first proc which is later (or equal) than proc */ - for ( ; - (first>0) && - (CurrentTime[pes_by_time[first-1]]>CurrentTime[proc]); - first--) - /* nothing */ ; - } - } /* while ... iterating over PEs in pes_by_time */ - - IF_GRAN_DEBUG(randomSteal, - if (stolen) - belch("^^ stealThreadMagic: stolen TSO %d (%p) by PE %d from PE %d (SparksAvail=%d; idlers=%d)", - tso->id, tso, proc, p, - SparksAvail, idlers()); - else - belch("stealThreadMagic: nothing stolen by PE %d (SparksAvail=%d; idlers=%d)", - proc, SparksAvail, idlers())); - - if (RtsFlags.GranFlags.GranSimStats.Global && - stolen && (i!=0)) { /* only for statistics */ - /* ToDo: more statistics on avg thread queue lenght etc */ - globalGranStats.rs_t_count++; - globalGranStats.no_of_migrates++; - } - - return stolen; -} - -//@cindex sparkStealTime -static rtsTime -sparkStealTime(void) -{ - double fishdelay, sparkdelay, latencydelay; - fishdelay = (double)RtsFlags.GranFlags.proc/2; - sparkdelay = fishdelay - - ((fishdelay-1.0)/(double)(RtsFlags.GranFlags.proc-1))*((double)idlers()); - latencydelay = sparkdelay*((double)RtsFlags.GranFlags.Costs.latency); - - return((rtsTime)latencydelay); -} - -//@node Routines directly called from Haskell world, Emiting profiling info for GrAnSim, Idle PEs, GranSim specific code -//@subsection Routines directly called from Haskell world -/* -The @GranSim...@ routines in here are directly called via macros from the -threaded world. - -First some auxiliary routines. -*/ - -/* Take the current thread off the thread queue and thereby activate the - next thread. It's assumed that the next ReSchedule after this uses - NEW_THREAD as param. - This fct is called from GranSimBlock and GranSimFetch -*/ - -//@cindex ActivateNextThread - -void -ActivateNextThread (proc) -PEs proc; -{ - StgTSO *t; - /* - This routine is entered either via GranSimFetch or via GranSimBlock. - It has to prepare the CurrentTSO for being blocked and update the - run queue and other statistics on PE proc. The actual enqueuing to the - blocking queue (if coming from GranSimBlock) is done in the entry code - of the BLACKHOLE and BLACKHOLE_BQ closures (see StgMiscClosures.hc). - */ - /* ToDo: add assertions here!! */ - //ASSERT(run_queue_hds[proc]!=END_TSO_QUEUE); - - // Only necessary if the running thread is at front of the queue - // run_queue_hds[proc] = run_queue_hds[proc]->link; - ASSERT(CurrentProc==proc); - ASSERT(!is_on_queue(CurrentTSO,proc)); - if (run_queue_hds[proc]==END_TSO_QUEUE) { - /* NB: this routine is only entered with asynchr comm (see assertion) */ - procStatus[proc] = Idle; - } else { - /* ToDo: check cost assignment */ - CurrentTime[proc] += RtsFlags.GranFlags.Costs.threadcontextswitchtime; - if (RtsFlags.GranFlags.GranSimStats.Full && - (!RtsFlags.GranFlags.Light || RtsFlags.GranFlags.Debug.checkLight)) - /* right flag !?? ^^^ */ - DumpRawGranEvent(proc, 0, GR_SCHEDULE, run_queue_hds[proc], - (StgClosure*)NULL, (StgInt)0, 0); - } -} - -/* - The following GranSim fcts are stg-called from the threaded world. -*/ - -/* Called from HP_CHK and friends (see StgMacros.h) */ -//@cindex GranSimAllocate -void -GranSimAllocate(n) -StgInt n; -{ - CurrentTSO->gran.allocs += n; - ++(CurrentTSO->gran.basicblocks); - - if (RtsFlags.GranFlags.GranSimStats.Heap) { - DumpRawGranEvent(CurrentProc, 0, GR_ALLOC, CurrentTSO, - (StgClosure*)NULL, (StgInt)0, n); - } - - CurrentTSO->gran.exectime += RtsFlags.GranFlags.Costs.heapalloc_cost; - CurrentTime[CurrentProc] += RtsFlags.GranFlags.Costs.heapalloc_cost; -} - -/* - Subtract the values added above, if a heap check fails and - so has to be redone. -*/ -//@cindex GranSimUnallocate -void -GranSimUnallocate(n) -StgInt n; -{ - CurrentTSO->gran.allocs -= n; - --(CurrentTSO->gran.basicblocks); - - CurrentTSO->gran.exectime -= RtsFlags.GranFlags.Costs.heapalloc_cost; - CurrentTime[CurrentProc] -= RtsFlags.GranFlags.Costs.heapalloc_cost; -} - -/* NB: We now inline this code via GRAN_EXEC rather than calling this fct */ -//@cindex GranSimExec -void -GranSimExec(ariths,branches,loads,stores,floats) -StgWord ariths,branches,loads,stores,floats; -{ - StgWord cost = RtsFlags.GranFlags.Costs.arith_cost*ariths + - RtsFlags.GranFlags.Costs.branch_cost*branches + - RtsFlags.GranFlags.Costs.load_cost * loads + - RtsFlags.GranFlags.Costs.store_cost*stores + - RtsFlags.GranFlags.Costs.float_cost*floats; - - CurrentTSO->gran.exectime += cost; - CurrentTime[CurrentProc] += cost; -} - -/* - Fetch the node if it isn't local - -- result indicates whether fetch has been done. - - This is GRIP-style single item fetching. -*/ - -//@cindex GranSimFetch -StgInt -GranSimFetch(node /* , liveness_mask */ ) -StgClosure *node; -/* StgInt liveness_mask; */ -{ - /* reset the return value (to be checked within STG land) */ - NeedToReSchedule = rtsFalse; - - if (RtsFlags.GranFlags.Light) { - /* Always reschedule in GrAnSim-Light to prevent one TSO from - running off too far - new_event(CurrentProc,CurrentProc,CurrentTime[CurrentProc], - ContinueThread,CurrentTSO,node,NULL); - */ - return(0); - } - - /* Faking an RBH closure: - If the bitmask of the closure is 0 then this node is a fake RBH; - */ - if (node->header.gran.procs == Nowhere) { - IF_GRAN_DEBUG(bq, - belch("## Found fake RBH (node %p); delaying TSO %d (%p)", - node, CurrentTSO->id, CurrentTSO)); - - new_event(CurrentProc, CurrentProc, CurrentTime[CurrentProc]+10000, - ContinueThread, CurrentTSO, node, (rtsSpark*)NULL); - - /* Rescheduling (GranSim internal) is necessary */ - NeedToReSchedule = rtsTrue; - - return(1); - } - - /* Note: once a node has been fetched, this test will be passed */ - if (!IS_LOCAL_TO(PROCS(node),CurrentProc)) - { - PEs p = where_is(node); - rtsTime fetchtime; - - IF_GRAN_DEBUG(thunkStealing, - if (p==CurrentProc) - belch("GranSimFetch: Trying to fetch from own processor%u\n", p);); - - CurrentTime[CurrentProc] += RtsFlags.GranFlags.Costs.mpacktime; - /* NB: Fetch is counted on arrival (FetchReply) */ - - fetchtime = stg_max(CurrentTime[CurrentProc],CurrentTime[p]) + - RtsFlags.GranFlags.Costs.latency; - - new_event(p, CurrentProc, fetchtime, - FetchNode, CurrentTSO, node, (rtsSpark*)NULL); - - if (fetchtime<TimeOfNextEvent) - TimeOfNextEvent = fetchtime; - - /* About to block */ - CurrentTSO->gran.blockedat = CurrentTime[CurrentProc]; - - ++OutstandingFetches[CurrentProc]; - - if (RtsFlags.GranFlags.DoAsyncFetch) - /* if asynchr comm is turned on, activate the next thread in the q */ - ActivateNextThread(CurrentProc); - else - procStatus[CurrentProc] = Fetching; - -#if 0 - /* ToDo: nuke the entire if (anything special for fair schedule?) */ - if (RtsFlags.GranFlags.DoAsyncFetch) - { - /* Remove CurrentTSO from the queue -- assumes head of queue == CurrentTSO */ - if(!RtsFlags.GranFlags.DoFairSchedule) - { - /* now done in do_the_fetchnode - if (RtsFlags.GranFlags.GranSimStats.Full) - DumpRawGranEvent(CurrentProc, p, GR_FETCH, CurrentTSO, - node, (StgInt)0, 0); - */ - ActivateNextThread(CurrentProc); - -# if 0 && defined(GRAN_CHECK) - if (RtsFlags.GranFlags.Debug.blockOnFetch_sanity) { - if (TSO_TYPE(CurrentTSO) & FETCH_MASK_TSO) { - fprintf(stderr,"FetchNode: TSO 0x%x has fetch-mask set @ %d\n", - CurrentTSO,CurrentTime[CurrentProc]); - stg_exit(EXIT_FAILURE); - } else { - TSO_TYPE(CurrentTSO) |= FETCH_MASK_TSO; - } - } -# endif - CurrentTSO->link = END_TSO_QUEUE; - /* CurrentTSO = END_TSO_QUEUE; */ - - /* CurrentTSO is pointed to by the FetchNode event; it is - on no run queue any more */ - } else { /* fair scheduling currently not supported -- HWL */ - barf("Asynchr communication is not yet compatible with fair scheduling\n"); - } - } else { /* !RtsFlags.GranFlags.DoAsyncFetch */ - procStatus[CurrentProc] = Fetching; // ToDo: BlockedOnFetch; - /* now done in do_the_fetchnode - if (RtsFlags.GranFlags.GranSimStats.Full) - DumpRawGranEvent(CurrentProc, p, - GR_FETCH, CurrentTSO, node, (StgInt)0, 0); - */ - IF_GRAN_DEBUG(blockOnFetch, - BlockedOnFetch[CurrentProc] = CurrentTSO;); /*- rtsTrue; -*/ - } -#endif /* 0 */ - - CurrentTime[CurrentProc] += RtsFlags.GranFlags.Costs.mtidytime; - - /* Rescheduling (GranSim internal) is necessary */ - NeedToReSchedule = rtsTrue; - - return(1); - } - return(0); -} - -//@cindex GranSimSpark -void -GranSimSpark(local,node) -StgInt local; -StgClosure *node; -{ - /* ++SparksAvail; Nope; do that in add_to_spark_queue */ - if (RtsFlags.GranFlags.GranSimStats.Sparks) - DumpRawGranEvent(CurrentProc, (PEs)0, SP_SPARK, - END_TSO_QUEUE, node, (StgInt)0, spark_queue_len(CurrentProc)-1); - - /* Force the PE to take notice of the spark */ - if(RtsFlags.GranFlags.DoAlwaysCreateThreads) { - new_event(CurrentProc,CurrentProc,CurrentTime[CurrentProc], - FindWork, - END_TSO_QUEUE, (StgClosure*)NULL, (rtsSpark*)NULL); - if (CurrentTime[CurrentProc]<TimeOfNextEvent) - TimeOfNextEvent = CurrentTime[CurrentProc]; - } - - if(local) - ++CurrentTSO->gran.localsparks; - else - ++CurrentTSO->gran.globalsparks; -} - -//@cindex GranSimSparkAt -void -GranSimSparkAt(spark,where,identifier) -rtsSpark *spark; -StgClosure *where; /* This should be a node; alternatively could be a GA */ -StgInt identifier; -{ - PEs p = where_is(where); - GranSimSparkAtAbs(spark,p,identifier); -} - -//@cindex GranSimSparkAtAbs -void -GranSimSparkAtAbs(spark,proc,identifier) -rtsSpark *spark; -PEs proc; -StgInt identifier; -{ - rtsTime exporttime; - - if (spark == (rtsSpark *)NULL) /* Note: Granularity control might have */ - return; /* turned a spark into a NULL. */ - - /* ++SparksAvail; Nope; do that in add_to_spark_queue */ - if(RtsFlags.GranFlags.GranSimStats.Sparks) - DumpRawGranEvent(proc,0,SP_SPARKAT, - END_TSO_QUEUE, spark->node, (StgInt)0, spark_queue_len(proc)); - - if (proc!=CurrentProc) { - CurrentTime[CurrentProc] += RtsFlags.GranFlags.Costs.mpacktime; - exporttime = (CurrentTime[proc] > CurrentTime[CurrentProc]? - CurrentTime[proc]: CurrentTime[CurrentProc]) - + RtsFlags.GranFlags.Costs.latency; - } else { - exporttime = CurrentTime[CurrentProc]; - } - - if ( RtsFlags.GranFlags.Light ) - /* Need CurrentTSO in event field to associate costs with creating - spark even in a GrAnSim Light setup */ - new_event(proc, CurrentProc, exporttime, - MoveSpark, - CurrentTSO, spark->node, spark); - else - new_event(proc, CurrentProc, exporttime, - MoveSpark, (StgTSO*)NULL, spark->node, spark); - /* Bit of a hack to treat placed sparks the same as stolen sparks */ - ++OutstandingFishes[proc]; - - /* Force the PE to take notice of the spark (FINDWORK is put after a - MoveSpark into the sparkq!) */ - if (RtsFlags.GranFlags.DoAlwaysCreateThreads) { - new_event(CurrentProc,CurrentProc,exporttime+1, - FindWork, - (StgTSO*)NULL, (StgClosure*)NULL, (rtsSpark*)NULL); - } - - if (exporttime<TimeOfNextEvent) - TimeOfNextEvent = exporttime; - - if (proc!=CurrentProc) { - CurrentTime[CurrentProc] += RtsFlags.GranFlags.Costs.mtidytime; - ++CurrentTSO->gran.globalsparks; - } else { - ++CurrentTSO->gran.localsparks; - } -} - -/* - This function handles local and global blocking. It's called either - from threaded code (RBH_entry, BH_entry etc) or from blockFetch when - trying to fetch an BH or RBH -*/ - -//@cindex GranSimBlock -void -GranSimBlock(tso, proc, node) -StgTSO *tso; -PEs proc; -StgClosure *node; -{ - PEs node_proc = where_is(node), - tso_proc = where_is((StgClosure *)tso); - - ASSERT(tso_proc==CurrentProc); - // ASSERT(node_proc==CurrentProc); - IF_GRAN_DEBUG(bq, - if (node_proc!=CurrentProc) - belch("## ghuH: TSO %d (%lx) [PE %d] blocks on non-local node %p [PE %d] (no simulation of FETCHMEs)", - tso->id, tso, tso_proc, node, node_proc)); - ASSERT(tso->link==END_TSO_QUEUE); - ASSERT(!is_on_queue(tso,proc)); // tso must not be on run queue already! - //ASSERT(tso==run_queue_hds[proc]); - - IF_DEBUG(gran, - belch("GRAN: TSO %d (%p) [PE %d] blocks on closure %p @ %lx", - tso->id, tso, proc, node, CurrentTime[proc])); - - - /* THIS SHOULD NEVER HAPPEN! - If tso tries to block on a remote node (i.e. node_proc!=CurrentProc) - we have missed a GranSimFetch before entering this closure; - we hack around it for now, faking a FetchNode; - because GranSimBlock is entered via a BLACKHOLE(_BQ) closure, - tso will be blocked on this closure until the FetchReply occurs. - - ngoq Dogh! - - if (node_proc!=CurrentProc) { - StgInt ret; - ret = GranSimFetch(node); - IF_GRAN_DEBUG(bq, - if (ret) - belch(".. GranSimBlock: faking a FetchNode of node %p from %d to %d", - node, node_proc, CurrentProc);); - return; - } - */ - - if (RtsFlags.GranFlags.GranSimStats.Full) - DumpRawGranEvent(proc,node_proc,GR_BLOCK,tso,node,(StgInt)0,0); - - ++(tso->gran.blockcount); - /* Distinction between local and global block is made in blockFetch */ - tso->gran.blockedat = CurrentTime[proc]; - - CurrentTime[proc] += RtsFlags.GranFlags.Costs.threadqueuetime; - ActivateNextThread(proc); - /* tso->link = END_TSO_QUEUE; not really necessary; only for testing */ -} - -#endif /* GRAN */ - -//@node Index, , Dumping routines, GranSim specific code -//@subsection Index - -//@index -//* ActivateNextThread:: @cindex\s-+ActivateNextThread -//* CurrentProc:: @cindex\s-+CurrentProc -//* CurrentTime:: @cindex\s-+CurrentTime -//* GranSimAllocate:: @cindex\s-+GranSimAllocate -//* GranSimBlock:: @cindex\s-+GranSimBlock -//* GranSimExec:: @cindex\s-+GranSimExec -//* GranSimFetch:: @cindex\s-+GranSimFetch -//* GranSimLight_insertThread:: @cindex\s-+GranSimLight_insertThread -//* GranSimSpark:: @cindex\s-+GranSimSpark -//* GranSimSparkAt:: @cindex\s-+GranSimSparkAt -//* GranSimSparkAtAbs:: @cindex\s-+GranSimSparkAtAbs -//* GranSimUnallocate:: @cindex\s-+GranSimUnallocate -//* any_idle:: @cindex\s-+any_idle -//* blockFetch:: @cindex\s-+blockFetch -//* do_the_fetchnode:: @cindex\s-+do_the_fetchnode -//* do_the_fetchreply:: @cindex\s-+do_the_fetchreply -//* do_the_findwork:: @cindex\s-+do_the_findwork -//* do_the_globalblock:: @cindex\s-+do_the_globalblock -//* do_the_movespark:: @cindex\s-+do_the_movespark -//* do_the_movethread:: @cindex\s-+do_the_movethread -//* do_the_startthread:: @cindex\s-+do_the_startthread -//* do_the_unblock:: @cindex\s-+do_the_unblock -//* fetchNode:: @cindex\s-+fetchNode -//* ga_to_proc:: @cindex\s-+ga_to_proc -//* get_next_event:: @cindex\s-+get_next_event -//* get_time_of_next_event:: @cindex\s-+get_time_of_next_event -//* grab_event:: @cindex\s-+grab_event -//* handleFetchRequest:: @cindex\s-+handleFetchRequest -//* handleIdlePEs:: @cindex\s-+handleIdlePEs -//* idlers:: @cindex\s-+idlers -//* insertThread:: @cindex\s-+insertThread -//* insert_event:: @cindex\s-+insert_event -//* is_on_queue:: @cindex\s-+is_on_queue -//* is_unique:: @cindex\s-+is_unique -//* new_event:: @cindex\s-+new_event -//* prepend_event:: @cindex\s-+prepend_event -//* print_event:: @cindex\s-+print_event -//* print_eventq:: @cindex\s-+print_eventq -//* prune_eventq :: @cindex\s-+prune_eventq -//* spark queue:: @cindex\s-+spark queue -//* sparkStealTime:: @cindex\s-+sparkStealTime -//* stealSomething:: @cindex\s-+stealSomething -//* stealSpark:: @cindex\s-+stealSpark -//* stealSparkMagic:: @cindex\s-+stealSparkMagic -//* stealThread:: @cindex\s-+stealThread -//* stealThreadMagic:: @cindex\s-+stealThreadMagic -//* thread_queue_len:: @cindex\s-+thread_queue_len -//* traverse_eventq_for_gc:: @cindex\s-+traverse_eventq_for_gc -//* where_is:: @cindex\s-+where_is -//@end index diff --git a/rts/parallel/GranSimRts.h b/rts/parallel/GranSimRts.h deleted file mode 100644 index fc31a1f0a6..0000000000 --- a/rts/parallel/GranSimRts.h +++ /dev/null @@ -1,268 +0,0 @@ -/* -------------------------------------------------------------------------- - Time-stamp: <Tue Mar 06 2001 00:18:30 Stardate: [-30]6285.06 hwloidl> - - Variables and functions specific to GranSim. - ----------------------------------------------------------------------- */ - -#ifndef GRANSIM_RTS_H -#define GRANSIM_RTS_H - -//@node Headers for GranSim objs used only in the RTS internally, , , -//@section Headers for GranSim objs used only in the RTS internally - -//@menu -//* Event queue:: -//* Spark handling routines:: -//* Processor related stuff:: -//* Local types:: -//* Statistics gathering:: -//* Prototypes:: -//@end menu -//*/ fool highlight - -//@node Event queue, Spark handling routines, Headers for GranSim objs used only in the RTS internally, Headers for GranSim objs used only in the RTS internally -//@subsection Event queue - -#if defined(GRAN) || defined(PAR) -/* Granularity event types for output (see DumpGranEvent) */ -typedef enum GranEventType_ { - GR_START = 0, GR_STARTQ, - GR_STEALING, GR_STOLEN, GR_STOLENQ, - GR_FETCH, GR_REPLY, GR_BLOCK, GR_RESUME, GR_RESUMEQ, - GR_SCHEDULE, GR_DESCHEDULE, - GR_END, - SP_SPARK, SP_SPARKAT, SP_USED, SP_PRUNED, SP_EXPORTED, SP_ACQUIRED, SP_REQUESTED, - GR_ALLOC, - GR_TERMINATE, - GR_SYSTEM_START, GR_SYSTEM_END, /* only for debugging */ - GR_EVENT_MAX -} GranEventType; - -extern char *gran_event_names[]; -#endif - -#if defined(GRAN) /* whole file */ - -/* Event Types (internal use only) */ -typedef enum rtsEventType_ { - ContinueThread = 0, /* Continue running the first thread in the queue */ - StartThread, /* Start a newly created thread */ - ResumeThread, /* Resume a previously running thread */ - MoveSpark, /* Move a spark from one PE to another */ - MoveThread, /* Move a thread from one PE to another */ - FindWork, /* Search for work */ - FetchNode, /* Fetch a node */ - FetchReply, /* Receive a node */ - GlobalBlock, /* Block a TSO on a remote node */ - UnblockThread /* Make a TSO runnable */ -} rtsEventType; - -/* Number of last event type */ -#define MAX_EVENT 9 - -typedef struct rtsEvent_ { - PEs proc; /* Processor id */ - PEs creator; /* Processor id of PE that created the event */ - rtsEventType evttype; /* rtsEvent type */ - rtsTime time; /* Time at which event happened */ - StgTSO *tso; /* Associated TSO, if relevant */ - StgClosure *node; /* Associated node, if relevant */ - rtsSpark *spark; /* Associated SPARK, if relevant */ - StgInt gc_info; /* Counter of heap objects to mark (used in GC only)*/ - struct rtsEvent_ *next; - } rtsEvent; - -typedef rtsEvent *rtsEventQ; - -extern rtsEventQ EventHd; - -/* Interface for ADT of Event Queue */ -rtsEvent *get_next_event(void); -rtsTime get_time_of_next_event(void); -void insert_event(rtsEvent *newentry); -void new_event(PEs proc, PEs creator, rtsTime time, - rtsEventType evttype, StgTSO *tso, - StgClosure *node, rtsSpark *spark); -void print_event(rtsEvent *event); -void print_eventq(rtsEvent *hd); -void prepend_event(rtsEvent *event); -rtsEventQ grab_event(void); -void prune_eventq(StgTSO *tso, StgClosure *node); - -void traverse_eventq_for_gc(void); -void markEventQueue(void); - -//@node Spark handling routines, Processor related stuff, Event queue, Headers for GranSim objs used only in the RTS internally -//@subsection Spark handling routines - -/* These functions are only used in the RTS internally; see GranSim.h for rest */ -void disposeSpark(rtsSpark *spark); -void disposeSparkQ(rtsSparkQ spark); -void print_spark(rtsSpark *spark); -void print_sparkq(PEs proc); -void print_sparkq_stats(void); -nat spark_queue_len(PEs proc); -rtsSpark *delete_from_sparkq (rtsSpark *spark, PEs p, rtsBool dispose_too); -void markSparkQueue(void); - -//@node Processor related stuff, Local types, Spark handling routines, Headers for GranSim objs used only in the RTS internally -//@subsection Processor related stuff - -typedef enum rtsProcStatus_ { - Idle = 0, /* empty threadq */ - Sparking, /* non-empty sparkq; FINDWORK has been issued */ - Starting, /* STARTTHREAD has been issue */ - Fetching, /* waiting for remote data (only if block-on-fetch) */ - Fishing, /* waiting for remote spark/thread */ - Busy /* non-empty threadq, with head of queue active */ -} rtsProcStatus; - -/* -#define IS_IDLE(proc) (procStatus[proc] == Idle) -#define IS_SPARKING(proc) (procStatus[proc] == Sparking) -#define IS_STARTING(proc) (procStatus[proc] == Starting) -#define IS_FETCHING(proc) (procStatus[proc] == Fetching) -#define IS_FISHING(proc) (procStatus[proc] == Fishing) -#define IS_BUSY(proc) (procStatus[proc] == Busy) -#define ANY_IDLE (any_idle()) -#define MAKE_IDLE(proc) procStatus[proc] = Idle -#define MAKE_SPARKING(proc) procStatus[proc] = Sparking -#define MAKE_STARTING(proc) procStatus[proc] = Starting -#define MAKE_FETCHING(proc) procStatus[proc] = Fetching -#define MAKE_FISHING(proc) procStatus[proc] = Fishing -#define MAKE_BUSY(proc) procStatus[proc] = Busy -*/ - -//@node Local types, Statistics gathering, Processor related stuff, Headers for GranSim objs used only in the RTS internally -//@subsection Local types - -/* Return codes of HandleFetchRequest: - 0 ... ok (FETCHREPLY event with a buffer containing addresses of the - nearby graph has been scheduled) - 1 ... node is already local (fetched by somebody else; no event is - scheduled in here) - 2 ... fetch request has been forwrded to the PE that now contains the - node - 3 ... node is a black hole (BH, BQ or RBH); no event is scheduled, and - the current TSO is put into the blocking queue of that node - 4 ... out of heap in PackNearbyGraph; GC should be triggered in calling - function to guarantee that the tso and node inputs are valid - (they may be moved during GC). - Return codes of blockFetch: - 0 ... ok; tso is now at beginning of BQ attached to the bh closure - 1 ... the bh closure is no BH any more; tso is immediately unblocked -*/ - -typedef enum rtsFetchReturnCode_ { - Ok = 0, - NodeIsLocal, - NodeHasMoved, - NodeIsBH, - NodeIsNoBH, - OutOfHeap, -} rtsFetchReturnCode; - -//@node Statistics gathering, Prototypes, Local types, Headers for GranSim objs used only in the RTS internally -//@subsection Statistics gathering - -extern unsigned int /* nat */ OutstandingFetches[], OutstandingFishes[]; -extern rtsProcStatus procStatus[]; -extern StgTSO *BlockedOnFetch[]; - -/* global structure for collecting statistics */ -typedef struct GlobalGranStats_ { - /* event stats */ - nat noOfEvents; - nat event_counts[MAX_EVENT]; - - /* communication stats */ - nat fetch_misses; - nat tot_fake_fetches; // GranSim internal; faked Fetches are a kludge!! - nat tot_low_pri_sparks; - - /* load distribution statistics */ - nat rs_sp_count, rs_t_count, ntimes_total, fl_total, - no_of_steals, no_of_migrates; - - /* spark queue stats */ - nat tot_sq_len, tot_sq_probes, tot_sparks; - nat tot_add_threads, tot_tq_len, non_end_add_threads; - - /* packet statistics */ - nat tot_packets, tot_packet_size, tot_cuts, tot_thunks; - - /* thread stats */ - nat tot_threads_created, threads_created_on_PE[MAX_PROC], - tot_TSOs_migrated; - - /* spark stats */ - nat pruned_sparks, withered_sparks; - nat tot_sparks_created, sparks_created_on_PE[MAX_PROC]; - - /* scheduling stats */ - nat tot_yields, tot_stackover, tot_heapover; - - /* blocking queue statistics */ - rtsTime tot_bq_processing_time; - nat tot_bq_len, tot_bq_len_local, tot_awbq, tot_FMBQs; -} GlobalGranStats; - -extern GlobalGranStats globalGranStats; - -//@node Prototypes, , Statistics gathering, Headers for GranSim objs used only in the RTS internally -//@subsection Prototypes - -/* Generally useful fcts */ -PEs where_is(StgClosure *node); -rtsBool is_unique(StgClosure *node); - -/* Prototypes of event handling functions; needed in Schedule.c:ReSchedule() */ -void do_the_globalblock (rtsEvent* event); -void do_the_unblock (rtsEvent* event); -void do_the_fetchnode (rtsEvent* event); -void do_the_fetchreply (rtsEvent* event); -void do_the_movethread (rtsEvent* event); -void do_the_movespark (rtsEvent* event); -void do_the_startthread(rtsEvent *event); -void do_the_findwork(rtsEvent* event); -void gimme_spark (rtsEvent *event, rtsBool *found_res, rtsSparkQ *spark_res); -rtsBool munch_spark (rtsEvent *event, rtsSparkQ spark); - -/* GranSimLight routines */ -void GranSimLight_enter_system(rtsEvent *event, StgTSO **ActiveTSOp); -void GranSimLight_leave_system(rtsEvent *event, StgTSO **ActiveTSOp); - -/* Communication related routines */ -rtsFetchReturnCode fetchNode(StgClosure* node, PEs from, PEs to); -rtsFetchReturnCode handleFetchRequest(StgClosure* node, PEs curr_proc, PEs p, StgTSO* tso); -void handleIdlePEs(void); - -long int random(void); /* used in stealSpark() and stealThread() in GranSim.c */ - -/* Scheduling fcts defined in GranSim.c */ -void insertThread(StgTSO *tso, PEs proc); -void endThread(StgTSO *tso, PEs proc); -rtsBool GranSimLight_insertThread(StgTSO *tso, PEs proc); -nat thread_queue_len(PEs proc); - -/* For debugging */ -rtsBool is_on_queue (StgTSO *tso, PEs proc); -#endif - -#if defined(GRAN) || defined(PAR) -/* - Interface for dumping routines (i.e. writing to log file). - These routines are shared with GUM (and could also be used for SMP). -*/ -void DumpGranEvent(GranEventType name, StgTSO *tso); -void DumpEndEvent(PEs proc, StgTSO *tso, rtsBool mandatory_thread); -void DumpTSO(StgTSO *tso); -void DumpRawGranEvent(PEs proc, PEs p, GranEventType name, - StgTSO *tso, StgClosure *node, - StgInt sparkname, StgInt len); -void DumpVeryRawGranEvent(rtsTime time, PEs proc, PEs p, GranEventType name, - StgTSO *tso, StgClosure *node, - StgInt sparkname, StgInt len); -#endif - -#endif /* GRANSIM_RTS_H */ diff --git a/rts/parallel/HLC.h b/rts/parallel/HLC.h deleted file mode 100644 index 793ac840f9..0000000000 --- a/rts/parallel/HLC.h +++ /dev/null @@ -1,63 +0,0 @@ -/* -------------------------------------------------------------------------- - Time-stamp: <Sun Mar 18 2001 20:16:14 Stardate: [-30]6349.22 hwloidl> - - High Level Communications Header (HLC.h) - - Contains the high-level definitions (i.e. communication - subsystem independent) used by GUM - Phil Trinder, Glasgow University, 12 December 1994 - H-W. Loidl, Heriot-Watt, November 1999 - ----------------------------------------------------------------------- */ - -#ifndef __HLC_H -#define __HLC_H - -#ifdef PAR - -#include "LLC.h" - -#define NEW_FISH_AGE 0 -#define NEW_FISH_HISTORY 0 -#define NEW_FISH_HUNGER 0 -#define FISH_LIFE_EXPECTANCY 10 - - -//@node GUM Message Sending and Unpacking Functions -//@subsection GUM Message Sending and Unpacking Functions - -rtsBool initMoreBuffers(void); - -void sendFetch (globalAddr *ga, globalAddr *bqga, int load); -void sendResume(globalAddr *rga, int nelem, rtsPackBuffer *packBuffer); -void sendAck (GlobalTaskId task, int ngas, globalAddr *gagamap); -void sendFish (GlobalTaskId destPE, GlobalTaskId origPE, int age, int history, int hunger); -void sendFree (GlobalTaskId destPE, int nelem, P_ data); -void sendSchedule(GlobalTaskId origPE, int nelem, rtsPackBuffer *packBuffer); -void sendReval(GlobalTaskId origPE, int nelem, rtsPackBuffer *data); - -//@node Message-Processing Functions -//@subsection Message-Processing Functions - -rtsBool processMessages(void); -void processFetches(void); -void processTheRealFetches(void); - -//@node Miscellaneous Functions -//@subsection Miscellaneous Functions - -void prepareFreeMsgBuffers(void); -void freeRemoteGA (int pe, globalAddr *ga); -void sendFreeMessages(void); - -GlobalTaskId choosePE(void); -StgClosure *createBlockedFetch (globalAddr ga, globalAddr rga); -void waitForTermination(void); - -/* Message bouncing (startup and shutdown, mainly) */ -void bounceFish(void); -void bounceReval(void); - -void DebugPrintGAGAMap (globalAddr *gagamap, int nGAs); - -#endif /* PAR */ -#endif /* __HLC_H */ diff --git a/rts/parallel/HLComms.c b/rts/parallel/HLComms.c deleted file mode 100644 index b0982e441c..0000000000 --- a/rts/parallel/HLComms.c +++ /dev/null @@ -1,1810 +0,0 @@ -/* ---------------------------------------------------------------------------- - * Time-stamp: <Wed Mar 21 2001 16:34:41 Stardate: [-30]6363.45 hwloidl> - * - * High Level Communications Routines (HLComms.lc) - * - * Contains the high-level routines (i.e. communication - * subsystem independent) used by GUM - * - * GUM 0.2x: Phil Trinder, Glasgow University, 12 December 1994 - * GUM 3.xx: Phil Trinder, Simon Marlow July 1998 - * GUM 4.xx: H-W. Loidl, Heriot-Watt University, November 1999 - - * - * ------------------------------------------------------------------------- */ - -#ifdef PAR /* whole file */ - -//@node High Level Communications Routines, , , -//@section High Level Communications Routines - -//@menu -//* Macros etc:: -//* Includes:: -//* GUM Message Sending and Unpacking Functions:: -//* Message-Processing Functions:: -//* GUM Message Processor:: -//* Miscellaneous Functions:: -//* Index:: -//@end menu - -//@node Macros etc, Includes, High Level Communications Routines, High Level Communications Routines -//@subsection Macros etc - -/* Evidently not Posix */ -/* #include "PosixSource.h" */ - -//@node Includes, GUM Message Sending and Unpacking Functions, Macros etc, High Level Communications Routines -//@subsection Includes - -#include "Rts.h" -#include "RtsUtils.h" -#include "RtsFlags.h" -#include "Storage.h" // for recordMutable -#include "HLC.h" -#include "Parallel.h" -#include "GranSimRts.h" -#include "ParallelRts.h" -#include "Sparks.h" -#include "FetchMe.h" // for BLOCKED_FETCH_info etc -#if defined(DEBUG) -# include "ParallelDebug.h" -#endif -#include "StgMacros.h" // inlined IS_... fcts - -#ifdef DIST -#include "SchedAPI.h" //for createIOThread -extern unsigned int context_switch; -#endif /* DIST */ - -//@node GUM Message Sending and Unpacking Functions, Message-Processing Functions, Includes, High Level Communications Routines -//@subsection GUM Message Sending and Unpacking Functions - -/* - * GUM Message Sending and Unpacking Functions - */ - -/* - * Allocate space for message processing - */ - -//@cindex gumPackBuffer -static rtsPackBuffer *gumPackBuffer; - -//@cindex initMoreBuffers -rtsBool -initMoreBuffers(void) -{ - if ((gumPackBuffer = (rtsPackBuffer *)stgMallocWords(RtsFlags.ParFlags.packBufferSize, - "initMoreBuffers")) == NULL) - return rtsFalse; - return rtsTrue; -} - -/* - * SendFetch packs the two global addresses and a load into a message + - * sends it. - -//@cindex FETCH - - Structure of a FETCH message: - - | GA 1 | GA 2 | - +------------------------------------+------+ - | gtid | slot | weight | gtid | slot | load | - +------------------------------------+------+ - */ - -//@cindex sendFetch -void -sendFetch(globalAddr *rga, globalAddr *lga, int load) -{ - ASSERT(rga->weight > 0 && lga->weight > 0); - IF_PAR_DEBUG(fetch, - belch("~^** Sending Fetch for ((%x, %d, 0)); locally ((%x, %d, %x)), load = %d", - rga->payload.gc.gtid, rga->payload.gc.slot, - lga->payload.gc.gtid, lga->payload.gc.slot, lga->weight, - load)); - - - /* ToDo: Dump event - DumpRawGranEvent(CURRENT_PROC, taskIDtoPE(rga->payload.gc.gtid), - GR_FETCH, CurrentTSO, (StgClosure *)(lga->payload.gc.slot), - 0, spark_queue_len(ADVISORY_POOL)); - */ - - sendOpV(PP_FETCH, rga->payload.gc.gtid, 6, - (StgWord) rga->payload.gc.gtid, (StgWord) rga->payload.gc.slot, - (StgWord) lga->weight, (StgWord) lga->payload.gc.gtid, - (StgWord) lga->payload.gc.slot, (StgWord) load); -} - -/* - * unpackFetch unpacks a FETCH message into two Global addresses and a load - * figure. -*/ - -//@cindex unpackFetch -static void -unpackFetch(globalAddr *lga, globalAddr *rga, int *load) -{ - long buf[6]; - - GetArgs(buf, 6); - - IF_PAR_DEBUG(fetch, - belch("~^** Unpacking Fetch for ((%x, %d, 0)) to ((%x, %d, %x)), load = %d", - (GlobalTaskId) buf[0], (int) buf[1], - (GlobalTaskId) buf[3], (int) buf[4], buf[2], buf[5])); - - lga->weight = 1; - lga->payload.gc.gtid = (GlobalTaskId) buf[0]; - lga->payload.gc.slot = (int) buf[1]; - - rga->weight = (unsigned) buf[2]; - rga->payload.gc.gtid = (GlobalTaskId) buf[3]; - rga->payload.gc.slot = (int) buf[4]; - - *load = (int) buf[5]; - - ASSERT(rga->weight > 0); -} - -/* - * SendResume packs the remote blocking queue's GA and data into a message - * and sends it. - -//@cindex RESUME - - Structure of a RESUME message: - - ------------------------------- - | weight | slot | n | data ... - ------------------------------- - - data is a packed graph represented as an rtsPackBuffer - n is the size of the graph (as returned by PackNearbyGraph) + packet hdr size - */ - -//@cindex sendResume -void -sendResume(globalAddr *rga, int nelem, rtsPackBuffer *packBuffer) -{ - IF_PAR_DEBUG(fetch, - belch("~^[] Sending Resume (packet <<%d>> with %d elems) for ((%x, %d, %x)) to [%x]", - packBuffer->id, nelem, - rga->payload.gc.gtid, rga->payload.gc.slot, rga->weight, - rga->payload.gc.gtid)); - IF_PAR_DEBUG(packet, - PrintPacket(packBuffer)); - - ASSERT(nelem==packBuffer->size); - /* check for magic end-of-buffer word */ - IF_DEBUG(sanity, ASSERT(*(packBuffer->buffer+nelem) == END_OF_BUFFER_MARKER)); - - sendOpNV(PP_RESUME, rga->payload.gc.gtid, - nelem + PACK_BUFFER_HDR_SIZE + DEBUG_HEADROOM, (StgPtr)packBuffer, - 2, (rtsWeight) rga->weight, (StgWord) rga->payload.gc.slot); -} - -/* - * unpackResume unpacks a Resume message into two Global addresses and - * a data array. - */ - -//@cindex unpackResume -static void -unpackResume(globalAddr *lga, int *nelem, rtsPackBuffer *packBuffer) -{ - long buf[3]; - - GetArgs(buf, 3); - - /* - RESUME event is written in awaken_blocked_queue - DumpRawGranEvent(CURRENT_PROC, taskIDtoPE(lga->payload.gc.gtid), - GR_RESUME, END_TSO_QUEUE, (StgClosure *)NULL, 0, 0); - */ - - lga->weight = (unsigned) buf[0]; - lga->payload.gc.gtid = mytid; - lga->payload.gc.slot = (int) buf[1]; - - *nelem = (int) buf[2] - PACK_BUFFER_HDR_SIZE - DEBUG_HEADROOM; - GetArgs(packBuffer, *nelem + PACK_BUFFER_HDR_SIZE + DEBUG_HEADROOM); - - IF_PAR_DEBUG(fetch, - belch("~^[] Unpacking Resume (packet <<%d>> with %d elems) for ((%x, %d, %x))", - packBuffer->id, *nelem, mytid, (int) buf[1], (unsigned) buf[0])); - - /* check for magic end-of-buffer word */ - IF_DEBUG(sanity, ASSERT(*(packBuffer->buffer+*nelem) == END_OF_BUFFER_MARKER)); -} - -/* - * SendAck packs the global address being acknowledged, together with - * an array of global addresses for any closures shipped and sends them. - -//@cindex ACK - - Structure of an ACK message: - - | GA 1 | GA 2 | - +---------------------------------------------+------- - | weight | gtid | slot | weight | gtid | slot | ..... ngas times - + --------------------------------------------+------- - - */ - -//@cindex sendAck -void -sendAck(GlobalTaskId task, int ngas, globalAddr *gagamap) -{ - static long *buffer; - long *p; - int i; - - if(ngas==0) - return; //don't send unnecessary messages!! - - buffer = (long *) gumPackBuffer; - - for(i = 0, p = buffer; i < ngas; i++, p += 6) { - ASSERT(gagamap[1].weight > 0); - p[0] = (long) gagamap->weight; - p[1] = (long) gagamap->payload.gc.gtid; - p[2] = (long) gagamap->payload.gc.slot; - gagamap++; - p[3] = (long) gagamap->weight; - p[4] = (long) gagamap->payload.gc.gtid; - p[5] = (long) gagamap->payload.gc.slot; - gagamap++; - } - IF_PAR_DEBUG(schedule, - belch("~^,, Sending Ack (%d pairs) to [%x]\n", - ngas, task)); - - sendOpN(PP_ACK, task, p - buffer, (StgPtr)buffer); -} - -/* - * unpackAck unpacks an Acknowledgement message into a Global address, - * a count of the number of global addresses following and a map of - * Global addresses - */ - -//@cindex unpackAck -static void -unpackAck(int *ngas, globalAddr *gagamap) -{ - long GAarraysize; - long buf[6]; - - GetArgs(&GAarraysize, 1); - - *ngas = GAarraysize / 6; - - IF_PAR_DEBUG(schedule, - belch("~^,, Unpacking Ack (%d pairs) on [%x]\n", - *ngas, mytid)); - - while (GAarraysize > 0) { - GetArgs(buf, 6); - gagamap->weight = (rtsWeight) buf[0]; - gagamap->payload.gc.gtid = (GlobalTaskId) buf[1]; - gagamap->payload.gc.slot = (int) buf[2]; - gagamap++; - gagamap->weight = (rtsWeight) buf[3]; - gagamap->payload.gc.gtid = (GlobalTaskId) buf[4]; - gagamap->payload.gc.slot = (int) buf[5]; - ASSERT(gagamap->weight > 0); - gagamap++; - GAarraysize -= 6; - } -} - -/* - * SendFish packs the global address being acknowledged, together with - * an array of global addresses for any closures shipped and sends them. - -//@cindex FISH - - Structure of a FISH message: - - +----------------------------------+ - | orig PE | age | history | hunger | - +----------------------------------+ - */ - -//@cindex sendFish -void -sendFish(GlobalTaskId destPE, GlobalTaskId origPE, - int age, int history, int hunger) -{ - IF_PAR_DEBUG(fish, - belch("~^$$ Sending Fish to [%x] (%d outstanding fishes)", - destPE, outstandingFishes)); - - sendOpV(PP_FISH, destPE, 4, - (StgWord) origPE, (StgWord) age, (StgWord) history, (StgWord) hunger); - - if (origPE == mytid) { - //fishing = rtsTrue; - outstandingFishes++; - } -} - -/* - * unpackFish unpacks a FISH message into the global task id of the - * originating PE and 3 data fields: the age, history and hunger of the - * fish. The history + hunger are not currently used. - - */ - -//@cindex unpackFish -static void -unpackFish(GlobalTaskId *origPE, int *age, int *history, int *hunger) -{ - long buf[4]; - - GetArgs(buf, 4); - - IF_PAR_DEBUG(fish, - belch("~^$$ Unpacking Fish from [%x] (age=%d)", - (GlobalTaskId) buf[0], (int) buf[1])); - - *origPE = (GlobalTaskId) buf[0]; - *age = (int) buf[1]; - *history = (int) buf[2]; - *hunger = (int) buf[3]; -} - -/* - * SendFree sends (weight, slot) pairs for GAs that we no longer need - * references to. - -//@cindex FREE - - Structure of a FREE message: - - +----------------------------- - | n | weight_1 | slot_1 | ... - +----------------------------- - */ -//@cindex sendFree -void -sendFree(GlobalTaskId pe, int nelem, StgPtr data) -{ - IF_PAR_DEBUG(free, - belch("~^!! Sending Free (%d GAs) to [%x]", - nelem/2, pe)); - - sendOpN(PP_FREE, pe, nelem, data); -} - -/* - * unpackFree unpacks a FREE message into the amount of data shipped and - * a data block. - */ -//@cindex unpackFree -static void -unpackFree(int *nelem, StgWord *data) -{ - long buf[1]; - - GetArgs(buf, 1); - *nelem = (int) buf[0]; - - IF_PAR_DEBUG(free, - belch("~^!! Unpacking Free (%d GAs)", - *nelem/2)); - - GetArgs(data, *nelem); -} - -/* - * SendSchedule sends a closure to be evaluated in response to a Fish - * message. The message is directed to the PE that originated the Fish - * (origPE), and includes the packed closure (data) along with its size - * (nelem). - -//@cindex SCHEDULE - - Structure of a SCHEDULE message: - - +------------------------------------ - | PE | n | pack buffer of a graph ... - +------------------------------------ - */ -//@cindex sendSchedule -void -sendSchedule(GlobalTaskId origPE, int nelem, rtsPackBuffer *packBuffer) -{ - IF_PAR_DEBUG(schedule, - belch("~^-- Sending Schedule (packet <<%d>> with %d elems) to [%x]\n", - packBuffer->id, nelem, origPE)); - IF_PAR_DEBUG(packet, - PrintPacket(packBuffer)); - - ASSERT(nelem==packBuffer->size); - /* check for magic end-of-buffer word */ - IF_DEBUG(sanity, ASSERT(*(packBuffer->buffer+nelem) == END_OF_BUFFER_MARKER)); - - sendOpN(PP_SCHEDULE, origPE, - nelem + PACK_BUFFER_HDR_SIZE + DEBUG_HEADROOM, (StgPtr)packBuffer); -} - -/* - * unpackSchedule unpacks a SCHEDULE message into the Global address of - * the closure shipped, the amount of data shipped (nelem) and the data - * block (data). - */ - -//@cindex unpackSchedule -static void -unpackSchedule(int *nelem, rtsPackBuffer *packBuffer) -{ - long buf[1]; - - /* first, just unpack 1 word containing the total size (including header) */ - GetArgs(buf, 1); - /* no. of elems, not counting the header of the pack buffer */ - *nelem = (int) buf[0] - PACK_BUFFER_HDR_SIZE - DEBUG_HEADROOM; - - /* automatic cast of flat pvm-data to rtsPackBuffer */ - GetArgs(packBuffer, *nelem + PACK_BUFFER_HDR_SIZE + DEBUG_HEADROOM); - - IF_PAR_DEBUG(schedule, - belch("~^-- Unpacking Schedule (packet <<%d>> with %d elems) on [%x]\n", - packBuffer->id, *nelem, mytid)); - - ASSERT(*nelem==packBuffer->size); - /* check for magic end-of-buffer word */ - IF_DEBUG(sanity, ASSERT(*(packBuffer->buffer+*nelem) == END_OF_BUFFER_MARKER)); -} - -#ifdef DIST -/* sendReval is almost identical to the Schedule version, so we can unpack with unpackSchedule */ -void -sendReval(GlobalTaskId origPE, int nelem, rtsPackBuffer *packBuffer) -{ - IF_PAR_DEBUG(schedule, - belch("~^-- Sending Reval (packet <<%d>> with %d elems) to [%x]\n", - packBuffer->id, nelem, origPE)); - IF_PAR_DEBUG(packet, - PrintPacket(packBuffer)); - - ASSERT(nelem==packBuffer->size); - /* check for magic end-of-buffer word */ - IF_DEBUG(sanity, ASSERT(*(packBuffer->buffer+nelem) == END_OF_BUFFER_MARKER)); - - sendOpN(PP_REVAL, origPE, - nelem + PACK_BUFFER_HDR_SIZE + DEBUG_HEADROOM, (StgPtr)packBuffer); -} - -void FinishReval(StgTSO *t) -{ StgClosure *res; - globalAddr ga; - nat size; - rtsPackBuffer *buffer=NULL; - - ga.payload.gc.slot = t->revalSlot; - ga.payload.gc.gtid = t->revalTid; - ga.weight = 0; - - //find where the reval result is - res = GALAlookup(&ga); - ASSERT(res); - - IF_PAR_DEBUG(schedule, - printGA(&ga); - belch(" needs the result %08x\n",res)); - - //send off the result - buffer = PackNearbyGraph(res, END_TSO_QUEUE, &size,ga.payload.gc.gtid); - ASSERT(buffer != (rtsPackBuffer *)NULL); - sendResume(&ga, size, buffer); - - IF_PAR_DEBUG(schedule, - belch("@;~) Reval Finished")); -} - -#endif /* DIST */ - -//@node Message-Processing Functions, GUM Message Processor, GUM Message Sending and Unpacking Functions, High Level Communications Routines -//@subsection Message-Processing Functions - -/* - * Message-Processing Functions - * - * The following routines process incoming GUM messages. Often reissuing - * messages in response. - * - * processFish unpacks a fish message, reissuing it if it's our own, - * sending work if we have it or sending it onwards otherwise. - */ - -/* - * processFetches constructs and sends resume messages for every - * BlockedFetch which is ready to be awakened. - * awaken_blocked_queue (in Schedule.c) is responsible for moving - * BlockedFetches from a blocking queue to the PendingFetches queue. - */ -void GetRoots(void); -extern StgBlockedFetch *PendingFetches; - -nat -pending_fetches_len(void) -{ - StgBlockedFetch *bf; - nat n; - - for (n=0, bf=PendingFetches; bf != END_BF_QUEUE; n++, bf = (StgBlockedFetch *)(bf->link)) { - ASSERT(get_itbl(bf)->type==BLOCKED_FETCH); - } - return n; -} - -//@cindex processFetches -void -processFetches(void) { - StgBlockedFetch *bf, *next; - StgClosure *closure; - StgInfoTable *ip; - globalAddr rga; - static rtsPackBuffer *packBuffer; - - IF_PAR_DEBUG(verbose, - belch("____ processFetches: %d pending fetches (root @ %p)", - pending_fetches_len(), PendingFetches)); - - for (bf = PendingFetches; - bf != END_BF_QUEUE; - bf=next) { - /* the PendingFetches list contains only BLOCKED_FETCH closures */ - ASSERT(get_itbl(bf)->type==BLOCKED_FETCH); - /* store link (we might overwrite it via blockFetch later on */ - next = (StgBlockedFetch *)(bf->link); - - /* - * Find the target at the end of the indirection chain, and - * process it in much the same fashion as the original target - * of the fetch. Though we hope to find graph here, we could - * find a black hole (of any flavor) or even a FetchMe. - */ - closure = bf->node; - /* - We evacuate BQs and update the node fields where necessary in GC.c - So, if we find an EVACUATED closure, something has gone Very Wrong - (and therefore we let the RTS crash most ungracefully). - */ - ASSERT(get_itbl(closure)->type != EVACUATED); - // closure = ((StgEvacuated *)closure)->evacuee; - - closure = UNWIND_IND(closure); - //while ((ind = IS_INDIRECTION(closure)) != NULL) { closure = ind; } - - ip = get_itbl(closure); - if (ip->type == FETCH_ME) { - /* Forward the Fetch to someone else */ - rga.payload.gc.gtid = bf->ga.payload.gc.gtid; - rga.payload.gc.slot = bf->ga.payload.gc.slot; - rga.weight = bf->ga.weight; - - sendFetch(((StgFetchMe *)closure)->ga, &rga, 0 /* load */); - - // Global statistics: count no. of fetches - if (RtsFlags.ParFlags.ParStats.Global && - RtsFlags.GcFlags.giveStats > NO_GC_STATS) { - globalParStats.tot_fetch_mess++; - } - - IF_PAR_DEBUG(fetch, - belch("__-> processFetches: Forwarding fetch from %lx to %lx", - mytid, rga.payload.gc.gtid)); - - } else if (IS_BLACK_HOLE(closure)) { - IF_PAR_DEBUG(verbose, - belch("__++ processFetches: trying to send a BLACK_HOLE => doing a blockFetch on closure %p (%s)", - closure, info_type(closure))); - bf->node = closure; - blockFetch(bf, closure); - } else { - /* We now have some local graph to send back */ - nat size; - - packBuffer = gumPackBuffer; - IF_PAR_DEBUG(verbose, - belch("__*> processFetches: PackNearbyGraph of closure %p (%s)", - closure, info_type(closure))); - - if ((packBuffer = PackNearbyGraph(closure, END_TSO_QUEUE, &size, bf->ga.payload.gc.gtid)) == NULL) { - // Put current BF back on list - bf->link = (StgBlockingQueueElement *)PendingFetches; - PendingFetches = (StgBlockedFetch *)bf; - // ToDo: check that nothing more has to be done to prepare for GC! - barf("processFetches: out of heap while packing graph; ToDo: call GC here"); - GarbageCollect(GetRoots, rtsFalse); - bf = PendingFetches; - PendingFetches = (StgBlockedFetch *)(bf->link); - closure = bf->node; - packBuffer = PackNearbyGraph(closure, END_TSO_QUEUE, &size, bf->ga.payload.gc.gtid); - ASSERT(packBuffer != (rtsPackBuffer *)NULL); - } - rga.payload.gc.gtid = bf->ga.payload.gc.gtid; - rga.payload.gc.slot = bf->ga.payload.gc.slot; - rga.weight = bf->ga.weight; - - sendResume(&rga, size, packBuffer); - - // Global statistics: count no. of fetches - if (RtsFlags.ParFlags.ParStats.Global && - RtsFlags.GcFlags.giveStats > NO_GC_STATS) { - globalParStats.tot_resume_mess++; - } - } - } - PendingFetches = END_BF_QUEUE; -} - -#if 0 -/* - Alternatively to sending fetch messages directly from the FETCH_ME_entry - code we could just store the data about the remote data in a global - variable and send the fetch request from the main scheduling loop (similar - to processFetches above). This would save an expensive STGCALL in the entry - code because we have to go back to the scheduler anyway. -*/ -//@cindex processFetches -void -processTheRealFetches(void) { - StgBlockedFetch *bf; - StgClosure *closure, *next; - - IF_PAR_DEBUG(verbose, - belch("__ processTheRealFetches: "); - printGA(&theGlobalFromGA); - printGA(&theGlobalToGA)); - - ASSERT(theGlobalFromGA.payload.gc.gtid != 0 && - theGlobalToGA.payload.gc.gtid != 0); - - /* the old version did this in the FETCH_ME entry code */ - sendFetch(&theGlobalFromGA, &theGlobalToGA, 0/*load*/); - -} -#endif - - -/* - Way of dealing with unwanted fish. - Used during startup/shutdown, or from unknown PEs -*/ -void -bounceFish(void) { - GlobalTaskId origPE; - int age, history, hunger; - - /* IF_PAR_DEBUG(verbose, */ - belch(".... [%x] Bouncing unwanted FISH",mytid); - - unpackFish(&origPE, &age, &history, &hunger); - - if (origPE == mytid) { - //fishing = rtsFalse; // fish has come home - outstandingFishes--; - last_fish_arrived_at = CURRENT_TIME; // remember time (see schedule fct) - return; // that's all - } - - /* otherwise, send it home to die */ - sendFish(origPE, origPE, (age + 1), NEW_FISH_HISTORY, NEW_FISH_HUNGER); - // Global statistics: count no. of fetches - if (RtsFlags.ParFlags.ParStats.Global && - RtsFlags.GcFlags.giveStats > NO_GC_STATS) { - globalParStats.tot_fish_mess++; - } -} - -/* - * processFish unpacks a fish message, reissuing it if it's our own, - * sending work if we have it or sending it onwards otherwise. - */ -//@cindex processFish -static void -processFish(void) -{ - GlobalTaskId origPE; - int age, history, hunger; - rtsSpark spark; - static rtsPackBuffer *packBuffer; - - unpackFish(&origPE, &age, &history, &hunger); - - if (origPE == mytid) { - //fishing = rtsFalse; // fish has come home - outstandingFishes--; - last_fish_arrived_at = CURRENT_TIME; // remember time (see schedule fct) - return; // that's all - } - - ASSERT(origPE != mytid); - IF_PAR_DEBUG(fish, - belch("$$__ processing fish; %d sparks available", - spark_queue_len(&(MainRegTable.rSparks)))); - while ((spark = findSpark(rtsTrue/*for_export*/)) != NULL) { - nat size; - // StgClosure *graph; - - packBuffer = gumPackBuffer; - ASSERT(closure_SHOULD_SPARK((StgClosure *)spark)); - if ((packBuffer = PackNearbyGraph(spark, END_TSO_QUEUE, &size,origPE)) == NULL) { - IF_PAR_DEBUG(fish, - belch("$$ GC while trying to satisfy FISH via PackNearbyGraph of node %p", - (StgClosure *)spark)); - barf("processFish: out of heap while packing graph; ToDo: call GC here"); - GarbageCollect(GetRoots, rtsFalse); - /* Now go back and try again */ - } else { - IF_PAR_DEBUG(verbose, - if (RtsFlags.ParFlags.ParStats.Sparks) - belch("==== STEALING spark %x; sending to %x", spark, origPE)); - - IF_PAR_DEBUG(fish, - belch("$$-- Replying to FISH from %x by sending graph @ %p (%s)", - origPE, - (StgClosure *)spark, info_type((StgClosure *)spark))); - sendSchedule(origPE, size, packBuffer); - disposeSpark(spark); - // Global statistics: count no. of fetches - if (RtsFlags.ParFlags.ParStats.Global && - RtsFlags.GcFlags.giveStats > NO_GC_STATS) { - globalParStats.tot_schedule_mess++; - } - - break; - } - } - if (spark == (rtsSpark)NULL) { - IF_PAR_DEBUG(fish, - belch("$$^^ No sparks available for FISH from %x", - origPE)); - /* We have no sparks to give */ - if (age < FISH_LIFE_EXPECTANCY) { - /* and the fish is atill young, send it to another PE to look for work */ - sendFish(choosePE(), origPE, - (age + 1), NEW_FISH_HISTORY, NEW_FISH_HUNGER); - - // Global statistics: count no. of fetches - if (RtsFlags.ParFlags.ParStats.Global && - RtsFlags.GcFlags.giveStats > NO_GC_STATS) { - globalParStats.tot_fish_mess++; - } - } else { /* otherwise, send it home to die */ - sendFish(origPE, origPE, (age + 1), NEW_FISH_HISTORY, NEW_FISH_HUNGER); - // Global statistics: count no. of fetches - if (RtsFlags.ParFlags.ParStats.Global && - RtsFlags.GcFlags.giveStats > NO_GC_STATS) { - globalParStats.tot_fish_mess++; - } - } - } -} /* processFish */ - -/* - * processFetch either returns the requested data (if available) - * or blocks the remote blocking queue on a black hole (if not). - */ - -//@cindex processFetch -static void -processFetch(void) -{ - globalAddr ga, rga; - int load; - StgClosure *closure; - StgInfoTable *ip; - - unpackFetch(&ga, &rga, &load); - IF_PAR_DEBUG(fetch, - belch("%%%%__ Rcvd Fetch for ((%x, %d, 0)), Resume ((%x, %d, %x)) (load %d) from %x", - ga.payload.gc.gtid, ga.payload.gc.slot, - rga.payload.gc.gtid, rga.payload.gc.slot, rga.weight, load, - rga.payload.gc.gtid)); - - closure = GALAlookup(&ga); - ASSERT(closure != (StgClosure *)NULL); - ip = get_itbl(closure); - if (ip->type == FETCH_ME) { - /* Forward the Fetch to someone else */ - sendFetch(((StgFetchMe *)closure)->ga, &rga, load); - - // Global statistics: count no. of fetches - if (RtsFlags.ParFlags.ParStats.Global && - RtsFlags.GcFlags.giveStats > NO_GC_STATS) { - globalParStats.tot_fetch_mess++; - } - } else if (rga.payload.gc.gtid == mytid) { - /* Our own FETCH forwarded back around to us */ - StgFetchMeBlockingQueue *fmbq = (StgFetchMeBlockingQueue *)GALAlookup(&rga); - - IF_PAR_DEBUG(fetch, - belch("%%%%== Fetch returned to sending PE; closure=%p (%s); receiver=%p (%s)", - closure, info_type(closure), fmbq, info_type((StgClosure*)fmbq))); - /* We may have already discovered that the fetch target is our own. */ - if ((StgClosure *)fmbq != closure) - CommonUp((StgClosure *)fmbq, closure); - (void) addWeight(&rga); - } else if (IS_BLACK_HOLE(closure)) { - /* This includes RBH's and FMBQ's */ - StgBlockedFetch *bf; - - /* Can we assert something on the remote GA? */ - ASSERT(GALAlookup(&rga) == NULL); - - /* If we're hitting a BH or RBH or FMBQ we have to put a BLOCKED_FETCH - closure into the BQ in order to denote that when updating this node - the result should be sent to the originator of this fetch message. */ - bf = (StgBlockedFetch *)createBlockedFetch(ga, rga); - IF_PAR_DEBUG(fetch, - belch("%%++ Blocking Fetch ((%x, %d, %x)) on %p (%s)", - rga.payload.gc.gtid, rga.payload.gc.slot, rga.weight, - closure, info_type(closure))); - blockFetch(bf, closure); - } else { - /* The target of the FetchMe is some local graph */ - nat size; - // StgClosure *graph; - rtsPackBuffer *buffer = (rtsPackBuffer *)NULL; - - if ((buffer = PackNearbyGraph(closure, END_TSO_QUEUE, &size, rga.payload.gc.gtid)) == NULL) { - barf("processFetch: out of heap while packing graph; ToDo: call GC here"); - GarbageCollect(GetRoots, rtsFalse); - closure = GALAlookup(&ga); - buffer = PackNearbyGraph(closure, END_TSO_QUEUE, &size, rga.payload.gc.gtid); - ASSERT(buffer != (rtsPackBuffer *)NULL); - } - sendResume(&rga, size, buffer); - - // Global statistics: count no. of fetches - if (RtsFlags.ParFlags.ParStats.Global && - RtsFlags.GcFlags.giveStats > NO_GC_STATS) { - globalParStats.tot_resume_mess++; - } - } -} - -/* - The list of pending fetches must be a root-list for GC. - This routine is called from GC.c (same as marking GAs etc). -*/ -void -markPendingFetches(rtsBool major_gc) { - - /* No need to traverse the list; this is done via the scavenge code - for a BLOCKED_FETCH closure, which evacuates the link field */ - - if (PendingFetches != END_BF_QUEUE ) { - IF_PAR_DEBUG(tables, - fprintf(stderr, "@@@@ PendingFetches is root; evaced from %p to", - PendingFetches)); - - PendingFetches = MarkRoot((StgClosure*)PendingFetches); - - IF_PAR_DEBUG(verbose, - fprintf(stderr, " %p\n", PendingFetches)); - - } else { - IF_PAR_DEBUG(tables, - fprintf(stderr, "@@@@ PendingFetches is empty; no need to mark it\n")); - } -} - -/* - * processFree unpacks a FREE message and adds the weights to our GAs. - */ -//@cindex processFree -static void -processFree(void) -{ - int nelem; - static StgWord *buffer; - int i; - globalAddr ga; - - buffer = (StgWord *)gumPackBuffer; - unpackFree(&nelem, buffer); - IF_PAR_DEBUG(free, - belch("!!__ Rcvd Free (%d GAs)", nelem / 2)); - - ga.payload.gc.gtid = mytid; - for (i = 0; i < nelem;) { - ga.weight = (rtsWeight) buffer[i++]; - ga.payload.gc.slot = (int) buffer[i++]; - IF_PAR_DEBUG(free, - fprintf(stderr, "!!-- Processing free "); - printGA(&ga); - fputc('\n', stderr); - ); - (void) addWeight(&ga); - } -} - -/* - * processResume unpacks a RESUME message into the graph, filling in - * the LA -> GA, and GA -> LA tables. Threads blocked on the original - * FetchMe (now a blocking queue) are awakened, and the blocking queue - * is converted into an indirection. Finally it sends an ACK in response - * which contains any newly allocated GAs. - */ - -//@cindex processResume -static void -processResume(GlobalTaskId sender) -{ - int nelem; - nat nGAs; - static rtsPackBuffer *packBuffer; - StgClosure *newGraph, *old; - globalAddr lga; - globalAddr *gagamap; - - packBuffer = (rtsPackBuffer *)gumPackBuffer; - unpackResume(&lga, &nelem, packBuffer); - - IF_PAR_DEBUG(fetch, - fprintf(stderr, "[]__ Rcvd Resume for "); - printGA(&lga); - fputc('\n', stderr)); - IF_PAR_DEBUG(packet, - PrintPacket((rtsPackBuffer *)packBuffer)); - - /* - * We always unpack the incoming graph, even if we've received the - * requested node in some other data packet (and already awakened - * the blocking queue). - if (SAVE_Hp + packBuffer[0] >= SAVE_HpLim) { - ReallyPerformThreadGC(packBuffer[0], rtsFalse); - SAVE_Hp -= packBuffer[0]; - } - */ - - // ToDo: Check for GC here !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - - /* Do this *after* GC; we don't want to release the object early! */ - - if (lga.weight > 0) - (void) addWeight(&lga); - - old = GALAlookup(&lga); - - /* ToDo: The closure that requested this graph must be one of these two?*/ - ASSERT(get_itbl(old)->type == FETCH_ME_BQ || - get_itbl(old)->type == RBH); - - if (RtsFlags.ParFlags.ParStats.Full) { - StgBlockingQueueElement *bqe, *last_bqe; - - IF_PAR_DEBUG(fetch, - belch("[]-- Resume is REPLY to closure %lx", old)); - - /* Write REPLY events to the log file, indicating that the remote - data has arrived - NB: we emit a REPLY only for the *last* elem in the queue; this is - the one that triggered the fetch message; all other entries - have just added themselves to the queue, waiting for the data - they know that has been requested (see entry code for FETCH_ME_BQ) - */ - if ((get_itbl(old)->type == FETCH_ME_BQ || - get_itbl(old)->type == RBH)) { - for (bqe = ((StgFetchMeBlockingQueue *)old)->blocking_queue, - last_bqe = END_BQ_QUEUE; - get_itbl(bqe)->type==TSO || - get_itbl(bqe)->type==BLOCKED_FETCH; - last_bqe = bqe, bqe = bqe->link) { /* nothing */ } - - ASSERT(last_bqe==END_BQ_QUEUE || - get_itbl((StgClosure *)last_bqe)->type == TSO); - - /* last_bqe now points to the TSO that triggered the FETCH */ - if (get_itbl((StgClosure *)last_bqe)->type == TSO) - DumpRawGranEvent(CURRENT_PROC, taskIDtoPE(sender), - GR_REPLY, ((StgTSO *)last_bqe), ((StgTSO *)last_bqe)->block_info.closure, - 0, spark_queue_len(&(MainRegTable.rSparks))); - } - } - - newGraph = UnpackGraph(packBuffer, &gagamap, &nGAs); - ASSERT(newGraph != NULL); - - /* - * Sometimes, unpacking will common up the resumee with the - * incoming graph, but if it hasn't, we'd better do so now. - */ - - if (get_itbl(old)->type == FETCH_ME_BQ) - CommonUp(old, newGraph); - - IF_PAR_DEBUG(fetch, - belch("[]-- Ready to resume unpacked graph at %p (%s)", - newGraph, info_type(newGraph))); - - IF_PAR_DEBUG(tables, - DebugPrintGAGAMap(gagamap, nGAs)); - - sendAck(sender, nGAs, gagamap); -} - -/* - * processSchedule unpacks a SCHEDULE message into the graph, filling - * in the LA -> GA, and GA -> LA tables. The root of the graph is added to - * the local spark queue. Finally it sends an ACK in response - * which contains any newly allocated GAs. - */ -//@cindex processSchedule -static void -processSchedule(GlobalTaskId sender) -{ - nat nelem, nGAs; - rtsBool success; - static rtsPackBuffer *packBuffer; - StgClosure *newGraph; - globalAddr *gagamap; - - packBuffer = gumPackBuffer; /* HWL */ - unpackSchedule(&nelem, packBuffer); - - IF_PAR_DEBUG(schedule, - belch("--__ Rcvd Schedule (%d elems)", nelem)); - IF_PAR_DEBUG(packet, - PrintPacket(packBuffer)); - - /* - * For now, the graph is a closure to be sparked as an advisory - * spark, but in future it may be a complete spark with - * required/advisory status, priority etc. - */ - - /* - space_required = packBuffer[0]; - if (SAVE_Hp + space_required >= SAVE_HpLim) { - ReallyPerformThreadGC(space_required, rtsFalse); - SAVE_Hp -= space_required; - } - */ - // ToDo: check whether GC is necessary !!!!!!!!!!!!!!!!!!!!! - newGraph = UnpackGraph(packBuffer, &gagamap, &nGAs); - ASSERT(newGraph != NULL); - success = add_to_spark_queue(newGraph, &(MainRegTable.rSparks)); - - if (RtsFlags.ParFlags.ParStats.Full && - RtsFlags.ParFlags.ParStats.Sparks && - success) - DumpRawGranEvent(CURRENT_PROC, CURRENT_PROC, - GR_STOLEN, ((StgTSO *)NULL), newGraph, - 0, 0 /* spark_queue_len(ADVISORY_POOL) */); - - IF_PAR_DEBUG(schedule, - if (success) - belch("--^^ added spark to unpacked graph %p (%s); %d sparks available on [%x] (%s)", - newGraph, info_type(newGraph), spark_queue_len(&(MainRegTable.rSparks)), mytid); - else - belch("--^^ received non-sparkable closure %p (%s); nothing added to spark pool; %d sparks available on [%x]", - newGraph, info_type(newGraph), spark_queue_len(&(MainRegTable.rSparks)), mytid)); - IF_PAR_DEBUG(packet, - belch("*< Unpacked graph with root at %p (%s):", - newGraph, info_type(newGraph)); - PrintGraph(newGraph, 0)); - - IF_PAR_DEBUG(tables, - DebugPrintGAGAMap(gagamap, nGAs)); - - sendAck(sender, nGAs, gagamap); - - //fishing = rtsFalse; - ASSERT(outstandingFishes>0); - outstandingFishes--; -} - -/* - * processAck unpacks an ACK, and uses the GAGA map to convert RBH's - * (which represent shared thunks that have been shipped) into fetch-mes - * to remote GAs. - */ -//@cindex processAck -static void -processAck(void) -{ - nat nGAs; - globalAddr *gaga; - globalAddr gagamap[256]; // ToDo: elim magic constant!! MAX_GAS * 2];?? - - unpackAck(&nGAs, gagamap); - - IF_PAR_DEBUG(tables, - belch(",,,, Rcvd Ack (%d pairs)", nGAs); - DebugPrintGAGAMap(gagamap, nGAs)); - - IF_DEBUG(sanity, - checkGAGAMap(gagamap, nGAs)); - - /* - * For each (oldGA, newGA) pair, set the GA of the corresponding - * thunk to the newGA, convert the thunk to a FetchMe, and return - * the weight from the oldGA. - */ - for (gaga = gagamap; gaga < gagamap + nGAs * 2; gaga += 2) { - StgClosure *old_closure = GALAlookup(gaga); - StgClosure *new_closure = GALAlookup(gaga + 1); - - ASSERT(old_closure != NULL); - if (new_closure == NULL) { - /* We don't have this closure, so we make a fetchme for it */ - globalAddr *ga = setRemoteGA(old_closure, gaga + 1, rtsTrue); - - /* convertToFetchMe should be done unconditionally here. - Currently, we assign GAs to CONSTRs, too, (a bit of a hack), - so we have to check whether it is an RBH before converting - - ASSERT(get_itbl(old_closure)==RBH); - */ - if (get_itbl(old_closure)->type==RBH) - convertToFetchMe((StgRBH *)old_closure, ga); - } else { - /* - * Oops...we've got this one already; update the RBH to - * point to the object we already know about, whatever it - * happens to be. - */ - CommonUp(old_closure, new_closure); - - /* - * Increase the weight of the object by the amount just - * received in the second part of the ACK pair. - */ - (void) addWeight(gaga + 1); - } - (void) addWeight(gaga); - } - - /* check the sanity of the LAGA and GALA tables after mincing them */ - IF_DEBUG(sanity, checkLAGAtable(rtsFalse)); -} - -#ifdef DIST - -void -bounceReval(void) { - barf("Task %x: TODO: should send NACK in response to REVAL",mytid); -} - -static void -processReval(GlobalTaskId sender) //similar to schedule... -{ nat nelem, space_required, nGAs; - static rtsPackBuffer *packBuffer; - StgClosure *newGraph; - globalAddr *gagamap; - StgTSO* tso; - globalAddr *ga; - - packBuffer = gumPackBuffer; /* HWL */ - unpackSchedule(&nelem, packBuffer); /* okay, since the structure is the same */ - - IF_PAR_DEBUG(packet, - belch("@;~) [%x] Rcvd Reval (%d elems)", mytid, nelem); - PrintPacket(packBuffer)); - - /* - space_required = packBuffer[0]; - if (SAVE_Hp + space_required >= SAVE_HpLim) { - ReallyPerformThreadGC(space_required, rtsFalse); - SAVE_Hp -= space_required; - } - */ - - // ToDo: check whether GC is necessary !!!!!!!!!!!!!!!!!!!!! - newGraph = UnpackGraph(packBuffer, &gagamap, &nGAs); - ASSERT(newGraph != NULL); - - IF_PAR_DEBUG(packet, - belch("@;~) Unpacked graph with root at %p (%s):", - newGraph, info_type(newGraph)); - PrintGraph(newGraph, 0)); - - IF_PAR_DEBUG(tables, - DebugPrintGAGAMap(gagamap, nGAs)); - - IF_PAR_DEBUG(tables, - printLAGAtable(); - DebugPrintGAGAMap(gagamap, nGAs)); - - //We don't send an Ack to the head!!!! - ASSERT(nGAs>0); - sendAck(sender, nGAs-1, gagamap+2); - - IF_PAR_DEBUG(verbose, - belch("@;~) About to create Reval thread on behalf of %x", - sender)); - - tso=createGenThread(RtsFlags.GcFlags.initialStkSize,newGraph); - tso->priority=RevalPriority; - tso->revalSlot=gagamap->payload.gc.slot;//record who sent the reval - tso->revalTid =gagamap->payload.gc.gtid; - scheduleThread(tso); - context_switch = 1; // switch at the earliest opportunity -} -#endif - - -//@node GUM Message Processor, Miscellaneous Functions, Message-Processing Functions, High Level Communications Routines -//@subsection GUM Message Processor - -/* - * GUM Message Processor - - * processMessages processes any messages that have arrived, calling - * appropriate routines depending on the message tag - * (opcode). N.B. Unless profiling it assumes that there {\em ARE} messages - * present and performs a blocking receive! During profiling it - * busy-waits in order to record idle time. - */ - -//@cindex processMessages -rtsBool -processMessages(void) -{ - rtsPacket packet; - OpCode opcode; - GlobalTaskId task; - rtsBool receivedFinish = rtsFalse; - - do { - packet = GetPacket(); /* Get next message; block until one available */ - getOpcodeAndSender(packet, &opcode, &task); - - if (task==SysManTask) { - switch (opcode) { - case PP_PETIDS: - processPEtids(); - break; - - case PP_FINISH: - IF_PAR_DEBUG(verbose, - belch("==== received FINISH [%p]", mytid)); - /* this boolean value is returned and propagated to the main - scheduling loop, thus shutting-down this PE */ - receivedFinish = rtsTrue; - break; - - default: - barf("Task %x: received unknown opcode %x from SysMan",mytid, opcode); - } - } else if (taskIDtoPE(task)==0) { - /* When a new PE joins then potentially FISH & REVAL message may - reach PES before they are notified of the new PEs existance. The - only solution is to bounce/fail these messages back to the sender. - But we will worry about it once we start seeing these race - conditions! */ - switch (opcode) { - case PP_FISH: - bounceFish(); - break; -#ifdef DIST - case PP_REVAL: - bounceReval(); - break; -#endif - case PP_PETIDS: - belch("Task %x: Ignoring PVM session opened by another SysMan %x",mytid,task); - break; - - case PP_FINISH: - break; - - default: - belch("Task %x: Ignoring opcode %x from unknown PE %x",mytid, opcode, task); - } - } else - switch (opcode) { - case PP_FETCH: - processFetch(); - // Global statistics: count no. of fetches - if (RtsFlags.ParFlags.ParStats.Global && - RtsFlags.GcFlags.giveStats > NO_GC_STATS) { - globalParStats.rec_fetch_mess++; - } - break; - - case PP_RESUME: - processResume(task); - // Global statistics: count no. of fetches - if (RtsFlags.ParFlags.ParStats.Global && - RtsFlags.GcFlags.giveStats > NO_GC_STATS) { - globalParStats.rec_resume_mess++; - } - break; - - case PP_ACK: - processAck(); - break; - - case PP_FISH: - processFish(); - // Global statistics: count no. of fetches - if (RtsFlags.ParFlags.ParStats.Global && - RtsFlags.GcFlags.giveStats > NO_GC_STATS) { - globalParStats.rec_fish_mess++; - } - break; - - case PP_FREE: - processFree(); - break; - - case PP_SCHEDULE: - processSchedule(task); - // Global statistics: count no. of fetches - if (RtsFlags.ParFlags.ParStats.Global && - RtsFlags.GcFlags.giveStats > NO_GC_STATS) { - globalParStats.rec_schedule_mess++; - } - break; - -#ifdef DIST - case PP_REVAL: - processReval(task); - // Global statistics: count no. of fetches - if (RtsFlags.ParFlags.ParStats.Global && - RtsFlags.GcFlags.giveStats > NO_GC_STATS) { - globalParStats.rec_reval_mess++; - } - break; -#endif - - default: - /* Anything we're not prepared to deal with. */ - barf("Task %x: Unexpected opcode %x from %x", - mytid, opcode, task); - } /* switch */ - - } while (PacketsWaiting()); /* While there are messages: process them */ - return receivedFinish; -} /* processMessages */ - -//@node Miscellaneous Functions, Index, GUM Message Processor, High Level Communications Routines -//@subsection Miscellaneous Functions - -/* - * blockFetch blocks a BlockedFetch node on some kind of black hole. - */ -//@cindex blockFetch -void -blockFetch(StgBlockedFetch *bf, StgClosure *bh) { - bf->node = bh; - switch (get_itbl(bh)->type) { - case BLACKHOLE: - bf->link = END_BQ_QUEUE; - //((StgBlockingQueue *)bh)->header.info = &stg_BLACKHOLE_BQ_info; - SET_INFO(bh, &stg_BLACKHOLE_BQ_info); // turn closure into a blocking queue - ((StgBlockingQueue *)bh)->blocking_queue = (StgBlockingQueueElement *)bf; - - // put bh on the mutables list - recordMutable((StgMutClosure *)bh); - break; - - case BLACKHOLE_BQ: - /* enqueue bf on blocking queue of closure bh */ - bf->link = ((StgBlockingQueue *)bh)->blocking_queue; - ((StgBlockingQueue *)bh)->blocking_queue = (StgBlockingQueueElement *)bf; - - // put bh on the mutables list; ToDo: check - recordMutable((StgMutClosure *)bh); - break; - - case FETCH_ME_BQ: - /* enqueue bf on blocking queue of closure bh */ - bf->link = ((StgFetchMeBlockingQueue *)bh)->blocking_queue; - ((StgFetchMeBlockingQueue *)bh)->blocking_queue = (StgBlockingQueueElement *)bf; - - // put bh on the mutables list; ToDo: check - recordMutable((StgMutClosure *)bh); - break; - - case RBH: - /* enqueue bf on blocking queue of closure bh */ - bf->link = ((StgRBH *)bh)->blocking_queue; - ((StgRBH *)bh)->blocking_queue = (StgBlockingQueueElement *)bf; - - // put bh on the mutables list; ToDo: check - recordMutable((StgMutClosure *)bh); - break; - - default: - barf("blockFetch: thought %p was a black hole (IP %#lx, %s)", - (StgClosure *)bh, get_itbl((StgClosure *)bh), - info_type((StgClosure *)bh)); - } - IF_PAR_DEBUG(bq, - belch("##++ blockFetch: after block the BQ of %p (%s) is:", - bh, info_type(bh)); - print_bq(bh)); -} - - -/* - @blockThread@ is called from the main scheduler whenever tso returns with - a ThreadBlocked return code; tso has already been added to a blocking - queue (that's done in the entry code of the closure, because it is a - cheap operation we have to do in any case); the main purpose of this - routine is to send a Fetch message in case we are blocking on a FETCHME(_BQ) - closure, which is indicated by the tso.why_blocked field; - we also write an entry into the log file if we are generating one - - Should update exectime etc in the entry code already; but we don't have - something like ``system time'' in the log file anyway, so this should - even out the inaccuracies. -*/ - -//@cindex blockThread -void -blockThread(StgTSO *tso) -{ - globalAddr *remote_ga=NULL; - globalAddr *local_ga; - globalAddr fmbq_ga; - - // ASSERT(we are on some blocking queue) - ASSERT(tso->block_info.closure != (StgClosure *)NULL); - - /* - We have to check why this thread has been blocked. - */ - switch (tso->why_blocked) { - case BlockedOnGA: - /* the closure must be a FETCH_ME_BQ; tso came in here via - FETCH_ME entry code */ - ASSERT(get_itbl(tso->block_info.closure)->type==FETCH_ME_BQ); - - /* HACK: the link field is used to hold the GA between FETCH_ME_entry - end this point; if something (eg. GC) happens inbetween the whole - thing will blow up - The problem is that the ga field of the FETCH_ME has been overwritten - with the head of the blocking queue (which is tso). - */ - ASSERT(looks_like_ga(&theGlobalFromGA)); - // ASSERT(tso->link!=END_TSO_QUEUE && tso->link!=NULL); - remote_ga = &theGlobalFromGA; //tso->link; - tso->link = (StgTSO*)END_BQ_QUEUE; - /* it was tso which turned node from FETCH_ME into FETCH_ME_BQ => - we have to send a Fetch message here! */ - if (RtsFlags.ParFlags.ParStats.Full) { - /* Note that CURRENT_TIME may perform an unsafe call */ - tso->par.exectime += CURRENT_TIME - tso->par.blockedat; - tso->par.fetchcount++; - tso->par.blockedat = CURRENT_TIME; - /* we are about to send off a FETCH message, so dump a FETCH event */ - DumpRawGranEvent(CURRENT_PROC, - taskIDtoPE(remote_ga->payload.gc.gtid), - GR_FETCH, tso, tso->block_info.closure, 0, 0); - } - /* Phil T. claims that this was a workaround for a hard-to-find - * bug, hence I'm leaving it out for now --SDM - */ - /* Assign a brand-new global address to the newly created FMBQ */ - local_ga = makeGlobal(tso->block_info.closure, rtsFalse); - splitWeight(&fmbq_ga, local_ga); - ASSERT(fmbq_ga.weight == 1U << (BITS_IN(unsigned) - 1)); - - sendFetch(remote_ga, &fmbq_ga, 0/*load*/); - - // Global statistics: count no. of fetches - if (RtsFlags.ParFlags.ParStats.Global && - RtsFlags.GcFlags.giveStats > NO_GC_STATS) { - globalParStats.tot_fetch_mess++; - } - - IF_DEBUG(sanity, - theGlobalFromGA.payload.gc.gtid = (GlobalTaskId)0); - break; - - case BlockedOnGA_NoSend: - /* the closure must be a FETCH_ME_BQ; tso came in here via - FETCH_ME_BQ entry code */ - ASSERT(get_itbl(tso->block_info.closure)->type==FETCH_ME_BQ); - - /* Fetch message has been sent already */ - if (RtsFlags.ParFlags.ParStats.Full) { - /* Note that CURRENT_TIME may perform an unsafe call */ - tso->par.exectime += CURRENT_TIME - tso->par.blockedat; - tso->par.blockcount++; - tso->par.blockedat = CURRENT_TIME; - /* dump a block event, because fetch has been sent already */ - DumpRawGranEvent(CURRENT_PROC, thisPE, - GR_BLOCK, tso, tso->block_info.closure, 0, 0); - } - break; - - case BlockedOnMVar: - case BlockedOnBlackHole: - /* the closure must be a BLACKHOLE_BQ or an RBH; tso came in here via - BLACKHOLE(_BQ) or CAF_BLACKHOLE or RBH entry code */ - ASSERT(get_itbl(tso->block_info.closure)->type==MVAR || - get_itbl(tso->block_info.closure)->type==BLACKHOLE_BQ || - get_itbl(tso->block_info.closure)->type==RBH); - - /* if collecting stats update the execution time etc */ - if (RtsFlags.ParFlags.ParStats.Full) { - /* Note that CURRENT_TIME may perform an unsafe call */ - tso->par.exectime += CURRENT_TIME - tso->par.blockedat; - tso->par.blockcount++; - tso->par.blockedat = CURRENT_TIME; - DumpRawGranEvent(CURRENT_PROC, thisPE, - GR_BLOCK, tso, tso->block_info.closure, 0, 0); - } - break; - - case BlockedOnDelay: - /* Whats sort of stats shall we collect for an explicit threadDelay? */ - IF_PAR_DEBUG(verbose, - belch("##++ blockThread: TSO %d blocked on ThreadDelay", - tso->id)); - break; - - /* Check that the following is impossible to happen, indeed - case BlockedOnException: - case BlockedOnRead: - case BlockedOnWrite: - */ - default: - barf("blockThread: impossible why_blocked code %d for TSO %d", - tso->why_blocked, tso->id); - } - - IF_PAR_DEBUG(verbose, - belch("##++ blockThread: TSO %d blocked on closure %p (%s); %s", - tso->id, tso->block_info.closure, info_type(tso->block_info.closure), - (tso->why_blocked==BlockedOnGA) ? "Sent FETCH for GA" : "")); - - IF_PAR_DEBUG(bq, - print_bq(tso->block_info.closure)); -} - -/* - * ChoosePE selects a GlobalTaskId from the array of PEs 'at random'. - * Important properties: - * - it varies during execution, even if the PE is idle - * - it's different for each PE - * - we never send a fish to ourselves - */ -extern long lrand48 (void); - -//@cindex choosePE -GlobalTaskId -choosePE(void) -{ - long temp; - - temp = lrand48() % nPEs; - if (allPEs[temp] == mytid) { /* Never send a FISH to yourself */ - temp = (temp + 1) % nPEs; - } - return allPEs[temp]; -} - -/* - * allocate a BLOCKED_FETCH closure and fill it with the relevant fields - * of the ga argument; called from processFetch when the local closure is - * under evaluation - */ -//@cindex createBlockedFetch -StgClosure * -createBlockedFetch (globalAddr ga, globalAddr rga) -{ - StgBlockedFetch *bf; - StgClosure *closure; - - closure = GALAlookup(&ga); - if ((bf = (StgBlockedFetch *)allocate(_HS + sizeofW(StgBlockedFetch))) == NULL) { - barf("createBlockedFetch: out of heap while allocating heap for a BlocekdFetch; ToDo: call GC here"); - GarbageCollect(GetRoots, rtsFalse); - closure = GALAlookup(&ga); - bf = (StgBlockedFetch *)allocate(_HS + sizeofW(StgBlockedFetch)); - // ToDo: check whether really guaranteed to succeed 2nd time around - } - - ASSERT(bf != (StgBlockedFetch *)NULL); - SET_INFO((StgClosure *)bf, &stg_BLOCKED_FETCH_info); - // ToDo: check whether other header info is needed - bf->node = closure; - bf->ga.payload.gc.gtid = rga.payload.gc.gtid; - bf->ga.payload.gc.slot = rga.payload.gc.slot; - bf->ga.weight = rga.weight; - // bf->link = NULL; debugging - - IF_PAR_DEBUG(schedule, - fprintf(stderr, "%%%%// created BF: bf=%p (%s) of closure , GA: ", - bf, info_type((StgClosure*)bf)); - printGA(&(bf->ga)); - fputc('\n',stderr)); - return (StgClosure *)bf; -} - -/* - * waitForTermination enters a loop ignoring spurious messages while - * waiting for the termination sequence to be completed. - */ -//@cindex waitForTermination -void -waitForTermination(void) -{ - do { - rtsPacket p = GetPacket(); - processUnexpectedMessage(p); - } while (rtsTrue); -} - -#ifdef DEBUG -//@cindex DebugPrintGAGAMap -void -DebugPrintGAGAMap(globalAddr *gagamap, int nGAs) -{ - nat i; - - for (i = 0; i < nGAs; ++i, gagamap += 2) - fprintf(stderr, "__ gagamap[%d] = ((%x, %d, %x)) -> ((%x, %d, %x))\n", i, - gagamap[0].payload.gc.gtid, gagamap[0].payload.gc.slot, gagamap[0].weight, - gagamap[1].payload.gc.gtid, gagamap[1].payload.gc.slot, gagamap[1].weight); -} - -//@cindex checkGAGAMap -void -checkGAGAMap(globalAddr *gagamap, int nGAs) -{ - nat i; - - for (i = 0; i < (nat)nGAs; ++i, gagamap += 2) { - ASSERT(looks_like_ga(gagamap)); - ASSERT(looks_like_ga(gagamap+1)); - } -} -#endif - -//@cindex freeMsgBuffer -static StgWord **freeMsgBuffer = NULL; -//@cindex freeMsgIndex -static nat *freeMsgIndex = NULL; - -//@cindex prepareFreeMsgBuffers -void -prepareFreeMsgBuffers(void) -{ - nat i; - - /* Allocate the freeMsg buffers just once and then hang onto them. */ - if (freeMsgIndex == NULL) { - freeMsgIndex = (nat *) stgMallocBytes(nPEs * sizeof(nat), - "prepareFreeMsgBuffers (Index)"); - freeMsgBuffer = (StgWord **) stgMallocBytes(nPEs * sizeof(long *), - "prepareFreeMsgBuffers (Buffer)"); - - for(i = 0; i < nPEs; i++) - if (i != (thisPE-1)) - freeMsgBuffer[i] = (StgPtr) stgMallocWords(RtsFlags.ParFlags.packBufferSize, - "prepareFreeMsgBuffers (Buffer #i)"); - else - freeMsgBuffer[i] = 0; - } - - /* Initialize the freeMsg buffer pointers to point to the start of their - buffers */ - for (i = 0; i < nPEs; i++) - freeMsgIndex[i] = 0; -} - -//@cindex freeRemoteGA -void -freeRemoteGA(int pe, globalAddr *ga) -{ - nat i; - - ASSERT(GALAlookup(ga) == NULL); - - if ((i = freeMsgIndex[pe]) + 2 >= RtsFlags.ParFlags.packBufferSize) { - IF_PAR_DEBUG(free, - belch("!! Filled a free message buffer (sending remaining messages indivisually)")); - - sendFree(ga->payload.gc.gtid, i, freeMsgBuffer[pe]); - i = 0; - } - freeMsgBuffer[pe][i++] = (StgWord) ga->weight; - freeMsgBuffer[pe][i++] = (StgWord) ga->payload.gc.slot; - freeMsgIndex[pe] = i; - - IF_DEBUG(sanity, - ga->weight = 0xdead0add; - ga->payload.gc.gtid = 0xbbbbbbbb; - ga->payload.gc.slot = 0xbbbbbbbb;); -} - -//@cindex sendFreeMessages -void -sendFreeMessages(void) -{ - nat i; - - for (i = 0; i < nPEs; i++) - if (freeMsgIndex[i] > 0) - sendFree(allPEs[i], freeMsgIndex[i], freeMsgBuffer[i]); -} - -/* synchronises with the other PEs. Receives and records in a global - * variable the task-id of SysMan. If this is the main thread (discovered - * in main.lc), identifies itself to SysMan. Finally it receives - * from SysMan an array of the Global Task Ids of each PE, which is - * returned as the value of the function. - */ - -#if defined(PAR_TICKY) -/* Has to see freeMsgIndex, so must be defined here not in ParTicky.c */ -//@cindex stats_CntFreeGA -void -stats_CntFreeGA (void) { // stats only - - // Global statistics: residency of thread and spark pool - if (RtsFlags.ParFlags.ParStats.Global && - RtsFlags.GcFlags.giveStats > NO_GC_STATS) { - nat i, s; - - globalParStats.cnt_free_GA++; - for (i = 0, s = 0; i < nPEs; i++) - s += globalParStats.tot_free_GA += freeMsgIndex[i]/2; - - if ( s > globalParStats.res_free_GA ) - globalParStats.res_free_GA = s; - } -} -#endif /* PAR_TICKY */ - -#endif /* PAR -- whole file */ - -//@node Index, , Miscellaneous Functions, High Level Communications Routines -//@subsection Index - -//@index -//* ACK:: @cindex\s-+ACK -//* DebugPrintGAGAMap:: @cindex\s-+DebugPrintGAGAMap -//* FETCH:: @cindex\s-+FETCH -//* FISH:: @cindex\s-+FISH -//* FREE:: @cindex\s-+FREE -//* RESUME:: @cindex\s-+RESUME -//* SCHEDULE:: @cindex\s-+SCHEDULE -//* blockFetch:: @cindex\s-+blockFetch -//* choosePE:: @cindex\s-+choosePE -//* freeMsgBuffer:: @cindex\s-+freeMsgBuffer -//* freeMsgIndex:: @cindex\s-+freeMsgIndex -//* freeRemoteGA:: @cindex\s-+freeRemoteGA -//* gumPackBuffer:: @cindex\s-+gumPackBuffer -//* initMoreBuffers:: @cindex\s-+initMoreBuffers -//* prepareFreeMsgBuffers:: @cindex\s-+prepareFreeMsgBuffers -//* processAck:: @cindex\s-+processAck -//* processFetch:: @cindex\s-+processFetch -//* processFetches:: @cindex\s-+processFetches -//* processFish:: @cindex\s-+processFish -//* processFree:: @cindex\s-+processFree -//* processMessages:: @cindex\s-+processMessages -//* processResume:: @cindex\s-+processResume -//* processSchedule:: @cindex\s-+processSchedule -//* sendAck:: @cindex\s-+sendAck -//* sendFetch:: @cindex\s-+sendFetch -//* sendFish:: @cindex\s-+sendFish -//* sendFree:: @cindex\s-+sendFree -//* sendFreeMessages:: @cindex\s-+sendFreeMessages -//* sendResume:: @cindex\s-+sendResume -//* sendSchedule:: @cindex\s-+sendSchedule -//* unpackAck:: @cindex\s-+unpackAck -//* unpackFetch:: @cindex\s-+unpackFetch -//* unpackFish:: @cindex\s-+unpackFish -//* unpackFree:: @cindex\s-+unpackFree -//* unpackResume:: @cindex\s-+unpackResume -//* unpackSchedule:: @cindex\s-+unpackSchedule -//* waitForTermination:: @cindex\s-+waitForTermination -//@end index diff --git a/rts/parallel/LLC.h b/rts/parallel/LLC.h deleted file mode 100644 index 536e431bef..0000000000 --- a/rts/parallel/LLC.h +++ /dev/null @@ -1,130 +0,0 @@ -/* -------------------------------------------------------------------------- - Time-stamp: <Sun Mar 18 2001 21:23:50 Stardate: [-30]6349.45 hwloidl> - - Low Level Communications Header (LLC.h) - - Contains the definitions used by the Low-level Communications - module of the GUM Haskell runtime environment. - Based on the Graph for PVM implementation. - - Phil Trinder, Glasgow University, 13th Dec 1994 - Adapted for the 4.xx RTS - H-W. Loidl, Heriot-Watt, November 1999 - ----------------------------------------------------------------------- */ - -#ifndef __LLC_H -#define __LLC_H - -#ifdef PAR - -//@node Low Level Communications Header, , , -//@section Low Level Communications Header - -//@menu -//* Includes:: -//* Macros and Constants:: -//* PVM macros:: -//* Externs:: -//@end menu - -//@node Includes, Macros and Constants, Low Level Communications Header, Low Level Communications Header -//@subsection Includes - -#include "Rts.h" -#include "Parallel.h" - -#include "PEOpCodes.h" -#include "pvm3.h" - -//@node Macros and Constants, PVM macros, Includes, Low Level Communications Header -//@subsection Macros and Constants - -#define ANY_TASK (-1) /* receive messages from any task */ -#define ANY_GLOBAL_TASK ANY_TASK -#define ANY_OPCODE (-1) /* receive any opcode */ -#define ALL_GROUP (-1) /* wait for barrier from every group member */ - -#define PEGROUP "PE" - -#define MGRGROUP "MGR" -#define SYSGROUP "SYS" - - -#define PETASK "PE" - -//@node PVM macros, Externs, Macros and Constants, Low Level Communications Header -//@subsection PVM macros - -#define sync(gp,op) do { \ - broadcast(gp,op); \ - pvm_barrier(gp,ALL_GROUP); \ - } while(0) - -#define broadcast(gp,op) do { \ - pvm_initsend(PvmDataDefault); \ - pvm_bcast(gp,op); \ - } while(0) - -#define checkComms(c,s) do { \ - if ((c)<0) { \ - pvm_perror(s); \ - stg_exit(EXIT_FAILURE); \ - }} while(0) - -#define _my_gtid pvm_mytid() -#define GetPacket() pvm_recv(ANY_TASK,ANY_OPCODE) -#define PacketsWaiting() (pvm_probe(ANY_TASK,ANY_OPCODE) != 0) - -#define SPARK_THREAD_DESCRIPTOR 1 -#define GLOBAL_THREAD_DESCRIPTOR 2 - -#define _extract_jump_field(v) (v) - -#define MAX_DATA_WORDS_IN_PACKET 1024 - -/* basic PVM packing */ -#define PutArg1(a) pvm_pklong((long *)&(a),1,1) -#define PutArg2(a) pvm_pklong((long *)&(a),1,1) -#define PutArgN(n,a) pvm_pklong((long *)&(a),1,1) -#define PutArgs(b,n) pvm_pklong((long *)b,n,1) - -#define PutLit(l) { int a = l; PutArgN(?,a); } - -/* basic PVM unpacking */ -#define GetArg1(a) pvm_upklong((long *)&(a),1,1) -#define GetArg2(a) pvm_upklong((long *)&(a),1,1) -#define GetArgN(n,a) pvm_upklong((long *)&(a),1,1) -#define GetArgs(b,n) pvm_upklong((long *)b,n,1) - -//@node Externs, , PVM macros, Low Level Communications Header -//@subsection Externs - -/* basic message passing routines */ -extern void sendOp (OpCode,GlobalTaskId), - sendOp1 (OpCode,GlobalTaskId,StgWord), - sendOp2 (OpCode,GlobalTaskId,StgWord,StgWord), - sendOpV (OpCode,GlobalTaskId,int,...), - sendOpN (OpCode,GlobalTaskId,int,StgPtr), - sendOpNV (OpCode,GlobalTaskId,int,StgPtr,int,...); - -extern void broadcastOpN(OpCode op, char *group, int n, StgPtr args); - -/* extracting data out of a packet */ -OpCode getOpcode (rtsPacket p); -void getOpcodeAndSender (rtsPacket p, OpCode *popcode, - GlobalTaskId *psender_id); -GlobalTaskId senderTask (rtsPacket p); -rtsPacket waitForPEOp(OpCode op, GlobalTaskId who, void(*processUnexpected)(rtsPacket) ); - -/* Init and shutdown routines */ -void startUpPE (void); -void shutDownPE(void); -int getExitCode(int nbytes, GlobalTaskId *sender_idp); - -/* aux functions */ -char *getOpName (unsigned op); // returns string of opcode -void processUnexpectedMessage (rtsPacket); -//void NullException(void); - -#endif /*PAR */ -#endif /*defined __LLC_H */ diff --git a/rts/parallel/LLComms.c b/rts/parallel/LLComms.c deleted file mode 100644 index baa6dddf0c..0000000000 --- a/rts/parallel/LLComms.c +++ /dev/null @@ -1,489 +0,0 @@ -/* ---------------------------------------------------------------------------- - * Time-stamp: <Mon Mar 19 2001 22:10:38 Stardate: [-30]6354.62 hwloidl> - * - * GUM Low-Level Inter-Task Communication - * - * This module defines PVM Routines for PE-PE communication. - * - * P. Trinder, December 5th. 1994. - * P. Trinder, July 1998 - * H-W. Loidl, November 1999 - - --------------------------------------------------------------------------- */ - -#ifdef PAR /* whole file */ - -//@node GUM Low-Level Inter-Task Communication, , , -//@section GUM Low-Level Inter-Task Communication - -/* - *This module defines the routines which communicate between PEs. The - *code is based on Kevin Hammond's GRIP RTS. (OpCodes.h defines - *PEOp1 etc. in terms of sendOp1 etc.). - * - *Routine & Arguments - * & - *sendOp & 0 \\ - *sendOp1 & 1 \\ - *sendOp2 & 2 \\ - *sendOpN & vector \\ - *sendOpV & variable \\ - *sendOpNV & variable+ vector \\ - * - *First the standard include files. - */ - -//@menu -//* Macros etc:: -//* Includes:: -//* Auxiliary functions:: -//* Index:: -//@end menu - -//@node Macros etc, Includes, GUM Low-Level Inter-Task Communication, GUM Low-Level Inter-Task Communication -//@subsection Macros etc - -/* Evidently not Posix */ -/* #include "PosixSource.h" */ - -#define UNUSED /* nothing */ - -//@node Includes, Auxiliary functions, Macros etc, GUM Low-Level Inter-Task Communication -//@subsection Includes - -#include "Rts.h" -#include "RtsFlags.h" -#include "RtsUtils.h" -#include "Parallel.h" -#include "ParallelRts.h" -#if defined(DEBUG) -# include "ParallelDebug.h" -#endif -#include "LLC.h" - -#ifdef __STDC__ -#include <stdarg.h> -#else -#include <varargs.h> -#endif - -/* Cannot use std macro when compiling for SysMan */ -/* debugging enabled */ -// #define IF_PAR_DEBUG(c,s) { s; } -/* debugging disabled */ -#define IF_PAR_DEBUG(c,s) /* nothing */ - -//@node Auxiliary functions, Index, Includes, GUM Low-Level Inter-Task Communication -//@subsection Auxiliary functions - -/* - * heapChkCounter tracks the number of heap checks since the last probe. - * Not currently used! We check for messages when a thread is resheduled. - */ -int heapChkCounter = 0; - -/* - * Then some miscellaneous functions. - * getOpName returns the character-string name of any OpCode. - */ - -char *UserPEOpNames[] = { PEOP_NAMES }; - -//@cindex getOpName -char * -getOpName(nat op) -{ - if (op >= MIN_PEOPS && op <= MAX_PEOPS) - return (UserPEOpNames[op - MIN_PEOPS]); - else - return ("Unknown PE OpCode"); -} - -/* - * traceSendOp handles the tracing of messages. - */ - -//@cindex traceSendOp -static void -traceSendOp(OpCode op, GlobalTaskId dest UNUSED, - unsigned int data1 UNUSED, unsigned int data2 UNUSED) -{ - char *OpName; - - OpName = getOpName(op); - IF_PAR_DEBUG(trace, - fprintf(stderr," %s [%x,%x] sent from %x to %x", - OpName, data1, data2, mytid, dest)); -} - -/* - * sendOp sends a 0-argument message with OpCode {\em op} to - * the global task {\em task}. - */ - -//@cindex sendOp -void -sendOp(OpCode op, GlobalTaskId task) -{ - traceSendOp(op, task,0,0); - - pvm_initsend(PvmDataRaw); - pvm_send(task, op); -} - -/* - * sendOp1 sends a 1-argument message with OpCode {\em op} - * to the global task {\em task}. - */ - -//@cindex sendOp1 -void -sendOp1(OpCode op, GlobalTaskId task, StgWord arg1) -{ - traceSendOp(op, task, arg1,0); - - pvm_initsend(PvmDataRaw); - PutArg1(arg1); - pvm_send(task, op); -} - - -/* - * sendOp2 is used by the FP code only. - */ - -//@cindex sendOp2 -void -sendOp2(OpCode op, GlobalTaskId task, StgWord arg1, StgWord arg2) -{ - traceSendOp(op, task, arg1, arg2); - - pvm_initsend(PvmDataRaw); - PutArg1(arg1); - PutArg2(arg2); - pvm_send(task, op); -} - -/* - * - * sendOpV takes a variable number of arguments, as specified by {\em n}. - * For example, - * - * sendOpV( PP_STATS, StatsTask, 3, start_time, stop_time, sparkcount); - */ - -//@cindex sendOpV -void -sendOpV(OpCode op, GlobalTaskId task, int n, ...) -{ - va_list ap; - int i; - StgWord arg; - - va_start(ap, n); - - traceSendOp(op, task, 0, 0); - - pvm_initsend(PvmDataRaw); - - for (i = 0; i < n; ++i) { - arg = va_arg(ap, StgWord); - PutArgN(i, arg); - } - va_end(ap); - - pvm_send(task, op); -} - -/* - * - * sendOpNV takes a variable-size datablock, as specified by {\em - * nelem} and a variable number of arguments, as specified by {\em - * narg}. N.B. The datablock and the additional arguments are contiguous - * and are copied over together. For example, - * - * sendOpNV(PP_RESUME, tsoga.pe, 6, nelem, data, - * (W_) ga.weight, (W_) ga.loc.gc.gtid, (W_) ga.loc.gc.slot, - * (W_) tsoga.weight, (W_) tsoga.loc.gc.gtid, (W_) tsoga.loc.gc.slot); - * - * Important: The variable arguments must all be StgWords. - - sendOpNV(_, tid, m, n, data, x1, ..., xm): - - | n elems - +------------------------------ - | x1 | ... | xm | n | data .... - +------------------------------ - */ - -//@cindex sendOpNV -void -sendOpNV(OpCode op, GlobalTaskId task, int nelem, - StgWord *datablock, int narg, ...) -{ - va_list ap; - int i; - StgWord arg; - - va_start(ap, narg); - - traceSendOp(op, task, 0, 0); - IF_PAR_DEBUG(trace, - fprintf(stderr,"~~ sendOpNV: op = %x (%s), task = %x, narg = %d, nelem = %d", - op, getOpName(op), task, narg, nelem)); - - pvm_initsend(PvmDataRaw); - - for (i = 0; i < narg; ++i) { - arg = va_arg(ap, StgWord); - IF_PAR_DEBUG(trace, - fprintf(stderr,"~~ sendOpNV: arg = %d\n",arg)); - PutArgN(i, arg); - } - arg = (StgWord) nelem; - PutArgN(narg, arg); - -/* for (i=0; i < nelem; ++i) fprintf(stderr, "%d ",datablock[i]); */ -/* fprintf(stderr," in sendOpNV\n");*/ - - PutArgs(datablock, nelem); - va_end(ap); - - pvm_send(task, op); -} - -/* - * sendOpN take a variable size array argument, whose size is given by - * {\em n}. For example, - * - * sendOpN( PP_STATS, StatsTask, 3, stats_array); - */ - -//@cindex sendOpN -void -sendOpN(OpCode op, GlobalTaskId task, int n, StgPtr args) -{ - long arg; - - traceSendOp(op, task, 0, 0); - - pvm_initsend(PvmDataRaw); - arg = (long) n; - PutArgN(0, arg); - PutArgs(args, n); - pvm_send(task, op); -} - -/* - * broadcastOpN is as sendOpN but broadcasts to all members of a group. - */ - -void -broadcastOpN(OpCode op, char *group, int n, StgPtr args) -{ - long arg; - - //traceSendOp(op, task, 0, 0); - - pvm_initsend(PvmDataRaw); - arg = (long) n; - PutArgN(0, arg); - PutArgs(args, n); - pvm_bcast(group, op); -} - -/* - waitForPEOp waits for a packet from global task who with the - OpCode op. If ignore is true all other messages are simply ignored; - otherwise they are handled by processUnexpected. - */ -//@cindex waitForPEOp -rtsPacket -waitForPEOp(OpCode op, GlobalTaskId who, void(*processUnexpected)(rtsPacket) ) -{ - rtsPacket p; - int nbytes; - OpCode opCode; - GlobalTaskId sender_id; - rtsBool match; - - IF_PAR_DEBUG(verbose, - fprintf(stderr,"~~ waitForPEOp: expecting op = %x (%s), who = [%x]\n", - op, getOpName(op), who)); - - do { - while((p = pvm_recv(ANY_TASK,ANY_OPCODE)) < 0) - pvm_perror("waitForPEOp: Waiting for PEOp"); - - pvm_bufinfo( p, &nbytes, &opCode, &sender_id ); - match = (op == ANY_OPCODE || op == opCode) && - (who == ANY_TASK || who == sender_id); - - if (match) { - IF_PAR_DEBUG(verbose, - fprintf(stderr, - "~~waitForPEOp: Qapla! received: OpCode = %#x (%s), sender_id = [%x]", - opCode, getOpName(opCode), sender_id)); - - return(p); - } - - /* Handle the unexpected OpCodes */ - if (processUnexpected!=NULL) { - (*processUnexpected)(p); - } else { - IF_PAR_DEBUG(verbose, - fprintf(stderr, - "~~ waitForPEOp: ignoring OpCode = %#x (%s), sender_id = [%x]", - opCode, getOpName(opCode), sender_id)); - } - - } while(rtsTrue); -} - -/* - processUnexpected processes unexpected messages. If the message is a - FINISH it exits the prgram, and PVM gracefully - */ -//@cindex processUnexpectedMessage -void -processUnexpectedMessage(rtsPacket packet) { - OpCode opCode = getOpcode(packet); - - IF_PAR_DEBUG(verbose, - GlobalTaskId sender = senderTask(packet); - fprintf(stderr,"~~ [%x] processUnexpected: Received %x (%s), sender %x\n", - mytid, opCode, getOpName(opCode), sender)); - - switch (opCode) { - case PP_FINISH: - stg_exit(EXIT_SUCCESS); - break; - - /* Anything we're not prepared to deal with. Note that ALL OpCodes - are discarded during termination -- this helps prevent bizarre - race conditions. */ - default: - // if (!GlobalStopPending) - { - GlobalTaskId errorTask; - OpCode opCode; - - getOpcodeAndSender(packet, &opCode, &errorTask); - fprintf(stderr,"== Task %x: Unexpected OpCode %x from %x in processUnexpected", - mytid, opCode, errorTask ); - - stg_exit(EXIT_FAILURE); - } - } -} - -//@cindex getOpcode -OpCode -getOpcode(rtsPacket p) -{ - int nbytes; - OpCode OpCode; - GlobalTaskId sender_id; - /* read PVM buffer */ - pvm_bufinfo(p, &nbytes, &OpCode, &sender_id); - /* return tag of the buffer as opcode */ - return(OpCode); -} - -//@cindex getOpcodeAndSender -void -getOpcodeAndSender(rtsPacket p, OpCode *opCodep, GlobalTaskId *senderIdp) -{ - int nbytes; - /* read PVM buffer */ - pvm_bufinfo(p, &nbytes, opCodep, senderIdp); -} - -//@cindex senderTask -GlobalTaskId -senderTask(rtsPacket p) -{ - int nbytes; - OpCode opCode; - GlobalTaskId sender_id; - /* read PVM buffer */ - pvm_bufinfo(p, &nbytes, &opCode, &sender_id); - return(sender_id); -} - -/* - * startUpPE does the low-level comms specific startup stuff for a - * PE. It initialises the comms system, joins the appropriate groups - * allocates the PE buffer - */ - -//@cindex startUpPE -void -startUpPE(void) -{ - mytid = _my_gtid; /* Initialise PVM and get task id into global var.*/ - - IF_PAR_DEBUG(verbose, - fprintf(stderr,"== [%x] PEStartup: Task id = [%x], No. PEs = %d \n", - mytid, mytid, nPEs)); - checkComms(pvm_joingroup(PEGROUP), "PEStartup"); - IF_PAR_DEBUG(verbose, - fprintf(stderr,"== [%x] PEStartup: Joined PEGROUP\n", mytid)); -} - -/* - * PEShutdown does the low-level comms-specific shutdown stuff for a - * single PE. It leaves the groups and then exits from pvm. - */ -//@cindex shutDownPE -void -shutDownPE(void) -{ - IF_PAR_DEBUG(verbose, - fprintf(stderr, "== [%x] PEshutdown\n", mytid)); - - checkComms(pvm_lvgroup(PEGROUP),"PEShutDown"); - checkComms(pvm_exit(),"PEShutDown"); -} - -/* - Extract the exit code out of a PP_FINISH packet (used in SysMan) -*/ -int -getExitCode(int nbytes, GlobalTaskId *sender_idp) { - int exitCode=0; - - if (nbytes==4) { // Notification from a task doing pvm_exit - GetArgs(sender_idp,1); // Presumably this must be MainPE Id - exitCode = -1; - } else if (nbytes==8) { // Doing a controlled shutdown - GetArgs(&exitCode,1); // HACK: controlled shutdown == 2 values - GetArgs(&exitCode,1); - } else { - exitCode = -2; // everything else - } - return exitCode; -} - -#endif /* PAR -- whole file */ - -//@node Index, , Auxiliary functions, GUM Low-Level Inter-Task Communication -//@subsection Index - -//@index -//* getOpName:: @cindex\s-+getOpName -//* traceSendOp:: @cindex\s-+traceSendOp -//* sendOp:: @cindex\s-+sendOp -//* sendOp1:: @cindex\s-+sendOp1 -//* sendOp2:: @cindex\s-+sendOp2 -//* sendOpV:: @cindex\s-+sendOpV -//* sendOpNV:: @cindex\s-+sendOpNV -//* sendOpN:: @cindex\s-+sendOpN -//* waitForPEOp:: @cindex\s-+waitForPEOp -//* processUnexpectedMessage:: @cindex\s-+processUnexpectedMessage -//* getOpcode:: @cindex\s-+getOpcode -//* getOpcodeAndSender:: @cindex\s-+getOpcodeAndSender -//* senderTask:: @cindex\s-+senderTask -//* startUpPE:: @cindex\s-+startUpPE -//* shutDownPE:: @cindex\s-+shutDownPE -//@end index diff --git a/rts/parallel/PEOpCodes.h b/rts/parallel/PEOpCodes.h deleted file mode 100644 index 2d18b439f2..0000000000 --- a/rts/parallel/PEOpCodes.h +++ /dev/null @@ -1,58 +0,0 @@ -#ifndef PEOPCODES_H -#define PEOPCODES_H - -/************************************************************************ -* PEOpCodes.h * -* * -* This file contains definitions for all the GUM PE Opcodes * -* It's based on the GRAPH for PVM version * -* Phil Trinder, Glasgow University 8th December 1994 * -* * - RFPointon, December 1999 - - removed PP_SYSMAN_TID, introduced PP_READY - - removed PP_MAIN_TASK, introduced PP_NEWPE - - added PP_REVAL -************************************************************************/ - -#define REPLY_OK 0x00 - -/*Startup + Shutdown*/ -#define PP_READY 0x50 /* sent PEs -> SysMan */ -#define PP_NEWPE 0x51 /* sent via newHost notify -> SysMan */ -#define PP_FINISH 0x52 /* sent PEs & via taskExit notfiy -> SysMan */ -#define PP_PETIDS 0x53 /* sent sysman -> PEs */ - -/* Stats stuff */ -#define PP_STATS 0x54 -#define PP_STATS_ON 0x55 -#define PP_STATS_OFF 0x56 - -//#define PP_FAIL 0x57 - -/*Garbage Collection*/ -#define PP_GC_INIT 0x58 -#define PP_FULL_SYSTEM 0x59 -#define PP_GC_POLL 0x5a - -/*GUM Messages*/ -#define PP_FETCH 0x5b -#define PP_RESUME 0x5c -#define PP_ACK 0x5d -#define PP_FISH 0x5e -#define PP_SCHEDULE 0x5f -#define PP_FREE 0x60 -#define PP_REVAL 0x61 - - -#define MIN_PEOPS 0x50 -#define MAX_PEOPS 0x61 - -#define PEOP_NAMES "Ready", "NewPE", \ - "Finish", "PETIDS", \ - "Stats", "Stats_On", "Stats_Off", \ - "Fail", \ - "GCInit", "FullSystem", "GCPoll", \ - "Fetch","Resume","ACK","Fish","Schedule", \ - "Free","REval" - -#endif /* PEOPCODES_H */ diff --git a/rts/parallel/Pack.c b/rts/parallel/Pack.c deleted file mode 100644 index 58fe7ed2db..0000000000 --- a/rts/parallel/Pack.c +++ /dev/null @@ -1,4293 +0,0 @@ -/* - Time-stamp: <2009-12-02 12:26:34 simonmar> - - Graph packing and unpacking code for sending it to another processor - and retrieving the original graph structure from the packet. - In the old RTS the code was split into Pack.c and Unpack.c (now deceased) - Used in GUM and GrAnSim. - - The GrAnSim version of the code defines routines for *simulating* the - packing of closures in the same way it is done in the parallel runtime - system. Basically GrAnSim only puts the addresses of the closures to be - transferred into a buffer. This buffer will then be associated with the - event of transferring the graph. When this event is scheduled, the - @UnpackGraph@ routine is called and the buffer can be discarded - afterwards. - - Note that in GranSim we need many buffers, not just one per PE. -*/ - -//@node Graph packing, , , -//@section Graph packing - -#if defined(PAR) || defined(GRAN) /* whole file */ - -//@menu -//* Includes:: -//* Prototypes:: -//* Global variables:: -//* ADT of Closure Queues:: -//* Initialisation for packing:: -//* Packing Functions:: -//* Low level packing routines:: -//* Unpacking routines:: -//* Aux fcts for packing:: -//* Printing Packet Contents:: -//* End of file:: -//@end menu -//*/ - -//@node Includes, Prototypes, Graph packing, Graph packing -//@subsection Includes - -#include "Rts.h" -#include "RtsFlags.h" -#include "RtsUtils.h" -#include "ClosureTypes.h" -#include "Storage.h" -#include "Hash.h" -#include "Parallel.h" -#include "GranSimRts.h" -#include "ParallelRts.h" -# if defined(DEBUG) -# include "sm/Sanity.h" -# include "Printer.h" -# include "ParallelDebug.h" -# endif -#include "FetchMe.h" - -/* Which RTS flag should be used to get the size of the pack buffer ? */ -# if defined(PAR) -# define RTS_PACK_BUFFER_SIZE RtsFlags.ParFlags.packBufferSize -# else /* GRAN */ -# define RTS_PACK_BUFFER_SIZE RtsFlags.GranFlags.packBufferSize -# endif - -//@node Prototypes, Global variables, Includes, Graph packing -//@subsection Prototypes -/* - Code declarations. -*/ - -//@node ADT of closure queues, Init for packing, Prototypes, Prototypes -//@subsubsection ADT of closure queues - -static inline void InitClosureQueue(void); -static inline rtsBool QueueEmpty(void); -static inline void QueueClosure(StgClosure *closure); -static inline StgClosure *DeQueueClosure(void); - -//@node Init for packing, Packing routines, ADT of closure queues, Prototypes -//@subsubsection Init for packing - -static void InitPacking(rtsBool unpack); -# if defined(PAR) -rtsBool InitPackBuffer(void); -# elif defined(GRAN) -rtsPackBuffer *InstantiatePackBuffer (void); -static void reallocPackBuffer (void); -# endif - -//@node Packing routines, Low level packing fcts, Init for packing, Prototypes -//@subsubsection Packing routines - -static void PackClosure (StgClosure *closure); - -//@node Low level packing fcts, Unpacking routines, Packing routines, Prototypes -//@subsubsection Low level packing fcts - -# if defined(GRAN) -static void Pack (StgClosure *data); -# else -static void Pack (StgWord data); - -static void PackGeneric(StgClosure *closure); -static void PackArray(StgClosure *closure); -static void PackPLC (StgPtr addr); -static void PackOffset (int offset); -static void PackPAP(StgPAP *pap); -static rtsPackBuffer *PackTSO(StgTSO *tso, nat *packBufferSize); -static rtsPackBuffer *PackStkO(StgPtr stko, nat *packBufferSize); -static void PackFetchMe(StgClosure *closure); - -static void GlobaliseAndPackGA (StgClosure *closure); -# endif - -//@node Unpacking routines, Aux fcts for packing, Low level packing fcts, Prototypes -//@subsubsection Unpacking routines - -# if defined(PAR) -void InitPendingGABuffer(nat size); -void CommonUp(StgClosure *src, StgClosure *dst); -static StgClosure *SetGAandCommonUp(globalAddr *gaP, StgClosure *closure, - rtsBool hasGA); -static nat FillInClosure(StgWord ***bufptrP, StgClosure *graph); -static void LocateNextParent(StgClosure **parentP, - nat *pptrP, nat *pptrsP, nat *sizeP); -StgClosure *UnpackGraph(rtsPackBuffer *packBuffer, - globalAddr **gamap, - nat *nGAs); -static StgClosure *UnpackClosure (StgWord ***bufptrP, StgClosure **graphP, - globalAddr *ga); -static StgWord **UnpackGA(StgWord **bufptr, globalAddr *ga); -static StgClosure *UnpackOffset(globalAddr *ga); -static StgClosure *UnpackPLC(globalAddr *ga); -static void UnpackArray(StgWord ***bufptrP, StgClosure *graph); -static nat UnpackPAP(StgWord ***bufptrP, StgClosure *graph); - -# elif defined(GRAN) -void CommonUp(StgClosure *src, StgClosure *dst); -StgClosure *UnpackGraph(rtsPackBuffer* buffer); -#endif - -//@node Aux fcts for packing, , Unpacking routines, Prototypes -//@subsubsection Aux fcts for packing - -# if defined(PAR) -static void DonePacking(void); -static void AmPacking(StgClosure *closure); -static int OffsetFor(StgClosure *closure); -static rtsBool NotYetPacking(int offset); -static inline rtsBool RoomToPack (nat size, nat ptrs); -static inline rtsBool isOffset(globalAddr *ga); -static inline rtsBool isFixed(globalAddr *ga); -static inline rtsBool isConstr(globalAddr *ga); -static inline rtsBool isUnglobalised(globalAddr *ga); -# elif defined(GRAN) -static void DonePacking(void); -static rtsBool NotYetPacking(StgClosure *closure); -# endif - -//@node Global variables, ADT of Closure Queues, Prototypes, Graph packing -//@subsection Global variables -/* - Static data declarations -*/ - -static nat pack_locn, /* ptr to first free loc in pack buffer */ - clq_size, clq_pos, - buf_id = 1; /* identifier for buffer */ -static nat unpacked_size; -static rtsBool roomInBuffer; -#if defined(PAR) -static GlobalTaskId dest_gtid=0; /* destination for message to send */ -#endif - -/* - The pack buffer - To be pedantic: in GrAnSim we're packing *addresses* of closures, - not the closures themselves. -*/ -static rtsPackBuffer *globalPackBuffer = NULL, /* for packing a graph */ - *globalUnpackBuffer = NULL; /* for unpacking a graph */ - - -/* - Bit of a hack for testing if a closure is the root of the graph. This is - set in @PackNearbyGraph@ and tested in @PackClosure@. -*/ - -static nat packed_thunks = 0; -static StgClosure *graph_root; - -# if defined(PAR) -/* - The offset hash table is used during packing to record the location in - the pack buffer of each closure which is packed. -*/ -//@cindex offsetTable -static HashTable *offsetTable; - -//@cindex PendingGABuffer -static globalAddr *PendingGABuffer, *gaga; - -# endif /* PAR */ - - -//@node ADT of Closure Queues, Initialisation for packing, Global variables, Graph packing -//@subsection ADT of Closure Queues - -//@menu -//* Closure Queues:: -//* Init routines:: -//* Basic routines:: -//@end menu - -//@node Closure Queues, Init routines, ADT of Closure Queues, ADT of Closure Queues -//@subsubsection Closure Queues -/* - Closure Queues - - These routines manage the closure queue. -*/ - -static nat clq_pos, clq_size; - -static StgClosure **ClosureQueue = NULL; /* HWL: init in main */ - -#if defined(DEBUG) -static char graphFingerPrint[MAX_FINGER_PRINT_LEN]; -#endif - -//@node Init routines, Basic routines, Closure Queues, ADT of Closure Queues -//@subsubsection Init routines - -/* @InitClosureQueue@ allocates and initialises the closure queue. */ - -//@cindex InitClosureQueue -static inline void -InitClosureQueue(void) -{ - clq_pos = clq_size = 0; - - if (ClosureQueue==NULL) - ClosureQueue = (StgClosure**) stgMallocWords(RTS_PACK_BUFFER_SIZE, - "InitClosureQueue"); -} - -//@node Basic routines, Types of Global Addresses, Init routines, ADT of Closure Queues -//@subsubsection Basic routines - -/* - QueueEmpty returns rtsTrue if the closure queue is empty; rtsFalse otherwise. -*/ - -//@cindex QueueEmpty -static inline rtsBool -QueueEmpty(void) -{ - return(clq_pos >= clq_size); -} - -/* QueueClosure adds its argument to the closure queue. */ - -//@cindex QueueClosure -static inline void -QueueClosure(closure) -StgClosure *closure; -{ - if(clq_size < RTS_PACK_BUFFER_SIZE ) { - IF_PAR_DEBUG(paranoia, - belch(">__> <<%d>> Q: %p (%s); %d elems in q", - globalPackBuffer->id, closure, info_type(closure), clq_size-clq_pos)); - ClosureQueue[clq_size++] = closure; - } else { - barf("Closure Queue Overflow (EnQueueing %p (%s))", - closure, info_type(closure)); - } -} - -/* DeQueueClosure returns the head of the closure queue. */ - -//@cindex DeQueueClosure -static inline StgClosure * -DeQueueClosure(void) -{ - if(!QueueEmpty()) { - IF_PAR_DEBUG(paranoia, - belch(">__> <<%d>> DeQ: %p (%s); %d elems in q", - globalPackBuffer->id, ClosureQueue[clq_pos], info_type(ClosureQueue[clq_pos]), - clq_size-clq_pos)); - return(ClosureQueue[clq_pos++]); - } else { - return((StgClosure*)NULL); - } -} - -/* DeQueueClosure returns the head of the closure queue. */ - -#if defined(DEBUG) -//@cindex PrintQueueClosure -static void -PrintQueueClosure(void) -{ - nat i; - - fputs("Closure queue:", stderr); - for (i=clq_pos; i < clq_size; i++) - fprintf(stderr, "%p (%s), ", - (StgClosure *)ClosureQueue[clq_pos++], - info_type(ClosureQueue[clq_pos++])); - fputc('\n', stderr); -} -#endif - -//@node Types of Global Addresses, , Basic routines, ADT of Closure Queues -//@subsubsection Types of Global Addresses - -/* - Types of Global Addresses - - These routines determine whether a GA is one of a number of special types - of GA. -*/ - -# if defined(PAR) -//@cindex isOffset -static inline rtsBool -isOffset(globalAddr *ga) -{ - return (ga->weight == 1U && ga->payload.gc.gtid == (GlobalTaskId)0); -} - -//@cindex isFixed -static inline rtsBool -isFixed(globalAddr *ga) -{ - return (ga->weight == 0U); -} - -//@cindex isConstr -static inline rtsBool -isConstr(globalAddr *ga) -{ - return (ga->weight == 2U); -} - -//@cindex isUnglobalised -static inline rtsBool -isUnglobalised(globalAddr *ga) -{ - return (ga->weight == 2U); -} -# endif - -//@node Initialisation for packing, Packing Functions, ADT of Closure Queues, Graph packing -//@subsection Initialisation for packing -/* - Simple Packing Routines - - About packet sizes in GrAnSim: In GrAnSim we use a malloced block of - gransim_pack_buffer_size words to simulate a packet of pack_buffer_size - words. In the simulated PackBuffer we only keep the addresses of the - closures that would be packed in the parallel system (see Pack). To - decide if a packet overflow occurs pack_buffer_size must be compared - versus unpacked_size (see RoomToPack). Currently, there is no multi - packet strategy implemented, so in the case of an overflow we just stop - adding closures to the closure queue. If an overflow of the simulated - packet occurs, we just realloc some more space for it and carry on as - usual. -- HWL -*/ - -# if defined(GRAN) -rtsPackBuffer * -InstantiatePackBuffer (void) { - extern rtsPackBuffer *globalPackBuffer; - - globalPackBuffer = (rtsPackBuffer *) stgMallocWords(sizeofW(rtsPackBuffer), - "InstantiatePackBuffer: failed to alloc packBuffer"); - globalPackBuffer->size = RtsFlags.GranFlags.packBufferSize_internal; - globalPackBuffer->buffer = (StgWord **) stgMallocWords(RtsFlags.GranFlags.packBufferSize_internal, - "InstantiatePackBuffer: failed to alloc GranSim internal packBuffer"); - /* NB: gransim_pack_buffer_size instead of pack_buffer_size -- HWL */ - /* stgMallocWords is now simple allocate in Storage.c */ - - return (globalPackBuffer); -} - -/* - Reallocate the GranSim internal pack buffer to make room for more closure - pointers. This is independent of the check for packet overflow as in GUM -*/ -static void -reallocPackBuffer (void) { - - ASSERT(pack_locn >= (int)globalPackBuffer->size+sizeofW(rtsPackBuffer)); - - IF_GRAN_DEBUG(packBuffer, - belch("** Increasing size of PackBuffer %p to %d words (PE %u @ %d)\n", - globalPackBuffer, globalPackBuffer->size+REALLOC_SZ, - CurrentProc, CurrentTime[CurrentProc])); - - globalPackBuffer = (rtsPackBuffer*)realloc(globalPackBuffer, - sizeof(StgClosure*)*(REALLOC_SZ + - (int)globalPackBuffer->size + - sizeofW(rtsPackBuffer))) ; - if (globalPackBuffer==(rtsPackBuffer*)NULL) - barf("Failing to realloc %d more words for PackBuffer %p (PE %u @ %d)\n", - REALLOC_SZ, globalPackBuffer, CurrentProc, CurrentTime[CurrentProc]); - - globalPackBuffer->size += REALLOC_SZ; - - ASSERT(pack_locn < globalPackBuffer->size+sizeofW(rtsPackBuffer)); -} -# endif - -# if defined(PAR) -/* @initPacking@ initialises the packing buffer etc. */ -//@cindex InitPackBuffer -rtsBool -InitPackBuffer(void) -{ - if (globalPackBuffer==(rtsPackBuffer*)NULL) { - if ((globalPackBuffer = (rtsPackBuffer *) - stgMallocWords(sizeofW(rtsPackBuffer)+RtsFlags.ParFlags.packBufferSize+DEBUG_HEADROOM, - "InitPackBuffer")) == NULL) - return rtsFalse; - } - return rtsTrue; -} - -# endif -//@cindex InitPacking -static void -InitPacking(rtsBool unpack) -{ -# if defined(GRAN) - globalPackBuffer = InstantiatePackBuffer(); /* for GrAnSim only -- HWL */ - /* NB: free in UnpackGraph */ -# elif defined(PAR) - if (unpack) { - /* allocate a GA-to-GA map (needed for ACK message) */ - InitPendingGABuffer(RtsFlags.ParFlags.packBufferSize); - } else { - /* allocate memory to pack the graph into */ - InitPackBuffer(); - } -# endif - /* init queue of closures seen during packing */ - InitClosureQueue(); - - if (unpack) - return; - - globalPackBuffer->id = buf_id++; /* buffer id are only used for debugging! */ - pack_locn = 0; /* the index into the actual pack buffer */ - unpacked_size = 0; /* the size of the whole graph when unpacked */ - roomInBuffer = rtsTrue; - packed_thunks = 0; /* total number of thunks packed so far */ -# if defined(PAR) - offsetTable = allocHashTable(); -# endif -} - -//@node Packing Functions, Low level packing routines, Initialisation for packing, Graph packing -//@subsection Packing Functions - -//@menu -//* Packing Sections of Nearby Graph:: -//* Packing Closures:: -//@end menu - -//@node Packing Sections of Nearby Graph, Packing Closures, Packing Functions, Packing Functions -//@subsubsection Packing Sections of Nearby Graph -/* - Packing Sections of Nearby Graph - - @PackNearbyGraph@ packs a closure and associated graph into a static - buffer (@PackBuffer@). It returns the address of this buffer and the - size of the data packed into the buffer (in its second parameter, - @packBufferSize@). The associated graph is packed in a depth first - manner, hence it uses an explicit queue of closures to be packed rather - than simply using a recursive algorithm. Once the packet is full, - closures (other than primitive arrays) are packed as FetchMes, and their - children are not queued for packing. */ - -//@cindex PackNearbyGraph - -/* NB: this code is shared between GranSim and GUM; - tso only used in GranSim */ -rtsPackBuffer * -PackNearbyGraph(closure, tso, packBufferSize, dest) -StgClosure* closure; -StgTSO* tso; -nat *packBufferSize; -GlobalTaskId dest; -{ - IF_PAR_DEBUG(resume, - graphFingerPrint[0] = '\0'); - - ASSERT(RTS_PACK_BUFFER_SIZE > 0); - ASSERT(_HS==1); // HWL HACK; compile time constant - -#if defined(PAR_TICKY) // HWL HAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACK - PAR_TICKY_PACK_NEARBY_GRAPH_START(); -#endif - - /* ToDo: check that we have enough heap for the packet - ngoq ngo' - if (Hp + PACK_HEAP_REQUIRED > HpLim) - return NULL; - */ - InitPacking(rtsFalse); -# if defined(PAR) - dest_gtid=dest; //-1 to disable -# elif defined(GRAN) - graph_root = closure; -# endif - - IF_GRAN_DEBUG(pack, - belch(">>> Packing <<%d>> (buffer @ %p); graph root @ %p [PE %d]\n demanded by TSO %d (%p) [PE %u]", - globalPackBuffer->id, globalPackBuffer, closure, where_is(closure), - tso->id, tso, where_is((StgClosure*)tso))); - - IF_GRAN_DEBUG(pack, - belch("** PrintGraph of %p is:", closure); - PrintGraph(closure,0)); - - IF_PAR_DEBUG(resume, - GraphFingerPrint(closure, graphFingerPrint); - ASSERT(strlen(graphFingerPrint)<=MAX_FINGER_PRINT_LEN); - belch(">>> Packing <<%d>> (buffer @ %p); graph root @ %p [%x]\n demanded by TSO %d (%p); Finger-print is\n {%s}", - globalPackBuffer->id, globalPackBuffer, closure, mytid, - tso->id, tso, graphFingerPrint)); - - IF_PAR_DEBUG(packet, - belch("** PrintGraph of %p is:", closure); - belch("** pack_locn=%d", pack_locn); - PrintGraph(closure,0)); - - QueueClosure(closure); - do { - PackClosure(DeQueueClosure()); - } while (!QueueEmpty()); - -# if defined(PAR) - - /* Record how much space the graph needs in packet and in heap */ - globalPackBuffer->tso = tso; // currently unused, I think (debugging?) - globalPackBuffer->unpacked_size = unpacked_size; - globalPackBuffer->size = pack_locn; - - /* Check for buffer overflow (again) */ - ASSERT(pack_locn <= RtsFlags.ParFlags.packBufferSize+DEBUG_HEADROOM); - IF_DEBUG(sanity, // write magic end-of-buffer word - globalPackBuffer->buffer[pack_locn] = END_OF_BUFFER_MARKER); - *packBufferSize = pack_locn; - -# else /* GRAN */ - - /* Record how much space is needed to unpack the graph */ - // PackBuffer[PACK_FLAG_LOCN] = (P_) MAGIC_PACK_FLAG; for testing - globalPackBuffer->tso = tso; - globalPackBuffer->unpacked_size = unpacked_size; - - // ASSERT(pack_locn <= PackBuffer[PACK_SIZE_LOCN]+PACK_HDR_SIZE); - /* ToDo: Print an earlier, more meaningful message */ - if (pack_locn==0) /* i.e. packet is empty */ - barf("EMPTY PACKET! Can't transfer closure %p at all!!\n", - closure); - globalPackBuffer->size = pack_locn; - *packBufferSize = pack_locn; - -# endif - - DonePacking(); /* {GrAnSim}vaD 'ut'Ha' */ - -# if defined(GRAN) - IF_GRAN_DEBUG(pack , - belch("** Finished <<%d>> packing graph %p; closures packed: %d; thunks packed: %d; size of graph: %d", - globalPackBuffer->id, closure, globalPackBuffer->size, packed_thunks, globalPackBuffer->unpacked_size)); - if (RtsFlags.GranFlags.GranSimStats.Global) { - globalGranStats.tot_packets++; - globalGranStats.tot_packet_size += pack_locn; - } - - IF_GRAN_DEBUG(pack, PrintPacket(globalPackBuffer)); -# elif defined(PAR) - IF_PAR_DEBUG(packet, - belch("** Finished <<%d>> packing graph %p (%s); closures packed: %d; thunks packed: %d; size of graph: %d", - globalPackBuffer->id, closure, info_type(closure), - globalPackBuffer->size, packed_thunks, - globalPackBuffer->unpacked_size));; - - IF_DEBUG(sanity, // do a sanity check on the packet just constructed - checkPacket(globalPackBuffer)); -# endif /* GRAN */ - -#if defined(PAR_TICKY) // HWL HAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACK - PAR_TICKY_PACK_NEARBY_GRAPH_END(globalPackBuffer->size, packed_thunks); -#endif - - return (globalPackBuffer); -} - -//@cindex PackOneNode - -# if defined(GRAN) -/* This version is used when the node is already local */ - -rtsPackBuffer * -PackOneNode(closure, tso, packBufferSize) -StgClosure* closure; -StgTSO* tso; -nat *packBufferSize; -{ - extern rtsPackBuffer *globalPackBuffer; - int i, clpack_locn; - - InitPacking(rtsFalse); - - IF_GRAN_DEBUG(pack, - belch("** PackOneNode: %p (%s)[PE %d] requested by TSO %d (%p) [PE %d]", - closure, info_type(closure), - where_is(closure), tso->id, tso, where_is((StgClosure *)tso))); - - Pack(closure); - - /* Record how much space is needed to unpack the graph */ - globalPackBuffer->tso = tso; - globalPackBuffer->unpacked_size = unpacked_size; - - /* Set the size parameter */ - ASSERT(pack_locn <= RTS_PACK_BUFFER_SIZE); - globalPackBuffer->size = pack_locn; - *packBufferSize = pack_locn; - - if (RtsFlags.GranFlags.GranSimStats.Global) { - globalGranStats.tot_packets++; - globalGranStats.tot_packet_size += pack_locn; - } - IF_GRAN_DEBUG(pack, - PrintPacket(globalPackBuffer)); - - return (globalPackBuffer); -} -# endif /* GRAN */ - -#if defined(GRAN) - -/* - PackTSO and PackStkO are entry points for two special kinds of closure - which are used in the parallel RTS. Compared with other closures they - are rather awkward to pack because they don't follow the normal closure - layout (where all pointers occur before all non-pointers). Luckily, - they're only needed when migrating threads between processors. */ - -//@cindex PackTSO -rtsPackBuffer* -PackTSO(tso, packBufferSize) -StgTSO *tso; -nat *packBufferSize; -{ - extern rtsPackBuffer *globalPackBuffer; - IF_GRAN_DEBUG(pack, - belch("** Packing TSO %d (%p)", tso->id, tso)); - *packBufferSize = 0; - // PackBuffer[0] = PackBuffer[1] = 0; ??? - return(globalPackBuffer); -} - -//@cindex PackStkO -static rtsPackBuffer* -PackStkO(stko, packBufferSize) -StgPtr stko; -nat *packBufferSize; -{ - extern rtsPackBuffer *globalPackBuffer; - IF_GRAN_DEBUG(pack, - belch("** Packing STKO %p", stko)); - *packBufferSize = 0; - // PackBuffer[0] = PackBuffer[1] = 0; - return(globalPackBuffer); -} - -static void -PackFetchMe(StgClosure *closure) -{ - barf("{PackFetchMe}Daq Qagh: no FetchMe closures in GRAN!"); -} - -#elif defined(PAR) - -static rtsPackBuffer* -PackTSO(tso, packBufferSize) -StgTSO *tso; -nat *packBufferSize; -{ - barf("{PackTSO}Daq Qagh: trying to pack a TSO %d (%p) of size %d; thread migrations not supported, yet", - tso->id, tso, packBufferSize); -} - -rtsPackBuffer* -PackStkO(stko, packBufferSize) -StgPtr stko; -nat *packBufferSize; -{ - barf("{PackStkO}Daq Qagh: trying to pack a STKO (%p) of size %d; thread migrations not supported, yet", - stko, packBufferSize); -} - -//@cindex PackFetchMe -static void -PackFetchMe(StgClosure *closure) -{ - StgInfoTable *ip; - nat i; - int offset; -#if defined(DEBUG) - nat x = pack_locn; -#endif - -#if defined(GRAN) - barf("{PackFetchMe}Daq Qagh: no FetchMe closures in GRAN!"); -#else - offset = OffsetFor(closure); - if (!NotYetPacking(offset)) { - IF_PAR_DEBUG(pack, - belch("*>.. Packing FETCH_ME for closure %p (s) as offset to %d", - closure, info_type(closure), offset)); - PackOffset(offset); - // unpacked_size += 0; // unpacked_size unchanged (closure is shared!!) - return; - } - - /* Need a GA even when packing a constructed FETCH_ME (cruel world!) */ - AmPacking(closure); - /* FMs must be always globalised */ - GlobaliseAndPackGA(closure); - - IF_PAR_DEBUG(pack, - belch("*>.. Packing FETCH_ME for closure %p (%s) with GA: ((%x, %d, %x))", - closure, info_type(closure), - globalPackBuffer->buffer[pack_locn-2], - globalPackBuffer->buffer[pack_locn-1], - globalPackBuffer->buffer[pack_locn-3])); - - /* Pack a FetchMe closure instead of closure */ - ip = &stg_FETCH_ME_info; - /* this assumes that the info ptr is always the first word in a closure*/ - Pack((StgWord)ip); - for (i = 1; i < _HS; ++i) // pack rest of fixed header - Pack((StgWord)*(((StgPtr)closure)+i)); - - unpacked_size += sizeofW(StgFetchMe); - /* size of FETCHME in packed is the same as that constant */ - ASSERT(pack_locn-x==PACK_FETCHME_SIZE); - /* In the pack buffer the pointer to a GA (in the FetchMe closure) - is expanded to the full GA; this is a compile-time const */ - //ASSERT(PACK_FETCHME_SIZE == sizeofW(StgFetchMe)-1+PACK_GA_SIZE); -#endif -} - -#endif - -#ifdef DIST -static void -PackRemoteRef(StgClosure *closure) -{ - StgInfoTable *ip; - nat i; - int offset; - - offset = OffsetFor(closure); - if (!NotYetPacking(offset)) { - PackOffset(offset); - unpacked_size += 2; - return; - } - - /* Need a GA even when packing a constructed REMOTE_REF (cruel world!) */ - AmPacking(closure); - - /* basically we just Globalise, but for sticky things we can't have multiple GAs, - so we must prevent the GAs being split. - - In returning things to the true sticky owner, this case is already handled, but for - anything else we just give up at the moment... This needs to be fixed! - */ - { globalAddr *ga; - ga = LAGAlookup(closure); // surely this ga must exist? - - // *************************************************************************** - // *************************************************************************** - // REMOTE_REF HACK - dual is in SetGAandCommonUp - // - prevents the weight from ever reaching zero - if(ga != NULL) - ga->weight=0x06660666; //anything apart from 0 really... - // *************************************************************************** - // *************************************************************************** - - if((ga != NULL)&&(ga->weight / 2 <= 2)) - barf("Cant split the weight any further when packing REMOTE_REF for closure %p (%s) with GA: ((%x, %d, %x))", - closure, info_type(closure), - ga->payload.gc.gtid, ga->payload.gc.slot, ga->weight); - } - GlobaliseAndPackGA(closure); - - IF_PAR_DEBUG(pack, - belch("*>.. Packing REMOTE_REF for closure %p (%s) with GA: ((%x, %d, %x))", - closure, info_type(closure), - globalPackBuffer->buffer[pack_locn-2], - globalPackBuffer->buffer[pack_locn-1], - globalPackBuffer->buffer[pack_locn-3])); - - /* Pack a REMOTE_REF closure instead of closure */ - ip = &stg_REMOTE_REF_info; - /* this assumes that the info ptr is always the first word in a closure*/ - Pack((StgWord)ip); - for (i = 1; i < _HS; ++i) // pack rest of fixed header - Pack((StgWord)*(((StgPtr)closure)+i)); - - unpacked_size += PACK_FETCHME_SIZE; -} -#endif /* DIST */ - -//@node Packing Closures, , Packing Sections of Nearby Graph, Packing Functions -//@subsubsection Packing Closures -/* - Packing Closures - - @PackClosure@ is the heart of the normal packing code. It packs a single - closure into the pack buffer, skipping over any indirections and - globalising it as necessary, queues any child pointers for further - packing, and turns it into a @FetchMe@ or revertible black hole (@RBH@) - locally if it was a thunk. Before the actual closure is packed, a - suitable global address (GA) is inserted in the pack buffer. There is - always room to pack a fetch-me to the closure (guaranteed by the - RoomToPack calculation), and this is packed if there is no room for the - entire closure. - - Space is allocated for any primitive array children of a closure, and - hence a primitive array can always be packed along with it's parent - closure. */ - -//@cindex PackClosure - -# if defined(PAR) - -void -PackClosure(closure) -StgClosure *closure; -{ - StgInfoTable *info; - nat clpack_locn; - - ASSERT(LOOKS_LIKE_GHC_INFO(get_itbl(closure))); - - closure = UNWIND_IND(closure); - /* now closure is the thing we want to pack */ - info = get_itbl(closure); - - clpack_locn = OffsetFor(closure); - - /* If the closure has been packed already, just pack an indirection to it - to guarantee that the graph doesn't become a tree when unpacked */ - if (!NotYetPacking(clpack_locn)) { - PackOffset(clpack_locn); - return; - } - - switch (info->type) { - - case CONSTR_CHARLIKE: - IF_PAR_DEBUG(pack, - belch("*>^^ Packing a charlike closure %d", - ((StgIntCharlikeClosure*)closure)->data)); - - PackPLC((StgPtr)CHARLIKE_CLOSURE(((StgIntCharlikeClosure*)closure)->data)); - // NB: unpacked_size of a PLC is 0 - return; - - case CONSTR_INTLIKE: - { - StgInt val = ((StgIntCharlikeClosure*)closure)->data; - - if ((val <= MAX_INTLIKE) && (val >= MIN_INTLIKE)) { - IF_PAR_DEBUG(pack, - belch("*>^^ Packing a small intlike %d as a PLC", - val)); - PackPLC((StgPtr)INTLIKE_CLOSURE(val)); - // NB: unpacked_size of a PLC is 0 - return; - } else { - IF_PAR_DEBUG(pack, - belch("*>^^ Packing a big intlike %d as a normal closure", - val)); - PackGeneric(closure); - return; - } - } - - case CONSTR: - case CONSTR_1_0: - case CONSTR_0_1: - case CONSTR_2_0: - case CONSTR_1_1: - case CONSTR_0_2: - /* it's a constructor (i.e. plain data) */ - IF_PAR_DEBUG(pack, - belch("*>^^ Packing a CONSTR %p (%s) using generic packing", - closure, info_type(closure))); - PackGeneric(closure); - return; - - case THUNK_STATIC: // ToDo: check whether that's ok - case FUN_STATIC: // ToDo: check whether that's ok - case CONSTR_STATIC: - case CONSTR_NOCAF_STATIC:// For now we ship indirections to CAFs: They are - // evaluated on each PE if needed - IF_PAR_DEBUG(pack, - belch("*>~~ Packing a %p (%s) as a PLC", - closure, info_type(closure))); - - PackPLC((StgPtr)closure); - // NB: unpacked_size of a PLC is 0 - return; - - case THUNK_SELECTOR: - { - StgClosure *selectee = ((StgSelector *)closure)->selectee; - - IF_PAR_DEBUG(pack, - belch("*>** Found THUNK_SELECTOR at %p (%s) pointing to %p (%s); using PackGeneric", - closure, info_type(closure), - selectee, info_type(selectee))); - PackGeneric(closure); - /* inlined code; probably could use PackGeneric - Pack((StgWord)(*(StgPtr)closure)); - Pack((StgWord)(selectee)); - QueueClosure(selectee); - unpacked_size += 2; - */ - } - return; - - case FUN: - case FUN_1_0: - case FUN_0_1: - case FUN_2_0: - case FUN_1_1: - case FUN_0_2: - case THUNK: - case THUNK_1_0: - case THUNK_0_1: - case THUNK_2_0: - case THUNK_1_1: - case THUNK_0_2: - PackGeneric(closure); - return; - - case AP_UPD: - case PAP: - /* - barf("*> Packing of PAP not implemented %p (%s)", - closure, info_type(closure)); - - Currently we don't pack PAPs; we pack a FETCH_ME to the closure, - instead. Note that since PAPs contain a chunk of stack as payload, - implementing packing of PAPs is a first step towards thread migration. - IF_PAR_DEBUG(pack, - belch("*>.. Packing a PAP closure at %p (%s) as a FETCH_ME", - closure, info_type(closure))); - PackFetchMe(closure); - */ - PackPAP((StgPAP *)closure); - return; - - case CAF_BLACKHOLE: - case BLACKHOLE: - case BLACKHOLE_BQ: - case SE_BLACKHOLE: - case SE_CAF_BLACKHOLE: - case RBH: - case FETCH_ME: - case FETCH_ME_BQ: - - /* If it's a (revertible) black-hole, pack a FetchMe closure to it */ - //ASSERT(pack_locn > PACK_HDR_SIZE); - - IF_PAR_DEBUG(pack, - belch("*>.. Packing a BH-like closure at %p (%s) as a FETCH_ME", - closure, info_type(closure))); - /* NB: in case of a FETCH_ME this might build up a chain of FETCH_MEs; - phps short-cut the GA here */ - PackFetchMe(closure); - return; - -#ifdef DIST - case REMOTE_REF: - IF_PAR_DEBUG(pack, - belch("*>.. Packing %p (%s) as a REMOTE_REF", - closure, info_type(closure))); - PackRemoteRef(closure); - /* we hopefully don't end up with a chain of REMOTE_REFs!!!!!!!!!! */ - - return; -#endif - - case TSO: - case MVAR: -#ifdef DIST - IF_PAR_DEBUG(pack, - belch("*>.. Packing %p (%s) as a RemoteRef", - closure, info_type(closure))); - PackRemoteRef(closure); -#else - barf("{Pack}Daq Qagh: Only GdH can pack %p (%s)", - closure, info_type(closure)); -#endif - return; - - case ARR_WORDS: - PackArray(closure); - return; - - case MUT_ARR_PTRS: - case MUT_ARR_PTRS_FROZEN: - case MUT_VAR: - /* - Eventually, this should use the same packing routine as ARR_WRODS - - GlobaliseAndPackGA(closure); - PackArray(closure); - return; - */ - barf("Qagh{Pack}Doq: packing of mutable closures not yet implemented: %p (%s)", - closure, info_type(closure)); - -# ifdef DEBUG - case BCO: - barf("{Pack}Daq Qagh: found BCO closure %p (%s); GUM hates interpreted code", - closure, info_type(closure)); - /* never reached */ - - // check error cases only in a debugging setup - case RET_BCO: - case RET_SMALL: - case RET_VEC_SMALL: - case RET_BIG: - case RET_VEC_BIG: - case RET_DYN: - barf("{Pack}Daq Qagh: found return vector %p (%s) when packing (thread migration not implemented)", - closure, info_type(closure)); - /* never reached */ - - case UPDATE_FRAME: - case STOP_FRAME: - case CATCH_FRAME: - case SEQ_FRAME: - barf("{Pack}Daq Qagh: found stack frame %p (%s) when packing (thread migration not implemented)", - closure, info_type(closure)); - /* never reached */ - - case BLOCKED_FETCH: - case EVACUATED: - /* something's very wrong */ - barf("{Pack}Daq Qagh: found %s (%p) when packing", - info_type(closure), closure); - /* never reached */ - - case IND: - case IND_OLDGEN: - case IND_PERM: - case IND_OLDGEN_PERM: - case IND_STATIC: - barf("Pack: found IND_... after shorting out indirections %d (%s)", - (nat)(info->type), info_type(closure)); - - case WEAK: - case FOREIGN: - case STABLE_NAME: - barf("Pack: found foreign thingy; not yet implemented in %d (%s)", - (nat)(info->type), info_type(closure)); -#endif - - default: - barf("Pack: strange closure %d", (nat)(info->type)); - } /* switch */ -} - -/* - Pack a constructor of unknown size. - Similar to PackGeneric but without creating GAs. -*/ -#if 0 -//@cindex PackConstr -static void -PackConstr(StgClosure *closure) -{ - StgInfoTable *info; - nat size, ptrs, nonptrs, vhs, i; - char str[80]; - - ASSERT(LOOKS_LIKE_GHC_INFO(closure->header.info)); - - /* get info about basic layout of the closure */ - info = get_closure_info(closure, &size, &ptrs, &nonptrs, &vhs, str); - - ASSERT(info->type == CONSTR || - info->type == CONSTR_1_0 || - info->type == CONSTR_0_1 || - info->type == CONSTR_2_0 || - info->type == CONSTR_1_1 || - info->type == CONSTR_0_2); - - IF_PAR_DEBUG(pack, - fprintf(stderr, "*>^^ packing a constructor at %p (%s) (size=%d, ptrs=%d, nonptrs=%d)\n", - closure, info_type(closure), size, ptrs, nonptrs)); - - /* Primitive arrays have gone; now we have (MUT_)ARR_WORDS etc */ - - if (!RoomToPack(PACK_GA_SIZE + _HS + vhs + nonptrs, ptrs)) { - IF_PAR_DEBUG(pack, - belch("*>&& pack buffer is full; packing FETCH_ME for closure %p (%s)", - closure, info_type(closure))); - PackFetchMe(closure); - return; - } - - /* Record the location of the GA */ - AmPacking(closure); - - /* Pack Constructor marker */ - Pack((StgWord)2); - - /* pack fixed and variable header */ - for (i = 0; i < _HS + vhs; ++i) - Pack((StgWord)*(((StgPtr)closure)+i)); - - /* register all ptrs for further packing */ - for (i = 0; i < ptrs; ++i) - QueueClosure(((StgClosure *) *(((StgPtr)closure)+(_HS+vhs)+i))); - - /* pack non-ptrs */ - for (i = 0; i < nonptrs; ++i) - Pack((StgWord)*(((StgPtr)closure)+(_HS+vhs)+ptrs+i)); -} -#endif - -/* - Generic packing code. - This code is performed for `ordinary' closures such as CONSTR, THUNK etc. -*/ -//@cindex PackGeneric -static void -PackGeneric(StgClosure *closure) -{ - StgInfoTable *info; - StgClosure *rbh; - nat size, ptrs, nonptrs, vhs, i, m; - char str[80]; - - ASSERT(LOOKS_LIKE_COOL_CLOSURE(closure)); - - /* get info about basic layout of the closure */ - info = get_closure_info(closure, &size, &ptrs, &nonptrs, &vhs, str); - - ASSERT(!IS_BLACK_HOLE(closure)); - - IF_PAR_DEBUG(pack, - fprintf(stderr, "*>== %p (%s): generic packing (size=%d, ptrs=%d, nonptrs=%d)\n", - closure, info_type(closure), size, ptrs, nonptrs)); - - /* packing strategies: how many thunks to add to a packet; - default is infinity i.e. RtsFlags.ParFlags.thunksToPack==0 */ - if (RtsFlags.ParFlags.thunksToPack && - packed_thunks >= RtsFlags.ParFlags.thunksToPack && - closure_THUNK(closure)) { - IF_PAR_DEBUG(pack, - belch("*>&& refusing to pack more than %d thunks per packet; packing FETCH_ME for closure %p (%s)", - packed_thunks, closure, info_type(closure))); - PackFetchMe(closure); - return; - } - - /* Primitive arrays have gone; now we have (MUT_)ARR_WORDS etc */ - - if (!RoomToPack(PACK_GA_SIZE + _HS + vhs + nonptrs, ptrs)) { - IF_PAR_DEBUG(pack, - belch("*>&& pack buffer is full; packing FETCH_ME for closure %p (%s)", - closure, info_type(closure))); - PackFetchMe(closure); - return; - } - - /* Record the location of the GA */ - AmPacking(closure); - /* Allocate a GA for this closure and put it into the buffer */ - /* Checks for globalisation scheme; default: globalise everything thunks */ - if ( RtsFlags.ParFlags.globalising == 0 || - (closure_THUNK(closure) && !closure_UNPOINTED(closure)) ) - GlobaliseAndPackGA(closure); - else - Pack((StgWord)2); // marker for unglobalised closure - - - ASSERT(!(info->type == ARR_WORDS || info->type == MUT_ARR_PTRS || - info->type == MUT_ARR_PTRS_FROZEN || info->type == MUT_VAR)); - - /* At last! A closure we can actually pack! */ - if (ip_MUTABLE(info) && ((info->type != FETCH_ME)||(info->type != REMOTE_REF))) - barf("*>// %p (%s) PackClosure: trying to replicate a Mutable closure!", - closure, info_type(closure)); - - /* - Remember, the generic closure layout is as follows: - +-------------------------------------------------+ - | FIXED HEADER | VARIABLE HEADER | PTRS | NON-PRS | - +-------------------------------------------------+ - */ - /* pack fixed and variable header */ - for (i = 0; i < _HS + vhs; ++i) - Pack((StgWord)*(((StgPtr)closure)+i)); - - /* register all ptrs for further packing */ - for (i = 0; i < ptrs; ++i) - QueueClosure(((StgClosure *) *(((StgPtr)closure)+(_HS+vhs)+i))); - - /* pack non-ptrs */ - for (i = 0; i < nonptrs; ++i) - Pack((StgWord)*(((StgPtr)closure)+(_HS+vhs)+ptrs+i)); - - // ASSERT(_HS+vhs+ptrs+nonptrs==size); - if ((m=_HS+vhs+ptrs+nonptrs)<size) { - IF_PAR_DEBUG(pack, - belch("*>** WARNING: slop in closure %p (%s); filling %d words; SHOULD NEVER HAPPEN", - closure, info_type(closure), size-m)); - for (i=m; i<size; i++) - Pack((StgWord)*(((StgPtr)closure)+i)); - } - - unpacked_size += size; - //unpacked_size += (size < MIN_UPD_SIZE) ? MIN_UPD_SIZE : size; - - /* - * Record that this is a revertable black hole so that we can fill in - * its address from the fetch reply. Problem: unshared thunks may cause - * space leaks this way, their GAs should be deallocated following an - * ACK. - */ - - if (closure_THUNK(closure) && !closure_UNPOINTED(closure)) { - rbh = convertToRBH(closure); - ASSERT(size>=_HS+MIN_UPD_SIZE); // min size for any updatable closure - ASSERT(rbh == closure); // rbh at the same position (minced version) - packed_thunks++; - } else if ( closure==graph_root ) { - packed_thunks++; // root of graph is counted as a thunk - } -} -/* - Pack an array of words. - ToDo: implement packing of MUT_ARRAYs -*/ - -//@cindex PackArray -static void -PackArray(StgClosure *closure) -{ - StgInfoTable *info; - nat size, ptrs, nonptrs, vhs; - nat i, n; - char str[80]; - - /* get info about basic layout of the closure */ - info = get_closure_info(closure, &size, &ptrs, &nonptrs, &vhs, str); - - ASSERT(info->type == ARR_WORDS || info->type == MUT_ARR_PTRS || - info->type == MUT_ARR_PTRS_FROZEN || info->type == MUT_VAR); - - n = arr_words_words(((StgArrWords *)closure)); - // this includes the header!: arr_words_sizeW(stgCast(StgArrWords*,q)); - - IF_PAR_DEBUG(pack, - belch("*>== %p (%s): packing an array of %d words (size=%d)\n", - closure, info_type(closure), n, - arr_words_sizeW((StgArrWords *)closure))); - - /* check that we have enough room in the pack buffer */ - if (!RoomToPack(PACK_GA_SIZE + _HS + vhs + nonptrs, ptrs)) { - IF_PAR_DEBUG(pack, - belch("*>&& pack buffer is full; packing FETCH_ME for closure %p (%s)", - closure, info_type(closure))); - PackFetchMe(closure); - return; - } - - /* global stats about arrays sent */ - if (RtsFlags.ParFlags.ParStats.Global && - RtsFlags.GcFlags.giveStats > NO_GC_STATS) { - globalParStats.tot_arrs++; - globalParStats.tot_arr_size += arr_words_words(((StgArrWords *)closure)); - } - - /* record offset of the closure and allocate a GA */ - AmPacking(closure); - /* Checks for globalisation scheme; default: globalise everything thunks */ - if ( RtsFlags.ParFlags.globalising == 0 || - (closure_THUNK(closure) && !closure_UNPOINTED(closure)) ) - GlobaliseAndPackGA(closure); - else - Pack((StgWord)2); // marker for unglobalised closure - - /* Pack the header (2 words: info ptr and the number of words to follow) */ - Pack((StgWord)*(StgPtr)closure); - Pack(arr_words_words(((StgArrWords *)closure))); - - /* pack the payload of the closure (all non-ptrs) */ - for (i=0; i<n; i++) - Pack((StgWord)((StgArrWords *)closure)->payload[i]); - - unpacked_size += arr_words_sizeW((StgArrWords *)closure); -} - -/* - Pack a PAP closure. - Note that the representation of a PAP in the buffer is different from - its representation in the heap. In particular, pointers to local - closures are packed directly as FETCHME closures, using - PACK_FETCHME_SIZE words to represent q 1 word pointer in the orig graph - structure. To account for the difference in size we store the packed - size of the closure as part of the PAP's variable header in the buffer. -*/ - -//@cindex PackPAP -static void -PackPAP(StgPAP *pap) { - nat n, i, j, pack_start; - StgPtr p, q; - const StgInfoTable* info; - StgWord bitmap; - /* debugging only */ - StgPtr end; - nat size, ptrs, nonptrs, vhs; - char str[80]; - nat unpacked_size_before_PAP, FMs_in_PAP=0; // debugging only - - /* This is actually a setup invariant; checked here 'cause it affects PAPs*/ - //ASSERT(PACK_FETCHME_SIZE == sizeofW(StgFetchMe)-1+PACK_GA_SIZE); - ASSERT(NotYetPacking(OffsetFor((StgClosure *)pap))); - IF_DEBUG(sanity, - unpacked_size_before_PAP = unpacked_size); - - n = (nat)(pap->n_args); - - /* get info about basic layout of the closure */ - info = get_closure_info((StgClosure *)pap, &size, &ptrs, &nonptrs, &vhs, str); - ASSERT(ptrs==0 && nonptrs==0 && size==pap_sizeW(pap)); - - IF_PAR_DEBUG(pack, - belch("*>** %p (%s): PackPAP: packing PAP with %d words (size=%d; ptrs=%d; nonptrs=%d:", - (StgClosure *)pap, info_type((StgClosure *)pap), - n, size, ptrs, nonptrs); - printClosure((StgClosure *)pap)); - - /* check that we have enough room in the pack buffer */ - if (!RoomToPack(PACK_GA_SIZE + _HS + vhs + nonptrs, ptrs)) { - IF_PAR_DEBUG(pack, - belch("*>&& pack buffer is full; packing FETCH_ME for closure %p (%s)", - (StgClosure *)pap, info_type((StgClosure *)pap))); - PackFetchMe((StgClosure *)pap); - return; - } - - /* record offset of the closure and allocate a GA */ - AmPacking((StgClosure *)pap); - /* Checks for globalisation scheme; default: globalise everything thunks */ - if ( RtsFlags.ParFlags.globalising == 0 || - (closure_THUNK(pap) && !closure_UNPOINTED(pap)) ) - GlobaliseAndPackGA((StgClosure *)pap); - else - Pack((StgWord)2); // marker for unglobalised closure - - /* Pack the PAP header */ - Pack((StgWord)(pap->header.info)); - Pack((StgWord)(pap->n_args)); - Pack((StgWord)(pap->fun)); - pack_start = pack_locn; // to compute size of PAP in buffer - Pack((StgWord)0); // this will be filled in later (size of PAP in buffer) - - /* Pack the payload of a PAP i.e. a stack chunk */ - /* pointers to start of stack chunk */ - p = (StgPtr)(pap->payload); - end = (StgPtr)((nat)pap+pap_sizeW(pap)*sizeof(StgWord)); // (StgPtr)((nat)pap+sizeof(StgPAP)+sizeof(StgPtr)*n); - while (p<end) { - /* the loop body has been borrowed from scavenge_stack */ - q = (StgPtr)*p; - - /* If we've got a tag, pack all words in that block */ - if (IS_ARG_TAG((W_)q)) { // q stands for the no. of non-ptrs to follow - nat m = ARG_TAG((W_)q); // first word after this block - IF_PAR_DEBUG(pack, - belch("*>** PackPAP @ %p: packing %d words (tagged), starting @ %p", - p, m, p)); - for (i=0; i<m+1; i++) - Pack((StgWord)*(p+i)); - p += m+1; // m words + the tag - continue; - } - - /* If q is is a pointer to a (heap allocated) closure we pack a FETCH_ME - ToDo: provide RTS flag to also pack these closures - */ - if (! LOOKS_LIKE_GHC_INFO(q) ) { - /* distinguish static closure (PLC) from other closures (FM) */ - switch (get_itbl((StgClosure*)q)->type) { - case CONSTR_CHARLIKE: - IF_PAR_DEBUG(pack, - belch("*>** PackPAP: packing a charlike closure %d", - ((StgIntCharlikeClosure*)q)->data)); - - PackPLC((StgPtr)CHARLIKE_CLOSURE(((StgIntCharlikeClosure*)q)->data)); - p++; - break; - - case CONSTR_INTLIKE: - { - StgInt val = ((StgIntCharlikeClosure*)q)->data; - - if ((val <= MAX_INTLIKE) && (val >= MIN_INTLIKE)) { - IF_PAR_DEBUG(pack, - belch("*>** PackPAP: Packing ptr to a small intlike %d as a PLC", val)); - PackPLC((StgPtr)INTLIKE_CLOSURE(val)); - p++; - break; - } else { - IF_PAR_DEBUG(pack, - belch("*>** PackPAP: Packing a ptr to a big intlike %d as a FM", - val)); - Pack((StgWord)(ARGTAG_MAX+1)); - PackFetchMe((StgClosure *)q); - p++; - IF_DEBUG(sanity, FMs_in_PAP++); - break; - } - } - case THUNK_STATIC: // ToDo: check whether that's ok - case FUN_STATIC: // ToDo: check whether that's ok - case CONSTR_STATIC: - case CONSTR_NOCAF_STATIC: - { - IF_PAR_DEBUG(pack, - belch("*>** PackPAP: packing a ptr to a %p (%s) as a PLC", - q, info_type((StgClosure *)q))); - - PackPLC((StgPtr)q); - p++; - break; - } - default: - IF_PAR_DEBUG(pack, - belch("*>** PackPAP @ %p: packing FM to %p (%s)", - p, q, info_type((StgClosure*)q))); - Pack((StgWord)(ARGTAG_MAX+1)); - PackFetchMe((StgClosure *)q); - p++; - IF_DEBUG(sanity, FMs_in_PAP++); - break; - } - continue; - } - - /* - * Otherwise, q must be the info pointer of an activation - * record. All activation records have 'bitmap' style layout - * info. - */ - info = get_itbl((StgClosure *)p); - switch (info->type) { - - /* Dynamic bitmap: the mask is stored on the stack */ - case RET_DYN: - IF_PAR_DEBUG(pack, - belch("*>** PackPAP @ %p: RET_DYN", - p)); - - /* Pack the header as is */ - Pack((StgWord)(((StgRetDyn *)p)->info)); - Pack((StgWord)(((StgRetDyn *)p)->liveness)); - Pack((StgWord)(((StgRetDyn *)p)->ret_addr)); - - bitmap = ((StgRetDyn *)p)->liveness; - p = (P_)&((StgRetDyn *)p)->payload[0]; - goto small_bitmap; - - /* probably a slow-entry point return address: */ - case FUN: - case FUN_STATIC: - { - IF_PAR_DEBUG(pack, - belch("*>** PackPAP @ %p: FUN or FUN_STATIC", - p)); - - Pack((StgWord)(((StgClosure *)p)->header.info)); - p++; - - goto follow_srt; //?? - } - - /* Using generic code here; could inline as in scavenge_stack */ - case UPDATE_FRAME: - { - StgUpdateFrame *frame = (StgUpdateFrame *)p; - nat type = get_itbl(frame->updatee)->type; - - ASSERT(type==BLACKHOLE || type==CAF_BLACKHOLE || type==BLACKHOLE_BQ); - - IF_PAR_DEBUG(pack, - belch("*>** PackPAP @ %p: UPDATE_FRAME (updatee=%p; link=%p)", - p, frame->updatee, frame->link)); - - Pack((StgWord)(frame->header.info)); - Pack((StgWord)(frame->link)); // ToDo: fix intra-stack pointer - Pack((StgWord)(frame->updatee)); // ToDo: follow link - - p += 3; - } - - /* small bitmap (< 32 entries, or 64 on a 64-bit machine) */ - case STOP_FRAME: - { - IF_PAR_DEBUG(pack, - belch("*>** PackPAP @ %p: STOP_FRAME", - p)); - Pack((StgWord)((StgStopFrame *)p)->header.info); - p++; - } - - case CATCH_FRAME: - { - IF_PAR_DEBUG(pack, - belch("*>** PackPAP @ %p: CATCH_FRAME (handler=%p)", - p, ((StgCatchFrame *)p)->handler)); - - Pack((StgWord)((StgCatchFrame *)p)->header.info); - Pack((StgWord)((StgCatchFrame *)p)->link); // ToDo: fix intra-stack pointer - Pack((StgWord)((StgCatchFrame *)p)->exceptions_blocked); - Pack((StgWord)((StgCatchFrame *)p)->handler); - p += 4; - } - - case SEQ_FRAME: - { - IF_PAR_DEBUG(pack, - belch("*>** PackPAP @ %p: UPDATE_FRAME (link=%p)", - p, ((StgSeqFrame *)p)->link)); - - Pack((StgWord)((StgSeqFrame *)p)->header.info); - Pack((StgWord)((StgSeqFrame *)p)->link); // ToDo: fix intra-stack pointer - - // ToDo: handle bitmap - bitmap = info->layout.bitmap; - - p = (StgPtr)&(((StgClosure *)p)->payload); - goto small_bitmap; - } - case RET_BCO: - case RET_SMALL: - case RET_VEC_SMALL: - IF_PAR_DEBUG(pack, - belch("*>** PackPAP @ %p: RET_{BCO,SMALL,VEC_SMALL} (bitmap=%o)", - p, info->layout.bitmap)); - - - Pack((StgWord)((StgClosure *)p)->header.info); - p++; - // ToDo: handle bitmap - bitmap = info->layout.bitmap; - /* this assumes that the payload starts immediately after the info-ptr */ - - small_bitmap: - while (bitmap != 0) { - if ((bitmap & 1) == 0) { - Pack((StgWord)(ARGTAG_MAX+1)); - PackFetchMe((StgClosure *)*p++); // pack a FetchMe to the closure - IF_DEBUG(sanity, FMs_in_PAP++); - } else { - Pack((StgWord)*p++); - } - bitmap = bitmap >> 1; - } - - follow_srt: - IF_PAR_DEBUG(pack, - belch("*>-- PackPAP: nothing to do for follow_srt")); - continue; - - /* large bitmap (> 32 entries) */ - case RET_BIG: - case RET_VEC_BIG: - { - StgPtr q; - StgLargeBitmap *large_bitmap; - - IF_PAR_DEBUG(pack, - belch("*>** PackPAP @ %p: RET_{BIG,VEC_BIG} (large_bitmap=%p)", - p, info->layout.large_bitmap)); - - - Pack((StgWord)((StgClosure *)p)->header.info); - p++; - - large_bitmap = info->layout.large_bitmap; - - for (j=0; j<large_bitmap->size; j++) { - bitmap = large_bitmap->bitmap[j]; - q = p + BITS_IN(W_); - while (bitmap != 0) { - if ((bitmap & 1) == 0) { - Pack((StgWord)(ARGTAG_MAX+1)); - PackFetchMe((StgClosure *)*p++); // ToDo: pack pointer(StgClosure *)*p = evacuate((StgClosure *)*p); - IF_DEBUG(sanity, FMs_in_PAP++); - } else { - Pack((StgWord)*p++); - } - bitmap = bitmap >> 1; - } - if (j+1 < large_bitmap->size) { - while (p < q) { - Pack((StgWord)(ARGTAG_MAX+1)); - PackFetchMe((StgClosure *)*p++); // ToDo: pack pointer (StgClosure *)*p = evacuate((StgClosure *)*p); - IF_DEBUG(sanity, FMs_in_PAP++); - } - } - } - - /* and don't forget to follow the SRT */ - goto follow_srt; - } - - default: - barf("PackPAP: weird activation record found on stack (@ %p): %d", - p, (int)(info->type)); - } - } - // fill in size of the PAP (only the payload!) in buffer - globalPackBuffer->buffer[pack_start] = (StgWord)(pack_locn - pack_start - 1*sizeofW(StgWord)); - /* - We can use the generic pap_sizeW macro to compute the size of the - unpacked PAP because whenever we pack a new FETCHME as part of the - PAP's payload we also adjust unpacked_size accordingly (smart, aren't we?) - - NB: the current PAP (un-)packing code relies on the fact that - the size of the unpacked PAP + size of all unpacked FMs is the same as - the size of the packed PAP!! - */ - unpacked_size += pap_sizeW(pap); // sizeofW(pap) + (nat)(globalPackBuffer->buffer[pack_start]); - IF_DEBUG(sanity, - ASSERT(unpacked_size-unpacked_size_before_PAP==pap_sizeW(pap)+FMs_in_PAP*sizeofW(StgFetchMe))); -} -# else /* GRAN */ - -/* Fake the packing of a closure */ - -void -PackClosure(closure) -StgClosure *closure; -{ - StgInfoTable *info, *childInfo; - nat size, ptrs, nonptrs, vhs; - char info_hdr_ty[80]; - nat i; - StgClosure *indirectee, *rbh; - char str[80]; - rtsBool is_mutable, will_be_rbh, no_more_thunks_please; - - is_mutable = rtsFalse; - - /* In GranSim we don't pack and unpack closures -- we just simulate - packing by updating the bitmask. So, the graph structure is unchanged - i.e. we don't short out indirections here. -- HWL */ - - /* Nothing to do with packing but good place to (sanity) check closure; - if the closure is a thunk, it must be unique; otherwise we have copied - work at some point before that which violates one of our main global - assertions in GranSim/GUM */ - ASSERT(!closure_THUNK(closure) || is_unique(closure)); - - IF_GRAN_DEBUG(pack, - belch("** Packing closure %p (%s)", - closure, info_type(closure))); - - if (where_is(closure) != where_is(graph_root)) { - IF_GRAN_DEBUG(pack, - belch("** faking a FETCHME [current PE: %d, closure's PE: %d]", - where_is(graph_root), where_is(closure))); - - /* GUM would pack a FETCHME here; simulate that by increasing the */ - /* unpacked size accordingly but don't pack anything -- HWL */ - unpacked_size += _HS + 2 ; // sizeofW(StgFetchMe); - return; - } - - /* If the closure's not already being packed */ - if (!NotYetPacking(closure)) - /* Don't have to do anything in GrAnSim if closure is already */ - /* packed -- HWL */ - { - IF_GRAN_DEBUG(pack, - belch("** Closure %p is already packed and omitted now!", - closure)); - return; - } - - switch (get_itbl(closure)->type) { - /* ToDo: check for sticky bit here? */ - /* BH-like closures which must not be moved to another PE */ - case CAF_BLACKHOLE: /* # of ptrs, nptrs: 0,2 */ - case SE_BLACKHOLE: /* # of ptrs, nptrs: 0,2 */ - case SE_CAF_BLACKHOLE: /* # of ptrs, nptrs: 0,2 */ - case BLACKHOLE: /* # of ptrs, nptrs: 0,2 */ - case BLACKHOLE_BQ: /* # of ptrs, nptrs: 1,1 */ - case RBH: /* # of ptrs, nptrs: 1,1 */ - /* same for these parallel specific closures */ - case BLOCKED_FETCH: - case FETCH_ME: - case FETCH_ME_BQ: - IF_GRAN_DEBUG(pack, - belch("** Avoid packing BH-like closures (%p, %s)!", - closure, info_type(closure))); - /* Just ignore RBHs i.e. they stay where they are */ - return; - - case THUNK_SELECTOR: - { - StgClosure *selectee = ((StgSelector *)closure)->selectee; - - IF_GRAN_DEBUG(pack, - belch("** Avoid packing THUNK_SELECTOR (%p, %s) but queuing %p (%s)!", - closure, info_type(closure), selectee, info_type(selectee))); - QueueClosure(selectee); - IF_GRAN_DEBUG(pack, - belch("** [%p (%s) (Queueing closure) ....]", - selectee, info_type(selectee))); - } - return; - - case CONSTR_STATIC: - case CONSTR_NOCAF_STATIC: - /* For now we ship indirections to CAFs: - * They are evaluated on each PE if needed */ - IF_GRAN_DEBUG(pack, - belch("** Nothing to pack for %p (%s)!", - closure, info_type(closure))); - // Pack(closure); GUM only - return; - - case CONSTR_CHARLIKE: - case CONSTR_INTLIKE: - IF_GRAN_DEBUG(pack, - belch("** Nothing to pack for %s (%p)!", - closure, info_type(closure))); - // PackPLC(((StgIntCharlikeClosure *)closure)->data); GUM only - return; - - case AP_UPD: - case PAP: - /* partial applications; special treatment necessary? */ - break; - - case MVAR: - barf("{PackClosure}Daq Qagh: found an MVAR (%p, %s); ToDo: implement proper treatment of MVARs", - closure, info_type(closure)); - - case ARR_WORDS: - case MUT_VAR: - case MUT_ARR_PTRS: - case MUT_ARR_PTRS_FROZEN: - /* Mutable objects; require special treatment to ship all data */ - is_mutable = rtsTrue; - break; - - case WEAK: - case FOREIGN: - case STABLE_NAME: - /* weak pointers and other FFI objects */ - barf("{PackClosure}Daq Qagh: found an FFI object (%p, %s); FFI not yet supported by GranSim, sorry", - closure, info_type(closure)); - - case TSO: - /* parallel objects */ - barf("{PackClosure}Daq Qagh: found a TSO when packing (%p, %s); thread migration not yet implemented, sorry", - closure, info_type(closure)); - - case BCO: - /* Hugs objects (i.e. closures used by the interpreter) */ - barf("{PackClosure}Daq Qagh: found a Hugs closure when packing (%p, %s); GranSim not yet integrated with Hugs, sorry", - closure, info_type(closure)); - - case IND: /* # of ptrs, nptrs: 1,0 */ - case IND_STATIC: /* # of ptrs, nptrs: 1,0 */ - case IND_PERM: /* # of ptrs, nptrs: 1,1 */ - case IND_OLDGEN: /* # of ptrs, nptrs: 1,1 */ - case IND_OLDGEN_PERM: /* # of ptrs, nptrs: 1,1 */ - /* we shouldn't find an indirection here, because we have shorted them - out at the beginning of this functions already. - */ - break; - /* should be: - barf("{PackClosure}Daq Qagh: found indirection when packing (%p, %s)", - closure, info_type(closure)); - */ - - case UPDATE_FRAME: - case CATCH_FRAME: - case SEQ_FRAME: - case STOP_FRAME: - /* stack frames; should never be found when packing for now; - once we support thread migration these have to be covered properly - */ - barf("{PackClosure}Daq Qagh: found stack frame when packing (%p, %s)", - closure, info_type(closure)); - - case RET_BCO: - case RET_SMALL: - case RET_VEC_SMALL: - case RET_BIG: - case RET_VEC_BIG: - case RET_DYN: - /* vectored returns; should never be found when packing; */ - barf("{PackClosure}Daq Qagh: found vectored return (%p, %s)", - closure, info_type(closure)); - - case INVALID_OBJECT: - barf("{PackClosure}Daq Qagh: found Invalid object (%p, %s)", - closure, info_type(closure)); - - default: - /* - Here we know that the closure is a CONSTR, FUN or THUNK (maybe - a specialised version with wired in #ptr/#nptr info; currently - we treat these specialised versions like the generic version) - */ - } /* switch */ - - /* Otherwise it's not Fixed */ - - info = get_closure_info(closure, &size, &ptrs, &nonptrs, &vhs, str); - will_be_rbh = closure_THUNK(closure) && !closure_UNPOINTED(closure); - - IF_GRAN_DEBUG(pack, - belch("** Info on closure %p (%s): size=%d; ptrs=%d", - closure, info_type(closure), - size, ptrs, - (will_be_rbh) ? "will become RBH" : "will NOT become RBH")); - - // check whether IS_UPDATABLE(closure) == !closure_UNPOINTED(closure) -- HWL - no_more_thunks_please = - (RtsFlags.GranFlags.ThunksToPack>0) && - (packed_thunks>=RtsFlags.GranFlags.ThunksToPack); - - /* - should be covered by get_closure_info - if (info->type == FETCH_ME || info->type == FETCH_ME_BQ || - info->type == BLACKHOLE || info->type == RBH ) - size = ptrs = nonptrs = vhs = 0; - */ - /* Now peek ahead to see whether the closure has any primitive */ - /* array children */ - /* - ToDo: fix this code - for (i = 0; i < ptrs; ++i) { - P_ childInfo; - W_ childSize, childPtrs, childNonPtrs, childVhs; - - childInfo = get_closure_info(((StgPtrPtr) (closure))[i + _HS + vhs], - &childSize, &childPtrs, &childNonPtrs, - &childVhs, junk_str); - if (IS_BIG_MOTHER(childInfo)) { - reservedPAsize += PACK_GA_SIZE + _HS + - childVhs + childNonPtrs + - childPtrs * PACK_FETCHME_SIZE; - PAsize += PACK_GA_SIZE + _HS + childSize; - PAptrs += childPtrs; - } - } - */ - /* Don't pack anything (GrAnSim) if it's a black hole, or the buffer - * is full and it isn't a primitive array. N.B. Primitive arrays are - * always packed (because their parents index into them directly) */ - - if (IS_BLACK_HOLE(closure)) - /* - ToDo: fix this code - || - !(RoomToPack(PACK_GA_SIZE + _HS + vhs + nonptrs, ptrs) - || IS_BIG_MOTHER(info))) - */ - return; - - /* At last! A closure we can actually pack! */ - - if (closure_MUTABLE(closure)) // not nec. && (info->type != FETCHME)) - belch("ghuH: Replicated a Mutable closure!"); - - if (RtsFlags.GranFlags.GranSimStats.Global && - no_more_thunks_please && will_be_rbh) { - globalGranStats.tot_cuts++; - if ( RtsFlags.GranFlags.Debug.pack ) - belch("** PackClosure (w/ ThunksToPack=%d): Cutting tree with root at %#x\n", - RtsFlags.GranFlags.ThunksToPack, closure); - } else if (will_be_rbh || (closure==graph_root) ) { - packed_thunks++; - globalGranStats.tot_thunks++; - } - - if (no_more_thunks_please && will_be_rbh) - return; /* don't pack anything */ - - /* actual PACKING done here -- HWL */ - Pack(closure); - for (i = 0; i < ptrs; ++i) { - /* extract i-th pointer from closure */ - QueueClosure((StgClosure *)(closure->payload[i])); - IF_GRAN_DEBUG(pack, - belch("** [%p (%s) (Queueing closure) ....]", - closure->payload[i], - info_type(*stgCast(StgPtr*,((closure)->payload+(i)))))); - //^^^^^^^^^^^ payloadPtr(closure,i)))); - } - - /* - for packing words (GUM only) do something like this: - - for (i = 0; i < ptrs; ++i) { - Pack(payloadWord(obj,i+j)); - } - */ - /* Turn thunk into a revertible black hole. */ - if (will_be_rbh) { - rbh = convertToRBH(closure); - ASSERT(rbh != NULL); - } -} -# endif /* PAR */ - -//@node Low level packing routines, Unpacking routines, Packing Functions, Graph packing -//@subsection Low level packing routines - -/* - @Pack@ is the basic packing routine. It just writes a word of data into - the pack buffer and increments the pack location. */ - -//@cindex Pack - -# if defined(PAR) -static void -Pack(data) -StgWord data; -{ - ASSERT(pack_locn < RtsFlags.ParFlags.packBufferSize); - globalPackBuffer->buffer[pack_locn++] = data; -} -#endif - -#if defined(GRAN) -static void -Pack(closure) -StgClosure *closure; -{ - StgInfoTable *info; - nat size, ptrs, nonptrs, vhs; - char str[80]; - - /* This checks the size of the GrAnSim internal pack buffer. The simulated - pack buffer is checked via RoomToPack (as in GUM) */ - if (pack_locn >= (int)globalPackBuffer->size+sizeofW(rtsPackBuffer)) - reallocPackBuffer(); - - if (closure==(StgClosure*)NULL) - belch("Qagh {Pack}Daq: Trying to pack 0"); - globalPackBuffer->buffer[pack_locn++] = closure; - /* ASSERT: Data is a closure in GrAnSim here */ - info = get_closure_info(closure, &size, &ptrs, &nonptrs, &vhs, str); - // ToDo: is check for MIN_UPD_SIZE really needed? */ - unpacked_size += _HS + (size < MIN_UPD_SIZE ? - MIN_UPD_SIZE : - size); -} -# endif /* GRAN */ - -/* - If a closure is local, make it global. Then, divide its weight for - export. The GA is then packed into the pack buffer. */ - -# if defined(PAR) -//@cindex GlobaliseAndPackGA -static void -GlobaliseAndPackGA(closure) -StgClosure *closure; -{ - globalAddr *ga; - globalAddr packGA; - - if ((ga = LAGAlookup(closure)) == NULL) { - ga = makeGlobal(closure, rtsTrue); - - // Global statistics: increase amount of global data by closure-size - if (RtsFlags.ParFlags.ParStats.Global && - RtsFlags.GcFlags.giveStats > NO_GC_STATS) { - StgInfoTable *info; - nat size, ptrs, nonptrs, vhs, i, m; // stats only!! - char str[80]; // stats only!! - - info = get_closure_info(closure, &size, &ptrs, &nonptrs, &vhs, str); - globalParStats.tot_global += size; - } - } - ASSERT(ga->weight==MAX_GA_WEIGHT || ga->weight > 2); - - if(dest_gtid==ga->payload.gc.gtid) - { packGA.payload = ga->payload; - packGA.weight = 0xFFFFFFFF; // 0,1,2 are used already - } - else - { splitWeight(&packGA, ga); - ASSERT(packGA.weight > 0); - } - - IF_PAR_DEBUG(pack, - fprintf(stderr, "*>## %p (%s): Globalising (%s) closure with GA ", - closure, info_type(closure), - ( (ga->payload.gc.gtid==dest_gtid)?"returning": - ( (ga->payload.gc.gtid==mytid)?"creating":"sharing" ) )); - printGA(&packGA); - fputc('\n', stderr)); - - - Pack((StgWord) packGA.weight); - Pack((StgWord) packGA.payload.gc.gtid); - Pack((StgWord) packGA.payload.gc.slot); -} - -/* - @PackPLC@ makes up a bogus GA for a PLC. Weight 0 implies that a PLC - address follows instead of PE, slot. */ - -//@cindex PackPLC - -static void -PackPLC(addr) -StgPtr addr; -{ - Pack(0L); /* weight */ - Pack((StgWord) addr); /* address */ -} - -/* - @PackOffset@ packs a special GA value that will be interpreted as an - offset to a closure in the pack buffer. This is used to avoid unfolding - the graph structure into a tree. */ - -static void -PackOffset(offset) -int offset; -{ - /* - IF_PAR_DEBUG(pack, - belch("** Packing Offset %d at pack location %u", - offset, pack_locn)); - */ - Pack(1L); /* weight */ - Pack(0L); /* pe */ - Pack(offset); /* slot/offset */ -} -# endif /* PAR */ - -//@node Unpacking routines, Aux fcts for packing, Low level packing routines, Graph packing -//@subsection Unpacking routines - -/* - This was formerly in the (now deceased) module Unpack.c - - Unpacking closures which have been exported to remote processors - - This module defines routines for unpacking closures in the parallel - runtime system (GUM). - - In the case of GrAnSim, this module defines routines for *simulating* the - unpacking of closures as it is done in the parallel runtime system. -*/ - -//@node GUM code, GranSim Code, Unpacking routines, Unpacking routines -//@subsubsection GUM code - -#if defined(PAR) - -//@cindex InitPendingGABuffer -void -InitPendingGABuffer(size) -nat size; -{ - if (PendingGABuffer==(globalAddr *)NULL) - PendingGABuffer = (globalAddr *) - stgMallocBytes(size*2*sizeof(globalAddr), - "InitPendingGABuffer"); - - /* current location in the buffer */ - gaga = PendingGABuffer; -} - -/* - @CommonUp@ commons up two closures which we have discovered to be - variants of the same object. One is made an indirection to the other. */ - -//@cindex CommonUp -void -CommonUp(StgClosure *src, StgClosure *dst) -{ - StgBlockingQueueElement *bqe; -#if defined(DEBUG) - StgInfoTable *info; - nat size, ptrs, nonptrs, vhs, i; - char str[80]; - - /* get info about basic layout of the closure */ - info = get_closure_info(src, &size, &ptrs, &nonptrs, &vhs, str); -#endif - - ASSERT(src != (StgClosure *)NULL && dst != (StgClosure *)NULL); - ASSERT(src != dst); - - IF_PAR_DEBUG(pack, - belch("*___ CommonUp %p (%s) --> %p (%s)", - src, info_type(src), dst, info_type(dst))); - - switch (get_itbl(src)->type) { - case BLACKHOLE_BQ: - bqe = ((StgBlockingQueue *)src)->blocking_queue; - break; - - case FETCH_ME_BQ: - bqe = ((StgFetchMeBlockingQueue *)src)->blocking_queue; - break; - - case RBH: - bqe = ((StgRBH *)src)->blocking_queue; - break; - - case BLACKHOLE: - case FETCH_ME: - bqe = END_BQ_QUEUE; - break; - - /* These closures are too small to be updated with an indirection!!! */ - case CONSTR_1_0: - case CONSTR_0_1: - ASSERT(size<_HS+MIN_UPD_SIZE); // that's why we have to avoid UPD_IND - return; - - /* currently we also common up 2 CONSTRs; this should reduce heap - * consumption but also does more work; not sure whether it's worth doing - */ - case CONSTR: - case CONSTR_2_0: - case CONSTR_1_1: - case CONSTR_0_2: - case ARR_WORDS: - case MUT_ARR_PTRS: - case MUT_ARR_PTRS_FROZEN: - case MUT_VAR: - break; - - default: - /* Don't common up anything else */ - return; - } - - /* closure must be big enough to permit update with ind */ - ASSERT(size>=_HS+MIN_UPD_SIZE); - /* NB: this also awakens the blocking queue for src */ - UPD_IND(src, dst); -} - -/* - * Common up the new closure with any existing closure having the same - * GA - */ -//@cindex SetGAandCommonUp -static StgClosure * -SetGAandCommonUp(globalAddr *ga, StgClosure *closure, rtsBool hasGA) -{ - StgClosure *existing; - StgInfoTable *ip, *oldip; - globalAddr *newGA; - - if (!hasGA) - return closure; - - /* should we already have a local copy? */ - if (ga->weight==0xFFFFFFFF) { - ASSERT(ga->payload.gc.gtid==mytid); //sanity - ga->weight=0; - /* probably should also ASSERT that a commonUp takes place...*/ - } - - ip = get_itbl(closure); - if ((existing = GALAlookup(ga)) == NULL) { - /* Just keep the new object */ - IF_PAR_DEBUG(pack, - belch("*<## New local object for GA ((%x, %d, %x)) is %p (%s)", - ga->payload.gc.gtid, ga->payload.gc.slot, ga->weight, - closure, info_type(closure))); - - // make an entry binding closure to ga in the RemoteGA table - newGA = setRemoteGA(closure, ga, rtsTrue); - // if local closure is a FETCH_ME etc fill in the global indirection - if (ip->type == FETCH_ME || ip->type == REMOTE_REF) - ((StgFetchMe *)closure)->ga = newGA; - } else { - - -#ifdef DIST -// *************************************************************************** -// *************************************************************************** -// REMOTE_REF HACK - dual is in PackRemoteRef -// - prevents the weight ever being updated - if (ip->type == REMOTE_REF) - ga->weight=0; -// *************************************************************************** -// *************************************************************************** -#endif /* DIST */ - - /* Two closures, one global name. Someone loses */ - oldip = get_itbl(existing); - if ((oldip->type == FETCH_ME || - IS_BLACK_HOLE(existing) || - /* try to share evaluated closures */ - oldip->type == CONSTR || - oldip->type == CONSTR_1_0 || - oldip->type == CONSTR_0_1 || - oldip->type == CONSTR_2_0 || - oldip->type == CONSTR_1_1 || - oldip->type == CONSTR_0_2 - ) && - ip->type != FETCH_ME) - { - IF_PAR_DEBUG(pack, - belch("*<#- Duplicate local object for GA ((%x, %d, %x)); redirecting %p (%s) -> %p (%s)", - ga->payload.gc.gtid, ga->payload.gc.slot, ga->weight, - existing, info_type(existing), closure, info_type(closure))); - - /* - * What we had wasn't worth keeping, so make the old closure an - * indirection to the new closure (copying BQs if necessary) and - * make sure that the old entry is not the preferred one for this - * closure. - */ - CommonUp(existing, closure); - //GALAdeprecate(ga); -#if defined(DEBUG) - { - StgInfoTable *info; - nat size, ptrs, nonptrs, vhs, i; - char str[80]; - - /* get info about basic layout of the closure */ - info = get_closure_info(GALAlookup(ga), &size, &ptrs, &nonptrs, &vhs, str); - - /* now ga indirectly refers to the new closure */ - ASSERT(size<_HS+MIN_UPD_SIZE || - UNWIND_IND(GALAlookup(ga))==closure); - } -#endif - } else { - /* - * Either we already had something worthwhile by this name or - * the new thing is just another FetchMe. However, the thing we - * just unpacked has to be left as-is, or the child unpacking - * code will fail. Remember that the way pointer words are - * filled in depends on the info pointers of the parents being - * the same as when they were packed. - */ - IF_PAR_DEBUG(pack, - belch("*<#@ Duplicate local object for GA ((%x, %d, %x)); keeping %p (%s) nuking unpacked %p (%s)", - ga->payload.gc.gtid, ga->payload.gc.slot, ga->weight, - existing, info_type(existing), closure, info_type(closure))); - - /* overwrite 2nd word; indicates that the closure is garbage */ - IF_DEBUG(sanity, - ((StgFetchMe*)closure)->ga = (globalAddr*)GARBAGE_MARKER; - IF_PAR_DEBUG(pack, - belch("++++ unpacked closure %p (%s) is garbage: %p", - closure, info_type(closure), *(closure+1)))); - - closure = existing; -#if 0 - // HACK - ty = get_itbl(closure)->type; - if (ty == CONSTR || - ty == CONSTR_1_0 || - ty == CONSTR_0_1 || - ty == CONSTR_2_0 || - ty == CONSTR_1_1 || - ty == CONSTR_0_2) - CommonUp(closure, graph); -#endif - } - /* We don't use this GA after all, so give back the weight */ - (void) addWeight(ga); - } - - /* if we have unpacked a FETCH_ME, we have a GA, too */ - ASSERT(get_itbl(closure)->type!=FETCH_ME || - looks_like_ga(((StgFetchMe*)closure)->ga)); - - /* Sort out the global address mapping */ - if (ip_THUNK(ip)){ - // || // (ip_THUNK(ip) && !ip_UNPOINTED(ip)) || - //(ip_MUTABLE(ip) && ip->type != FETCH_ME)) { - /* Make up new GAs for single-copy closures */ - globalAddr *newGA = makeGlobal(closure, rtsTrue); - - // It's a new GA and therefore has the full weight - ASSERT(newGA->weight==0); - - /* Create an old GA to new GA mapping */ - *gaga++ = *ga; - splitWeight(gaga, newGA); - /* inlined splitWeight; we know that newGALA has full weight - newGA->weight = gaga->weight = 1L << (BITS_IN(unsigned) - 1); - gaga->payload = newGA->payload; - */ - ASSERT(gaga->weight == 1U << (BITS_IN(unsigned) - 1)); - gaga++; - } - return closure; -} - -/* - Copies a segment of the buffer, starting at @bufptr@, representing a closure - into the heap at @graph@. - */ -//@cindex FillInClosure -static nat -FillInClosure(StgWord ***bufptrP, StgClosure *graph) -{ - StgInfoTable *ip; - StgWord **bufptr = *bufptrP; - nat ptrs, nonptrs, vhs, i, size; - char str[80]; - - ASSERT(LOOKS_LIKE_GHC_INFO(((StgClosure*)bufptr)->header.info)); - - /* - * Close your eyes. You don't want to see where we're looking. You - * can't get closure info until you've unpacked the variable header, - * but you don't know how big it is until you've got closure info. - * So...we trust that the closure in the buffer is organized the - * same way as they will be in the heap...at least up through the - * end of the variable header. - */ - ip = get_closure_info((StgClosure *)bufptr, &size, &ptrs, &nonptrs, &vhs, str); - - /* Make sure that nothing sans the fixed header is filled in - The ga field of the FETCH_ME is filled in in SetGAandCommonUp */ - if (ip->type == FETCH_ME || ip->type == REMOTE_REF) { - ASSERT(size>=_HS+MIN_UPD_SIZE); // size of the FM in the heap - ptrs = nonptrs = vhs = 0; // i.e. only unpack FH from buffer - } - /* ToDo: check whether this is really needed */ - if (ip->type == ARR_WORDS) { - UnpackArray(bufptrP, graph); - return arr_words_sizeW((StgArrWords *)bufptr); - } - - if (ip->type == PAP || ip->type == AP_UPD) { - return UnpackPAP(bufptrP, graph); // includes size of unpackes FMs - } - - /* - Remember, the generic closure layout is as follows: - +-------------------------------------------------+ - | FIXED HEADER | VARIABLE HEADER | PTRS | NON-PRS | - +-------------------------------------------------+ - */ - /* Fill in the fixed header */ - for (i = 0; i < _HS; i++) - ((StgPtr)graph)[i] = (StgWord)*bufptr++; - - /* Fill in the packed variable header */ - for (i = 0; i < vhs; i++) - ((StgPtr)graph)[_HS + i] = (StgWord)*bufptr++; - - /* Pointers will be filled in later */ - - /* Fill in the packed non-pointers */ - for (i = 0; i < nonptrs; i++) - ((StgPtr)graph)[_HS + i + vhs + ptrs] = (StgWord)*bufptr++; - - /* Indirections are never packed */ - // ASSERT(INFO_PTR(graph) != (W_) Ind_info_TO_USE); - // return bufptr; - *bufptrP = bufptr; - ASSERT(((ip->type==FETCH_ME || ip->type==REMOTE_REF)&& sizeofW(StgFetchMe)==size) || - _HS+vhs+ptrs+nonptrs == size); - return size; -} - -/* - Find the next pointer field in the parent closure. - If the current parent has been completely unpacked already, get the - next closure from the global closure queue. -*/ -//@cindex LocateNextParent -static void -LocateNextParent(parentP, pptrP, pptrsP, sizeP) -StgClosure **parentP; -nat *pptrP, *pptrsP, *sizeP; -{ - StgInfoTable *ip; // debugging - nat nonptrs, pvhs; - char str[80]; - - /* pptr as an index into the current parent; find the next pointer field - in the parent by increasing pptr; if that takes us off the closure - (i.e. *pptr + 1 > *pptrs) grab a new parent from the closure queue - */ - (*pptrP)++; - while (*pptrP + 1 > *pptrsP) { - /* *parentP has been constructed (all pointer set); so check it now */ - IF_DEBUG(sanity, - if ((*parentP!=(StgClosure*)NULL) && // not root - (*((StgPtr)(*parentP)+1)!=GARBAGE_MARKER) && // not commoned up - (get_itbl(*parentP)->type != FETCH_ME)) - checkClosure(*parentP)); - - *parentP = DeQueueClosure(); - - if (*parentP == NULL) - break; - else { - ip = get_closure_info(*parentP, sizeP, pptrsP, &nonptrs, - &pvhs, str); - *pptrP = 0; - } - } - /* *parentP points to the new (or old) parent; */ - /* *pptr, *pptrs and *size have been updated referring to the new parent */ -} - -/* - UnpackClosure is the heart of the unpacking routine. It is called for - every closure found in the packBuffer. Any prefix such as GA, PLC marker - etc has been unpacked into the *ga structure. - UnpackClosure does the following: - - check for the kind of the closure (PLC, Offset, std closure) - - copy the contents of the closure from the buffer into the heap - - update LAGA tables (in particular if we end up with 2 closures - having the same GA, we make one an indirection to the other) - - set the GAGA map in order to send back an ACK message - - At the end of this function *graphP has been updated to point to the - next free word in the heap for unpacking the rest of the graph and - *bufptrP points to the next word in the pack buffer to be unpacked. -*/ - -static StgClosure* -UnpackClosure (StgWord ***bufptrP, StgClosure **graphP, globalAddr *ga) { - StgClosure *closure; - nat size; - rtsBool hasGA = rtsFalse, unglobalised = rtsFalse; - - /* Now unpack the closure body, if there is one; three cases: - - PLC: closure is just a pointer to a static closure - - Offset: closure has been unpacked already - - else: copy data from packet into closure - */ - if (isFixed(ga)) { - closure = UnpackPLC(ga); - } else if (isOffset(ga)) { - closure = UnpackOffset(ga); - } else { - /* if not PLC or Offset it must be a GA and then the closure */ - ASSERT(RtsFlags.ParFlags.globalising!=0 || LOOKS_LIKE_GA(ga)); - /* check whether this is an unglobalised closure */ - unglobalised = isUnglobalised(ga); - /* Now we have to build something. */ - hasGA = !isConstr(ga); - /* the new closure will be built here */ - closure = *graphP; - - /* fill in the closure from the buffer */ - size = FillInClosure(/*in/out*/bufptrP, /*in*/closure); - /* if it is unglobalised, it may not be a thunk!! */ - ASSERT(!unglobalised || !closure_THUNK(closure)); - - /* Add to queue for processing */ - QueueClosure(closure); - - /* common up with other graph if necessary */ - if (!unglobalised) - closure = SetGAandCommonUp(ga, closure, hasGA); - - /* if we unpacked a THUNK, check that it is large enough to update */ - ASSERT(!closure_THUNK(closure) || size>=_HS+MIN_UPD_SIZE); - /* graph shall point to next free word in the heap */ - *graphP += size; - //*graphP += (size < _HS+MIN_UPD_SIZE) ? _HS+MIN_UPD_SIZE : size; // see ASSERT - } - return closure; -} - -/* - @UnpackGraph@ unpacks the graph contained in a message buffer. It - returns a pointer to the new graph. The @gamap@ parameter is set to - point to an array of (oldGA,newGA) pairs which were created as a result - of unpacking the buffer; @nGAs@ is set to the number of GA pairs which - were created. - - The format of graph in the pack buffer is as defined in @Pack.lc@. */ - -//@cindex UnpackGraph -StgClosure * -UnpackGraph(packBuffer, gamap, nGAs) -rtsPackBuffer *packBuffer; -globalAddr **gamap; -nat *nGAs; -{ - StgWord **bufptr, **slotptr; - globalAddr gaS; - StgClosure *closure, *graphroot, *graph, *parent; - nat size, heapsize, bufsize, - pptr = 0, pptrs = 0, pvhs = 0; - nat unpacked_closures = 0, unpacked_thunks = 0; // stats only - - IF_PAR_DEBUG(resume, - graphFingerPrint[0] = '\0'); - - ASSERT(_HS==1); // HWL HACK; compile time constant - -#if defined(PAR_TICKY) // HWL HAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACK - PAR_TICKY_UNPACK_GRAPH_START(); -#endif - - /* Initialisation */ - InitPacking(rtsTrue); // same as in PackNearbyGraph - globalUnpackBuffer = packBuffer; - - IF_DEBUG(sanity, // do a sanity check on the incoming packet - checkPacket(packBuffer)); - - ASSERT(gaga==PendingGABuffer); - graphroot = (StgClosure *)NULL; - - /* Unpack the header */ - bufsize = packBuffer->size; - heapsize = packBuffer->unpacked_size; - bufptr = packBuffer->buffer; - - /* allocate heap */ - if (heapsize > 0) { - graph = (StgClosure *)allocate(heapsize); - ASSERT(graph != NULL); - // parallel global statistics: increase amount of global data - if (RtsFlags.ParFlags.ParStats.Global && - RtsFlags.GcFlags.giveStats > NO_GC_STATS) { - globalParStats.tot_global += heapsize; - } - } - - /* iterate over the buffer contents and unpack all closures */ - parent = (StgClosure *)NULL; - do { - /* check that we aren't at the end of the buffer, yet */ - IF_DEBUG(sanity, ASSERT(*bufptr != END_OF_BUFFER_MARKER)); - - /* This is where we will ultimately save the closure's address */ - slotptr = bufptr; - - /* fill in gaS from buffer; gaS may receive GA, PLC- or offset-marker */ - bufptr = UnpackGA(/*in*/bufptr, /*out*/&gaS); - - /* this allocates heap space, updates LAGA tables etc */ - closure = UnpackClosure (/*in/out*/&bufptr, /*in/out*/&graph, /*in*/&gaS); - unpacked_closures++; // stats only; doesn't count FMs in PAP!!! - unpacked_thunks += (closure_THUNK(closure)) ? 1 : 0; // stats only - - /* - * Set parent pointer to point to chosen closure. If we're at the top of - * the graph (our parent is NULL), then we want to arrange to return the - * chosen closure to our caller (possibly in place of the allocated graph - * root.) - */ - if (parent == NULL) - graphroot = closure; - else - ((StgPtr)parent)[_HS + pvhs + pptr] = (StgWord) closure; - - /* Save closure pointer for resolving offsets */ - *slotptr = (StgWord*) closure; - - /* Locate next parent pointer */ - LocateNextParent(&parent, &pptr, &pptrs, &size); - - IF_DEBUG(sanity, - gaS.weight = 0xdeadffff; - gaS.payload.gc.gtid = 0xdead; - gaS.payload.gc.slot = 0xdeadbeef;); - } while (parent != NULL); - - IF_PAR_DEBUG(resume, - GraphFingerPrint(graphroot, graphFingerPrint); - ASSERT(strlen(graphFingerPrint)<=MAX_FINGER_PRINT_LEN); - belch(">>> Fingerprint of graph rooted at %p (after unpacking <<%d>>:\n {%s}", - graphroot, packBuffer->id, graphFingerPrint)); - - /* we unpacked exactly as many words as there are in the buffer */ - ASSERT(bufsize == (nat) (bufptr-(packBuffer->buffer))); - /* we filled no more heap closure than we allocated at the beginning; - ideally this should be a ==; - NB: test is only valid if we unpacked anything at all (graphroot might - end up to be a PLC!), therfore the strange test for HEAP_ALLOCED - */ - - /* - { - StgInfoTable *info = get_itbl(graphroot); - ASSERT(!HEAP_ALLOCED(graphroot) || heapsize >= (nat) (graph-graphroot) || - // ToDo: check whether CAFs are really a special case here!! - info->type==CAF_BLACKHOLE || info->type==FETCH_ME || info->type==FETCH_ME_BQ); - } - */ - - /* check for magic end-of-buffer word */ - IF_DEBUG(sanity, ASSERT(*bufptr == END_OF_BUFFER_MARKER)); - - *gamap = PendingGABuffer; - *nGAs = (gaga - PendingGABuffer) / 2; - - IF_PAR_DEBUG(tables, - belch("** LAGA table after unpacking closure %p:", - graphroot); - printLAGAtable()); - - /* ToDo: are we *certain* graphroot has been set??? WDP 95/07 */ - ASSERT(graphroot!=NULL); - - IF_DEBUG(sanity, - { - StgPtr p; - - /* check the unpacked graph */ - //checkHeapChunk(graphroot,graph-sizeof(StgWord)); - - // if we do sanity checks, then wipe the pack buffer after unpacking - for (p=(StgPtr)packBuffer->buffer; p<(StgPtr)(packBuffer->buffer)+(packBuffer->size); ) - *p++ = 0xdeadbeef; - }); - - /* reset the global variable */ - globalUnpackBuffer = (rtsPackBuffer*)NULL; - -#if defined(PAR_TICKY) // HWL HAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACK - PAR_TICKY_UNPACK_GRAPH_END(unpacked_closures, unpacked_thunks); -#endif - - return (graphroot); -} - -//@cindex UnpackGA -static StgWord ** -UnpackGA(StgWord **bufptr, globalAddr *ga) -{ - /* First, unpack the next GA or PLC */ - ga->weight = (rtsWeight) *bufptr++; - - if (ga->weight == 2) { // unglobalised closure to follow - // nothing to do; closure starts at *bufptr - } else if (ga->weight > 0) { // fill in GA - ga->payload.gc.gtid = (GlobalTaskId) *bufptr++; - ga->payload.gc.slot = (int) *bufptr++; - } else { - ga->payload.plc = (StgPtr) *bufptr++; - } - return bufptr; -} - -//@cindex UnpackPLC -static StgClosure * -UnpackPLC(globalAddr *ga) -{ - /* No more to unpack; just set closure to local address */ - IF_PAR_DEBUG(pack, - belch("*<^^ Unpacked PLC at %x", ga->payload.plc)); - return (StgClosure*)ga->payload.plc; -} - -//@cindex UnpackOffset -static StgClosure * -UnpackOffset(globalAddr *ga) -{ - /* globalUnpackBuffer is a global var init in UnpackGraph */ - ASSERT(globalUnpackBuffer!=(rtsPackBuffer*)NULL); - /* No more to unpack; just set closure to cached address */ - IF_PAR_DEBUG(pack, - belch("*<__ Unpacked indirection to %p (was OFFSET %d)", - (StgClosure *)((globalUnpackBuffer->buffer)[ga->payload.gc.slot]), - ga->payload.gc.slot)); - return (StgClosure *)(globalUnpackBuffer->buffer)[ga->payload.gc.slot]; -} - -/* - Input: *bufptrP, *graphP ... ptrs to the pack buffer and into the heap. - - *bufptrP points to something that should be unpacked as a FETCH_ME: - | - v - +------------------------------- - | GA | FH of FM - +------------------------------- - - The first 3 words starting at *bufptrP are the GA address; the next - word is the generic FM info ptr followed by the remaining FH (if any) - The result after unpacking will be a FETCH_ME closure, pointed to by - *graphP at the start of the fct; - | - v - +------------------------+ - | FH of FM | ptr to a GA | - +------------------------+ - - The ptr field points into the RemoteGA table, which holds the actual GA. - *bufptrP has been updated to point to the next word in the buffer. - *graphP has been updated to point to the first free word at the end. -*/ - -static StgClosure* -UnpackFetchMe (StgWord ***bufptrP, StgClosure **graphP) { - StgClosure *closure, *foo; - globalAddr gaS; - - /* This fct relies on size of FM < size of FM in pack buffer */ - ASSERT(sizeofW(StgFetchMe)<=PACK_FETCHME_SIZE); - - /* fill in gaS from buffer */ - *bufptrP = UnpackGA(*bufptrP, &gaS); - /* might be an offset to a closure in the pack buffer */ - if (isOffset(&gaS)) { - belch("*< UnpackFetchMe: found OFFSET to %d when unpacking FM at buffer loc %p", - gaS.payload.gc.slot, *bufptrP); - - closure = UnpackOffset(&gaS); - /* return address of previously unpacked closure; leaves *graphP unchanged */ - return closure; - } - - /* we have a proper GA at hand */ - ASSERT(LOOKS_LIKE_GA(&gaS)); - - IF_DEBUG(sanity, - if (isFixed(&gaS)) - barf("*< UnpackFetchMe: found PLC where FM was expected %p (%s)", - *bufptrP, info_type((StgClosure*)*bufptrP))); - - IF_PAR_DEBUG(pack, - belch("*<_- Unpacked @ %p a FETCH_ME to GA ", - *graphP); - printGA(&gaS); - fputc('\n', stderr)); - - /* the next thing must be the IP to a FETCH_ME closure */ - ASSERT(get_itbl((StgClosure *)*bufptrP)->type == FETCH_ME); - - closure = *graphP; - /* fill in the closure from the buffer */ - FillInClosure(bufptrP, closure); - - /* the newly built closure is a FETCH_ME */ - ASSERT(get_itbl(closure)->type == FETCH_ME); - - /* common up with other graph if necessary - this also assigns the contents of gaS to the ga field of the FM closure */ - foo = SetGAandCommonUp(&gaS, closure, rtsTrue); - - ASSERT(foo!=closure || LOOKS_LIKE_GA(((StgFetchMe*)closure)->ga)); - - IF_PAR_DEBUG(pack, - if (foo==closure) { // only if not commoned up - belch("*<_- current FM @ %p next FM @ %p; unpacked FM @ %p is ", - *graphP, *graphP+sizeofW(StgFetchMe), closure); - printClosure(closure); - }); - *graphP += sizeofW(StgFetchMe); - return foo; -} - -/* - Unpack an array of words. - Could use generic unpack most of the time, but cleaner to separate it. - ToDo: implement packing of MUT_ARRAYs -*/ - -//@cindex UnpackArray -static void -UnpackArray(StgWord ***bufptrP, StgClosure *graph) -{ - StgInfoTable *info; - StgWord **bufptr=*bufptrP; - nat size, ptrs, nonptrs, vhs, i, n; - char str[80]; - - /* yes, I know I am paranoid; but who's asking !? */ - IF_DEBUG(sanity, - info = get_closure_info((StgClosure*)bufptr, - &size, &ptrs, &nonptrs, &vhs, str); - ASSERT(info->type == ARR_WORDS || info->type == MUT_ARR_PTRS || - info->type == MUT_ARR_PTRS_FROZEN || info->type == MUT_VAR)); - - n = arr_words_words(((StgArrWords *)bufptr)); - // this includes the header!: arr_words_sizeW(stgCast(StgArrWords*,q)); - - IF_PAR_DEBUG(pack, - if (n<100) - belch("*<== unpacking an array of %d words %p (%s) (size=%d) |%s|\n", - n, (StgClosure*)bufptr, info_type((StgClosure*)bufptr), - arr_words_sizeW((StgArrWords *)bufptr), - /* print array (string?) */ - ((StgArrWords *)graph)->payload); - else - belch("*<== unpacking an array of %d words %p (%s) (size=%d)\n", - n, (StgClosure*)bufptr, info_type((StgClosure*)bufptr), - arr_words_sizeW((StgArrWords *)bufptr))); - - /* Unpack the header (2 words: info ptr and the number of words to follow) */ - ((StgArrWords *)graph)->header.info = (StgInfoTable*)*bufptr++; // assumes _HS==1; yuck! - ((StgArrWords *)graph)->bytes = ((StgWord)*bufptr++) * sizeof(StgWord); - - /* unpack the payload of the closure (all non-ptrs) */ - for (i=0; i<n; i++) - ((StgArrWords *)graph)->payload[i] = (StgWord)*bufptr++; - - ASSERT(bufptr==*bufptrP+arr_words_sizeW((StgArrWords *)*bufptrP)); - *bufptrP = bufptr; -} - -/* - Unpack a PAP in the buffer into a heap closure. - For each FETCHME we find in the packed PAP we have to unpack a separate - FETCHME closure and insert a pointer to this closure into the PAP. - We unpack all FETCHMEs into an area after the PAP proper (the `FM area'). - Note that the size of a FETCHME in the buffer is exactly the same as - the size of an unpacked FETCHME plus 1 word for the pointer to it. - Therefore, we just allocate packed_size words in the heap for the unpacking. - After this routine the heap starting from *graph looks like this: - - graph - | - v PAP closure | FM area | - +------------------------------------------------------------+ - | PAP header | n_args | fun | payload ... | FM_1 | FM_2 .... | - +------------------------------------------------------------+ - - where payload contains pointers to each of the unpacked FM_1, FM_2 ... - The size of the PAP closure plus all FMs is _HS+2+packed_size. -*/ - -//@cindex UnpackPAP -static nat -UnpackPAP(StgWord ***bufptrP, StgClosure *graph) -{ - nat n, i, j, packed_size = 0; - StgPtr p, q, end, payload_start, p_FMs; - const StgInfoTable* info; - StgWord bitmap; - StgWord **bufptr = *bufptrP; -#if defined(DEBUG) - nat FMs_in_PAP=0; - void checkPAPSanity(StgPAP *graph, StgPtr p_FM_begin, StgPtr p_FM_end); -#endif - - IF_PAR_DEBUG(pack, - belch("*<** UnpackPAP: unpacking PAP @ %p with %d words to closure %p", - *bufptr, *(bufptr+1), graph)); - - /* Unpack the PAP header (both fixed and variable) */ - ((StgPAP *)graph)->header.info = (StgInfoTable*)*bufptr++; - n = ((StgPAP *)graph)->n_args = (StgWord)*bufptr++; - ((StgPAP *)graph)->fun = (StgClosure*)*bufptr++; - packed_size = (nat)*bufptr++; - - IF_PAR_DEBUG(pack, - belch("*<** UnpackPAP: PAP header is [%p, %d, %p] %d", - ((StgPAP *)graph)->header.info, - ((StgPAP *)graph)->n_args, - ((StgPAP *)graph)->fun, - packed_size)); - - payload_start = (StgPtr)bufptr; - /* p points to the current word in the heap */ - p = (StgPtr)((StgPAP *)graph)->payload; // payload of PAP will be unpacked here - p_FMs = (StgPtr)graph+pap_sizeW((StgPAP*)graph); // FMs will be unpacked here - end = (StgPtr) payload_start+packed_size; - /* - The main loop unpacks the PAP in *bufptr into *p, with *p_FMS as the - FM area for unpacking all FETCHMEs encountered during unpacking. - */ - while ((StgPtr)bufptr<end) { - /* be sure that we don't write more than we allocated for this closure */ - ASSERT(p_FMs <= (StgPtr)(graph+_HS+2+packed_size)); - /* be sure that the unpacked PAP doesn't run into the FM area */ - ASSERT(p < (StgPtr)(graph+pap_sizeW((StgPAP*)graph))); - /* the loop body has been borrowed from scavenge_stack */ - q = *bufptr; // let q be the contents of the current pointer into the buffer - - /* Test whether the next thing is a FETCH_ME. - In PAPs FETCH_ME are encoded via a starting marker of ARGTAG_MAX+1 - */ - if (q==(StgPtr)(ARGTAG_MAX+1)) { - IF_PAR_DEBUG(pack, - belch("*<** UnpackPAP @ %p: unpacking FM; filling in ptr to FM area: %p", - p, p_FMs)); - bufptr++; // skip ARGTAG_MAX+1 marker - // Unpack a FM into the FM area after the PAP proper and insert pointer - *p++ = (StgWord)UnpackFetchMe(&bufptr, (StgClosure**)&p_FMs); - IF_DEBUG(sanity, FMs_in_PAP++); - continue; - } - - /* Test whether it is a PLC */ - if (q==(StgPtr)0) { // same as isFixed(q) - IF_PAR_DEBUG(pack, - belch("*<** UnpackPAP @ %p: unpacking PLC to %p", - p, *(bufptr+1))); - bufptr++; // skip 0 marker - *p++ = (StgWord)*bufptr++; - continue; - } - - /* If we've got a tag, pack all words in that block */ - if (IS_ARG_TAG((W_)q)) { // q stands for the no. of non-ptrs to follow - nat m = ARG_SIZE(q); // first word after this block - IF_PAR_DEBUG(pack, - belch("*<** UnpackPAP @ %p: unpacking %d words (tagged), starting @ %p", - p, m, p)); - for (i=0; i<m+1; i++) - *p++ = (StgWord)*bufptr++; - continue; - } - - /* - * Otherwise, q must be the info pointer of an activation - * record. All activation records have 'bitmap' style layout - * info. - */ - info = get_itbl((StgClosure *)q); - switch (info->type) { - - /* Dynamic bitmap: the mask is stored on the stack */ - case RET_DYN: - IF_PAR_DEBUG(pack, - belch("*<** UnpackPAP @ %p: RET_DYN", - p)); - - /* Pack the header as is */ - ((StgRetDyn *)p)->info = (StgWord)*bufptr++; - ((StgRetDyn *)p)->liveness = (StgWord)*bufptr++; - ((StgRetDyn *)p)->ret_addr = (StgWord)*bufptr++; - p += 3; - - //bitmap = ((StgRetDyn *)p)->liveness; - //p = (P_)&((StgRetDyn *)p)->payload[0]; - goto small_bitmap; - - /* probably a slow-entry point return address: */ - case FUN: - case FUN_STATIC: - { - IF_PAR_DEBUG(pack, - belch("*<** UnpackPAP @ %p: FUN or FUN_STATIC", - p)); - - ((StgClosure *)p)->header.info = (StgInfoTable*)*bufptr; - p++; - - goto follow_srt; //?? - } - - /* Using generic code here; could inline as in scavenge_stack */ - case UPDATE_FRAME: - { - StgUpdateFrame *frame = (StgUpdateFrame *)p; - //nat type = get_itbl(frame->updatee)->type; - - //ASSERT(type==BLACKHOLE || type==CAF_BLACKHOLE || type==BLACKHOLE_BQ); - - IF_PAR_DEBUG(pack, - belch("*<** UnpackPAP @ %p: UPDATE_FRAME", - p)); - - ((StgUpdateFrame *)p)->header.info = (StgInfoTable*)*bufptr++; - ((StgUpdateFrame *)p)->link = (StgUpdateFrame*)*bufptr++; // ToDo: fix intra-stack pointer - ((StgUpdateFrame *)p)->updatee = (StgClosure*)*bufptr++; // ToDo: follow link - - p += 3; - } - - /* small bitmap (< 32 entries, or 64 on a 64-bit machine) */ - case STOP_FRAME: - { - IF_PAR_DEBUG(pack, - belch("*<** UnpackPAP @ %p: STOP_FRAME", - p)); - ((StgStopFrame *)p)->header.info = (StgInfoTable*)*bufptr; - p++; - } - - case CATCH_FRAME: - { - IF_PAR_DEBUG(pack, - belch("*<** UnpackPAP @ %p: CATCH_FRAME", - p)); - - ((StgCatchFrame *)p)->header.info = (StgInfoTable*)*bufptr++; - ((StgCatchFrame *)p)->link = (StgUpdateFrame*)*bufptr++; - ((StgCatchFrame *)p)->exceptions_blocked = (StgInt)*bufptr++; - ((StgCatchFrame *)p)->handler = (StgClosure*)*bufptr++; - p += 4; - } - - case SEQ_FRAME: - { - IF_PAR_DEBUG(pack, - belch("*<** UnpackPAP @ %p: UPDATE_FRAME", - p)); - - ((StgSeqFrame *)p)->header.info = (StgInfoTable*)*bufptr++; - ((StgSeqFrame *)p)->link = (StgUpdateFrame*)*bufptr++; - - // ToDo: handle bitmap - bitmap = info->layout.bitmap; - - p = (StgPtr)&(((StgClosure *)p)->payload); - goto small_bitmap; - } - case RET_BCO: - case RET_SMALL: - case RET_VEC_SMALL: - IF_PAR_DEBUG(pack, - belch("*<** UnpackPAP @ %p: RET_{BCO,SMALL,VEC_SMALL}", - p)); - - - ((StgClosure *)p)->header.info = (StgInfoTable*)*bufptr++; - p++; - // ToDo: handle bitmap - bitmap = info->layout.bitmap; - /* this assumes that the payload starts immediately after the info-ptr */ - - small_bitmap: - while (bitmap != 0) { - if ((bitmap & 1) == 0) { - *p++ = (StgWord)UnpackFetchMe(&bufptr, (StgClosure**)&p_FMs); - IF_DEBUG(sanity, FMs_in_PAP++); - } else { - *p++ = (StgWord)*bufptr++; - } - bitmap = bitmap >> 1; - } - - follow_srt: - belch("*<-- UnpackPAP: nothing to do for follow_srt"); - continue; - - /* large bitmap (> 32 entries) */ - case RET_BIG: - case RET_VEC_BIG: - { - StgPtr q; - StgLargeBitmap *large_bitmap; - - IF_PAR_DEBUG(pack, - belch("*<** UnpackPAP @ %p: RET_{BIG,VEC_BIG} (large_bitmap=%p)", - p, info->layout.large_bitmap)); - - - ((StgClosure *)p)->header.info = (StgInfoTable*)*bufptr++; - p++; - - large_bitmap = info->layout.large_bitmap; - - for (j=0; j<large_bitmap->size; j++) { - bitmap = large_bitmap->bitmap[j]; - q = p + BITS_IN(W_); - while (bitmap != 0) { - if ((bitmap & 1) == 0) { - *p++ = (StgWord)UnpackFetchMe(&bufptr, (StgClosure**)&p_FMs); - IF_DEBUG(sanity, FMs_in_PAP++); - } else { - *p++ = (StgWord)*bufptr; - } - bitmap = bitmap >> 1; - } - if (j+1 < large_bitmap->size) { - while (p < q) { - *p++ = (StgWord)UnpackFetchMe(&bufptr, (StgClosure**)&p_FMs); - IF_DEBUG(sanity, FMs_in_PAP++); - } - } - } - - /* and don't forget to follow the SRT */ - goto follow_srt; - } - - default: - barf("UnpackPAP: weird activation record found on stack: %d", - (int)(info->type)); - } - } - IF_PAR_DEBUG(pack, - belch("*<** UnpackPAP finished; unpacked closure @ %p is:", - (StgClosure *)graph); - printClosure((StgClosure *)graph)); - - IF_DEBUG(sanity, /* check sanity of unpacked PAP */ - checkClosure(graph)); - - *bufptrP = bufptr; - /* - Now p points to the first word after the PAP proper and p_FMs points - to the next free word in the heap; everything between p and p_FMs are - FETCHMEs - */ - IF_DEBUG(sanity, - checkPAPSanity(graph, p, p_FMs)); - - /* we have to return the size of PAP + FMs as size of the unpacked thing */ - ASSERT(graph+pap_sizeW((StgPAP*)graph)==p); - return (nat)((StgClosure*)p_FMs-graph); -} - -#if defined(DEBUG) -/* - Check sanity of a PAP after unpacking the PAP. - This means that there is slice of heap after the PAP containing FETCHMEs -*/ -void -checkPAPSanity(StgPAP *graph, StgPtr p_FM_begin, StgPtr p_FM_end) -{ - StgPtr xx; - - /* check that the main unpacked closure is a PAP */ - ASSERT(graph->header.info = &stg_PAP_info); - checkClosure(graph); - /* check that all of the closures in the FM-area are FETCHMEs */ - for (xx=p_FM_begin; xx<p_FM_end; xx += sizeofW(StgFetchMe)) { - /* must be a FETCHME closure */ - ASSERT(((StgClosure*)xx)->header.info == &stg_FETCH_ME_info); - /* it might have been commoned up (=> marked as garbage); - otherwise it points to a GA */ - ASSERT((((StgFetchMe*)xx)->ga)==GARBAGE_MARKER || - LOOKS_LIKE_GA(((StgFetchMe*)xx)->ga)); - } - /* traverse the payload of the PAP */ - for (xx=graph->payload; xx-(StgPtr)(graph->payload)<graph->n_args; xx++) { - /* if the current elem is a pointer into the FM area, check that - the GA field is ok */ - ASSERT(!(p_FM_begin<(StgPtr)*xx && (StgPtr)*xx<p_FM_end) || - LOOKS_LIKE_GA(((StgFetchMe*)*xx)->ga)); - } -} -#endif /* DEBUG */ -#endif /* PAR */ - -//@node GranSim Code, , GUM code, Unpacking routines -//@subsubsection GranSim Code - -/* - For GrAnSim: No actual unpacking should be necessary. We just - have to walk over the graph and set the bitmasks appropriately. - Since we use RBHs similarly to GUM but without an ACK message/event - we have to revert the RBH from within the UnpackGraph routine (good luck!) - -- HWL -*/ - -#if defined(GRAN) -void -CommonUp(StgClosure *src, StgClosure *dst) -{ - barf("CommonUp: should never be entered in a GranSim setup"); -} - -StgClosure* -UnpackGraph(buffer) -rtsPackBuffer* buffer; -{ - nat size, ptrs, nonptrs, vhs, - bufptr = 0; - StgClosure *closure, *graphroot, *graph; - StgInfoTable *ip; - StgWord bufsize, unpackedsize, - pptr = 0, pptrs = 0, pvhs; - StgTSO* tso; - char str[240], str1[80]; - int i; - - bufptr = 0; - graphroot = buffer->buffer[0]; - - tso = buffer->tso; - - /* Unpack the header */ - unpackedsize = buffer->unpacked_size; - bufsize = buffer->size; - - IF_GRAN_DEBUG(pack, - belch("<<< Unpacking <<%d>> (buffer @ %p):\n (root @ %p, PE %d,size=%d), demanded by TSO %d (%p)[PE %d]", - buffer->id, buffer, graphroot, where_is(graphroot), - bufsize, tso->id, tso, - where_is((StgClosure *)tso))); - - do { - closure = buffer->buffer[bufptr++]; /* that's all we need for GrAnSim -- HWL */ - - /* Actually only ip is needed; rest is useful for TESTING -- HWL */ - ip = get_closure_info(closure, - &size, &ptrs, &nonptrs, &vhs, str); - - IF_GRAN_DEBUG(pack, - sprintf(str, "** (%p): Changing bitmask[%s]: 0x%x ", - closure, (closure_HNF(closure) ? "NF" : "__"), - PROCS(closure))); - - if (get_itbl(closure)->type == RBH) { - /* if it's an RBH, we have to revert it into a normal closure, thereby - awakening the blocking queue; not that this is code currently not - needed in GUM, but it should be added with the new features in - GdH (and the implementation of an NACK message) - */ - // closure->header.gran.procs = PE_NUMBER(CurrentProc); - SET_GRAN_HDR(closure, PE_NUMBER(CurrentProc)); /* Move node */ - - IF_GRAN_DEBUG(pack, - strcat(str, " (converting RBH) ")); - - convertFromRBH(closure); /* In GUM that's done by convertToFetchMe */ - - IF_GRAN_DEBUG(pack, - belch(":: closure %p (%s) is a RBH; after reverting: IP=%p", - closure, info_type(closure), get_itbl(closure))); - } else if (IS_BLACK_HOLE(closure)) { - IF_GRAN_DEBUG(pack, - belch(":: closure %p (%s) is a BH; copying node to %d", - closure, info_type(closure), CurrentProc)); - closure->header.gran.procs |= PE_NUMBER(CurrentProc); /* Copy node */ - } else if ( (closure->header.gran.procs & PE_NUMBER(CurrentProc)) == 0 ) { - if (closure_HNF(closure)) { - IF_GRAN_DEBUG(pack, - belch(":: closure %p (%s) is a HNF; copying node to %d", - closure, info_type(closure), CurrentProc)); - closure->header.gran.procs |= PE_NUMBER(CurrentProc); /* Copy node */ - } else { - IF_GRAN_DEBUG(pack, - belch(":: closure %p (%s) is no (R)BH or HNF; moving node to %d", - closure, info_type(closure), CurrentProc)); - closure->header.gran.procs = PE_NUMBER(CurrentProc); /* Move node */ - } - } - - IF_GRAN_DEBUG(pack, - sprintf(str1, "0x%x", PROCS(closure)); strcat(str, str1)); - IF_GRAN_DEBUG(pack, belch(str)); - - } while (bufptr<buffer->size) ; /* (parent != NULL); */ - - /* In GrAnSim we allocate pack buffers dynamically! -- HWL */ - free(buffer->buffer); - free(buffer); - - IF_GRAN_DEBUG(pack, - belch("PrintGraph of %p is:", graphroot); PrintGraph(graphroot,0)); - - return (graphroot); -} -#endif /* GRAN */ - -//@node Aux fcts for packing, Printing Packet Contents, Unpacking routines, Graph packing -//@subsection Aux fcts for packing - -//@menu -//* Offset table:: -//* Packet size:: -//* Types of Global Addresses:: -//* Closure Info:: -//@end menu - -//@node Offset table, Packet size, Aux fcts for packing, Aux fcts for packing -//@subsubsection Offset table - -/* - DonePacking is called when we've finished packing. It releases memory - etc. */ - -//@cindex DonePacking - -# if defined(PAR) - -static void -DonePacking(void) -{ - freeHashTable(offsetTable, NULL); - offsetTable = NULL; -} - -/* - AmPacking records that the closure is being packed. Note the abuse of - the data field in the hash table -- this saves calling @malloc@! */ - -//@cindex AmPacking - -static void -AmPacking(closure) -StgClosure *closure; -{ - insertHashTable(offsetTable, (StgWord) closure, (void *) (StgWord) pack_locn); -} - -/* - OffsetFor returns an offset for a closure which is already being packed. */ - -//@cindex OffsetFor - -static int -OffsetFor(closure) -StgClosure *closure; -{ - return (int) (StgWord) lookupHashTable(offsetTable, (StgWord) closure); -} - -/* - NotYetPacking determines whether the closure's already being packed. - Offsets $<$ @PACK_HDR_SIZE@ (e.g. 0) mean no. */ - -//@cindex NotYetPacking - -static rtsBool -NotYetPacking(offset) -int offset; -{ - return(offset == 0); // ToDo: what if root is found again?? FIX -} - -# else /* GRAN */ - -static void -DonePacking(void) -{ - /* nothing */ -} - -/* - NotYetPacking searches through the whole pack buffer for closure. */ - -static rtsBool -NotYetPacking(closure) -StgClosure *closure; -{ nat i; - rtsBool found = rtsFalse; - - for (i=0; (i<pack_locn) && !found; i++) - found = globalPackBuffer->buffer[i]==closure; - - return (!found); -} -# endif - -//@node Packet size, Closure Info, Offset table, Aux fcts for packing -//@subsubsection Packet size - -/* - The size needed if all currently queued closures are packed as FETCH_ME - closures. This represents the headroom we must have when packing the - buffer in order to maintain all links in the graphs. -*/ -// ToDo: check and merge cases -#if defined(PAR) -static nat -QueuedClosuresMinSize (nat ptrs) { - return ((clq_size - clq_pos) + ptrs) * PACK_FETCHME_SIZE; -} -#else /* GRAN */ -static nat -QueuedClosuresMinSize (nat ptrs) { - return ((clq_size - clq_pos) + ptrs) * PACK_FETCHME_SIZE; -} -#endif - -/* - RoomToPack determines whether there's room to pack the closure into - the pack buffer based on - - o how full the buffer is already, - o the closures' size and number of pointers (which must be packed as GAs), - o the size and number of pointers held by any primitive arrays that it - points to - - It has a *side-effect* (naughty, naughty) in assigning roomInBuffer - to rtsFalse. -*/ - -//@cindex RoomToPack -static rtsBool -RoomToPack(size, ptrs) -nat size, ptrs; -{ -# if defined(PAR) - if (roomInBuffer && - (pack_locn + // where we are in the buffer right now - size + // space needed for the current closure - QueuedClosuresMinSize(ptrs) // space for queued closures as FETCH_MEs - + 1 // headroom (DEBUGGING only) - >= - RTS_PACK_BUFFER_SIZE)) - { - roomInBuffer = rtsFalse; - } -# else /* GRAN */ - if (roomInBuffer && - (unpacked_size + - size + - QueuedClosuresMinSize(ptrs) - >= - RTS_PACK_BUFFER_SIZE)) - { - roomInBuffer = rtsFalse; - } -# endif - return (roomInBuffer); -} - -//@node Closure Info, , Packet size, Aux fcts for packing -//@subsubsection Closure Info - -/* - Closure Info - - @get_closure_info@ determines the size, number of pointers etc. for this - type of closure -- see @SMInfoTables.lh@ for the legal info. types etc. - -[Can someone please keep this function up to date. I keep needing it - (or something similar) for interpretive code, and it keeps - bit-rotting. {\em It really belongs somewhere else too}. KH @@ 17/2/95] */ - -#if 0 - -// {Parallel.h}Daq ngoqvam vIroQpu' - -# if defined(GRAN) || defined(PAR) -/* extracting specific info out of closure; currently only used in GRAN -- HWL */ -//@cindex get_closure_info -StgInfoTable* -get_closure_info(node, size, ptrs, nonptrs, vhs, info_hdr_ty) -StgClosure* node; -nat *size, *ptrs, *nonptrs, *vhs; -char *info_hdr_ty; -{ - StgInfoTable *info; - - info = get_itbl(node); - /* the switch shouldn't be necessary, really; just use default case */ - switch (info->type) { -#if 0 - case CONSTR_1_0: - case THUNK_1_0: - case FUN_1_0: - *size = sizeW_fromITBL(info); - *ptrs = (nat) 1; // (info->layout.payload.ptrs); - *nonptrs = (nat) 0; // (info->layout.payload.nptrs); - *vhs = (nat) 0; // unknown - info_hdr_type(node, info_hdr_ty); - return info; - - case CONSTR_0_1: - case THUNK_0_1: - case FUN_0_1: - *size = sizeW_fromITBL(info); - *ptrs = (nat) 0; // (info->layout.payload.ptrs); - *nonptrs = (nat) 1; // (info->layout.payload.nptrs); - *vhs = (nat) 0; // unknown - info_hdr_type(node, info_hdr_ty); - return info; - - case CONSTR_2_0: - case THUNK_2_0: - case FUN_2_0: - *size = sizeW_fromITBL(info); - *ptrs = (nat) 2; // (info->layout.payload.ptrs); - *nonptrs = (nat) 0; // (info->layout.payload.nptrs); - *vhs = (nat) 0; // unknown - info_hdr_type(node, info_hdr_ty); - return info; - - case CONSTR_1_1: - case THUNK_1_1: - case FUN_1_1: - *size = sizeW_fromITBL(info); - *ptrs = (nat) 1; // (info->layout.payload.ptrs); - *nonptrs = (nat) 1; // (info->layout.payload.nptrs); - *vhs = (nat) 0; // unknown - info_hdr_type(node, info_hdr_ty); - return info; - - case CONSTR_0_2: - case THUNK_0_2: - case FUN_0_2: - *size = sizeW_fromITBL(info); - *ptrs = (nat) 0; // (info->layout.payload.ptrs); - *nonptrs = (nat) 2; // (info->layout.payload.nptrs); - *vhs = (nat) 0; // unknown - info_hdr_type(node, info_hdr_ty); - return info; -#endif - case RBH: - { - StgInfoTable *rip = REVERT_INFOPTR(info); // closure to revert to - *size = sizeW_fromITBL(rip); - *ptrs = (nat) (rip->layout.payload.ptrs); - *nonptrs = (nat) (rip->layout.payload.nptrs); - *vhs = (nat) 0; // unknown - info_hdr_type(node, info_hdr_ty); - return rip; // NB: we return the reverted info ptr for a RBH!!!!!! - } - - default: - *size = sizeW_fromITBL(info); - *ptrs = (nat) (info->layout.payload.ptrs); - *nonptrs = (nat) (info->layout.payload.nptrs); - *vhs = (nat) 0; // unknown - info_hdr_type(node, info_hdr_ty); - return info; - } -} - -//@cindex IS_BLACK_HOLE -rtsBool -IS_BLACK_HOLE(StgClosure* node) -{ - StgInfoTable *info; - info = get_itbl(node); - return ((info->type == BLACKHOLE || info->type == RBH) ? rtsTrue : rtsFalse); -} - -//@cindex IS_INDIRECTION -StgClosure * -IS_INDIRECTION(StgClosure* node) -{ - StgInfoTable *info; - info = get_itbl(node); - switch (info->type) { - case IND: - case IND_OLDGEN: - case IND_PERM: - case IND_OLDGEN_PERM: - case IND_STATIC: - /* relies on indirectee being at same place for all these closure types */ - return (((StgInd*)node) -> indirectee); - default: - return NULL; - } -} - -/* -rtsBool -IS_THUNK(StgClosure* node) -{ - StgInfoTable *info; - info = get_itbl(node); - return ((info->type == THUNK || - info->type == THUNK_STATIC || - info->type == THUNK_SELECTOR) ? rtsTrue : rtsFalse); -} -*/ - -# endif /* GRAN */ -#endif /* 0 */ - -# if 0 -/* ngoq ngo' */ - -P_ -get_closure_info(closure, size, ptrs, nonptrs, vhs, type) -P_ closure; -W_ *size, *ptrs, *nonptrs, *vhs; -char *type; -{ - P_ ip = (P_) INFO_PTR(closure); - - if (closure==NULL) { - fprintf(stderr, "Qagh {get_closure_info}Daq: NULL closure\n"); - *size = *ptrs = *nonptrs = *vhs = 0; - strcpy(type,"ERROR in get_closure_info"); - return; - } else if (closure==PrelBase_Z91Z93_closure) { - /* fprintf(stderr, "Qagh {get_closure_info}Daq: PrelBase_Z91Z93_closure closure\n"); */ - *size = *ptrs = *nonptrs = *vhs = 0; - strcpy(type,"PrelBase_Z91Z93_closure"); - return; - }; - - ip = (P_) INFO_PTR(closure); - - switch (INFO_TYPE(ip)) { - case INFO_SPEC_U_TYPE: - case INFO_SPEC_S_TYPE: - case INFO_SPEC_N_TYPE: - *size = SPEC_CLOSURE_SIZE(closure); - *ptrs = SPEC_CLOSURE_NoPTRS(closure); - *nonptrs = SPEC_CLOSURE_NoNONPTRS(closure); - *vhs = 0 /*SPEC_VHS*/; - strcpy(type,"SPEC"); - break; - - case INFO_GEN_U_TYPE: - case INFO_GEN_S_TYPE: - case INFO_GEN_N_TYPE: - *size = GEN_CLOSURE_SIZE(closure); - *ptrs = GEN_CLOSURE_NoPTRS(closure); - *nonptrs = GEN_CLOSURE_NoNONPTRS(closure); - *vhs = GEN_VHS; - strcpy(type,"GEN"); - break; - - case INFO_DYN_TYPE: - *size = DYN_CLOSURE_SIZE(closure); - *ptrs = DYN_CLOSURE_NoPTRS(closure); - *nonptrs = DYN_CLOSURE_NoNONPTRS(closure); - *vhs = DYN_VHS; - strcpy(type,"DYN"); - break; - - case INFO_TUPLE_TYPE: - *size = TUPLE_CLOSURE_SIZE(closure); - *ptrs = TUPLE_CLOSURE_NoPTRS(closure); - *nonptrs = TUPLE_CLOSURE_NoNONPTRS(closure); - *vhs = TUPLE_VHS; - strcpy(type,"TUPLE"); - break; - - case INFO_DATA_TYPE: - *size = DATA_CLOSURE_SIZE(closure); - *ptrs = DATA_CLOSURE_NoPTRS(closure); - *nonptrs = DATA_CLOSURE_NoNONPTRS(closure); - *vhs = DATA_VHS; - strcpy(type,"DATA"); - break; - - case INFO_IMMUTUPLE_TYPE: - case INFO_MUTUPLE_TYPE: - *size = MUTUPLE_CLOSURE_SIZE(closure); - *ptrs = MUTUPLE_CLOSURE_NoPTRS(closure); - *nonptrs = MUTUPLE_CLOSURE_NoNONPTRS(closure); - *vhs = MUTUPLE_VHS; - strcpy(type,"(IM)MUTUPLE"); - break; - - case INFO_STATIC_TYPE: - *size = STATIC_CLOSURE_SIZE(closure); - *ptrs = STATIC_CLOSURE_NoPTRS(closure); - *nonptrs = STATIC_CLOSURE_NoNONPTRS(closure); - *vhs = STATIC_VHS; - strcpy(type,"STATIC"); - break; - - case INFO_CAF_TYPE: - case INFO_IND_TYPE: - *size = IND_CLOSURE_SIZE(closure); - *ptrs = IND_CLOSURE_NoPTRS(closure); - *nonptrs = IND_CLOSURE_NoNONPTRS(closure); - *vhs = IND_VHS; - strcpy(type,"CAF|IND"); - break; - - case INFO_CONST_TYPE: - *size = CONST_CLOSURE_SIZE(closure); - *ptrs = CONST_CLOSURE_NoPTRS(closure); - *nonptrs = CONST_CLOSURE_NoNONPTRS(closure); - *vhs = CONST_VHS; - strcpy(type,"CONST"); - break; - - case INFO_SPEC_RBH_TYPE: - *size = SPEC_RBH_CLOSURE_SIZE(closure); - *ptrs = SPEC_RBH_CLOSURE_NoPTRS(closure); - *nonptrs = SPEC_RBH_CLOSURE_NoNONPTRS(closure); - if (*ptrs <= 2) { - *nonptrs -= (2 - *ptrs); - *ptrs = 1; - } else - *ptrs -= 1; - *vhs = SPEC_RBH_VHS; - strcpy(type,"SPEC_RBH"); - break; - - case INFO_GEN_RBH_TYPE: - *size = GEN_RBH_CLOSURE_SIZE(closure); - *ptrs = GEN_RBH_CLOSURE_NoPTRS(closure); - *nonptrs = GEN_RBH_CLOSURE_NoNONPTRS(closure); - if (*ptrs <= 2) { - *nonptrs -= (2 - *ptrs); - *ptrs = 1; - } else - *ptrs -= 1; - *vhs = GEN_RBH_VHS; - strcpy(type,"GEN_RBH"); - break; - - case INFO_CHARLIKE_TYPE: - *size = CHARLIKE_CLOSURE_SIZE(closure); - *ptrs = CHARLIKE_CLOSURE_NoPTRS(closure); - *nonptrs = CHARLIKE_CLOSURE_NoNONPTRS(closure); - *vhs = CHARLIKE_VHS; - strcpy(type,"CHARLIKE"); - break; - - case INFO_INTLIKE_TYPE: - *size = INTLIKE_CLOSURE_SIZE(closure); - *ptrs = INTLIKE_CLOSURE_NoPTRS(closure); - *nonptrs = INTLIKE_CLOSURE_NoNONPTRS(closure); - *vhs = INTLIKE_VHS; - strcpy(type,"INTLIKE"); - break; - -# if !defined(GRAN) - case INFO_FETCHME_TYPE: - *size = FETCHME_CLOSURE_SIZE(closure); - *ptrs = FETCHME_CLOSURE_NoPTRS(closure); - *nonptrs = FETCHME_CLOSURE_NoNONPTRS(closure); - *vhs = FETCHME_VHS; - strcpy(type,"FETCHME"); - break; - - case INFO_FMBQ_TYPE: - *size = FMBQ_CLOSURE_SIZE(closure); - *ptrs = FMBQ_CLOSURE_NoPTRS(closure); - *nonptrs = FMBQ_CLOSURE_NoNONPTRS(closure); - *vhs = FMBQ_VHS; - strcpy(type,"FMBQ"); - break; -# endif - - case INFO_BQ_TYPE: - *size = BQ_CLOSURE_SIZE(closure); - *ptrs = BQ_CLOSURE_NoPTRS(closure); - *nonptrs = BQ_CLOSURE_NoNONPTRS(closure); - *vhs = BQ_VHS; - strcpy(type,"BQ"); - break; - - case INFO_BH_TYPE: - *size = BH_CLOSURE_SIZE(closure); - *ptrs = BH_CLOSURE_NoPTRS(closure); - *nonptrs = BH_CLOSURE_NoNONPTRS(closure); - *vhs = BH_VHS; - strcpy(type,"BH"); - break; - - case INFO_TSO_TYPE: - *size = 0; /* TSO_CLOSURE_SIZE(closure); */ - *ptrs = 0; /* TSO_CLOSURE_NoPTRS(closure); */ - *nonptrs = 0; /* TSO_CLOSURE_NoNONPTRS(closure); */ - *vhs = TSO_VHS; - strcpy(type,"TSO"); - break; - - case INFO_STKO_TYPE: - *size = 0; - *ptrs = 0; - *nonptrs = 0; - *vhs = STKO_VHS; - strcpy(type,"STKO"); - break; - - default: - fprintf(stderr, "get_closure_info: Unexpected closure type (%lu), closure %lx\n", - INFO_TYPE(ip), (StgWord) closure); - EXIT(EXIT_FAILURE); - } - - return ip; -} -# endif - -# if 0 -// Use allocate in Storage.c instead -/* - @AllocateHeap@ will bump the heap pointer by @size@ words if the space - is available, but it will not perform garbage collection. - ToDo: check whether we can use an existing STG allocation routine -- HWL -*/ - - -//@cindex AllocateHeap -StgPtr -AllocateHeap(size) -nat size; -{ - StgPtr newClosure; - - /* Allocate a new closure */ - if (Hp + size > HpLim) - return NULL; - - newClosure = Hp + 1; - Hp += size; - - return newClosure; -} -# endif - -# if defined(PAR) - -//@cindex doGlobalGC -void -doGlobalGC(void) -{ - fprintf(stderr,"Splat -- we just hit global GC!\n"); - stg_exit(EXIT_FAILURE); - //fishing = rtsFalse; - outstandingFishes--; -} - -# endif /* PAR */ - -//@node Printing Packet Contents, End of file, Aux fcts for packing, Graph packing -//@subsection Printing Packet Contents -/* - Printing Packet Contents - */ - -#if defined(DEBUG) || defined(GRAN_CHECK) - -//@cindex PrintPacket - -#if defined(PAR) -void -PrintPacket(packBuffer) -rtsPackBuffer *packBuffer; -{ - StgClosure *parent, *graphroot, *closure_start; - const StgInfoTable *ip; - globalAddr ga; - StgWord **bufptr, **slotptr; - - nat bufsize; - nat pptr = 0, pptrs = 0, pvhs; - nat locn = 0; - nat i; - nat size, ptrs, nonptrs, vhs; - char str[80]; - - /* disable printing if a non-std globalisation scheme is used; ToDo: FIX */ - if (RtsFlags.ParFlags.globalising != 0) - return; - - /* NB: this whole routine is more or less a copy of UnpackGraph with all - unpacking components replaced by printing fcts - Long live higher-order fcts! - */ - /* Initialisation */ - //InitPackBuffer(); /* in case it isn't already init'd */ - InitClosureQueue(); - // ASSERT(gaga==PendingGABuffer); - graphroot = (StgClosure *)NULL; - - /* Unpack the header */ - bufsize = packBuffer->size; - bufptr = packBuffer->buffer; - - fprintf(stderr, "*. Printing <<%d>> (buffer @ %p):\n", - packBuffer->id, packBuffer); - fprintf(stderr, "*. size: %d; unpacked_size: %d; tso: %p; buffer: %p\n", - packBuffer->size, packBuffer->unpacked_size, - packBuffer->tso, packBuffer->buffer); - - parent = (StgClosure *)NULL; - - do { - /* This is where we will ultimately save the closure's address */ - slotptr = bufptr; - locn = slotptr-(packBuffer->buffer); // index of closure in buffer - - /* First, unpack the next GA or PLC */ - ga.weight = (rtsWeight) *bufptr++; - - if (ga.weight == 2) { // unglobalised closure to follow - // nothing to do; closure starts at *bufptr - } else if (ga.weight > 0) { // fill in GA - ga.payload.gc.gtid = (GlobalTaskId) *bufptr++; - ga.payload.gc.slot = (int) *bufptr++; - } else - ga.payload.plc = (StgPtr) *bufptr++; - - /* Now unpack the closure body, if there is one */ - if (isFixed(&ga)) { - fprintf(stderr, "*. %u: PLC @ %p\n", locn, ga.payload.plc); - // closure = ga.payload.plc; - } else if (isOffset(&ga)) { - fprintf(stderr, "*. %u: OFFSET TO %d\n", locn, ga.payload.gc.slot); - // closure = (StgClosure *) buffer[ga.payload.gc.slot]; - } else { - /* Print normal closures */ - - ASSERT(bufsize > 0); - - fprintf(stderr, "*. %u: ((%x, %d, %x)) ", locn, - ga.payload.gc.gtid, ga.payload.gc.slot, ga.weight); - - closure_start = (StgClosure*)bufptr; - ip = get_closure_info((StgClosure *)bufptr, - &size, &ptrs, &nonptrs, &vhs, str); - - /* ToDo: check whether this is really needed */ - if (ip->type == FETCH_ME || ip->type == REMOTE_REF) { - size = _HS; - ptrs = nonptrs = vhs = 0; - } - /* ToDo: check whether this is really needed */ - if (ip->type == ARR_WORDS) { - ptrs = vhs = 0; - nonptrs = arr_words_words(((StgArrWords *)bufptr)); - size = arr_words_sizeW((StgArrWords *)bufptr); - } - - /* special code for printing a PAP in a buffer */ - if (ip->type == PAP || ip->type == AP_UPD) { - vhs = 3; - ptrs = 0; - nonptrs = (nat)((StgPAP *)bufptr)->payload[0]; - size = _HS+vhs+ptrs+nonptrs; - } - - /* - Remember, the generic closure layout is as follows: - +-------------------------------------------------+ - | FIXED HEADER | VARIABLE HEADER | PTRS | NON-PRS | - +-------------------------------------------------+ - */ - /* Print fixed header */ - fprintf(stderr, "FH ["); - for (i = 0; i < _HS; i++) - fprintf(stderr, " %p", *bufptr++); - - if (ip->type == FETCH_ME || ip->type == REMOTE_REF) - size = ptrs = nonptrs = vhs = 0; - - // VH is always empty in the new RTS - ASSERT(vhs==0 || - ip->type == PAP || ip->type == AP_UPD); - /* Print variable header */ - fprintf(stderr, "] VH ["); - for (i = 0; i < vhs; i++) - fprintf(stderr, " %p", *bufptr++); - - //fprintf(stderr, "] %d PTRS [", ptrs); - /* Pointers will be filled in later */ - - fprintf(stderr, " ] (%d, %d) [", ptrs, nonptrs); - /* Print non-pointers */ - for (i = 0; i < nonptrs; i++) - fprintf(stderr, " %p", *bufptr++); - - fprintf(stderr, "] (%s)\n", str); - - /* Indirections are never packed */ - // ASSERT(INFO_PTR(graph) != (W_) Ind_info_TO_USE); - - /* Add to queue for processing - When just printing the packet we do not have an unpacked closure - in hand, so we feed it the packet entry; - again, this assumes that at least the fixed header of the closure - has the same layout in the packet; also we may not overwrite entries - in the packet (done in Unpack), but for printing that's a bad idea - anyway */ - QueueClosure((StgClosure *)closure_start); - - /* No Common up needed for printing */ - - /* No Sort out the global address mapping for printing */ - - } /* normal closure case */ - - /* Locate next parent pointer */ - pptr++; - while (pptr + 1 > pptrs) { - parent = DeQueueClosure(); - - if (parent == NULL) - break; - else { - (void) get_closure_info(parent, &size, &pptrs, &nonptrs, - &pvhs, str); - pptr = 0; - } - } - } while (parent != NULL); - fprintf(stderr, "*. --- End packet <<%d>> (claimed size=%d; real size=%d)---\n", - packBuffer->id, packBuffer->size, size); - -} - -/* - Doing a sanity check on a packet. - This does a full iteration over the packet, as in PrintPacket. -*/ -//@cindex checkPacket -void -checkPacket(packBuffer) -rtsPackBuffer *packBuffer; -{ - StgClosure *parent, *graphroot, *closure_start; - const StgInfoTable *ip; - globalAddr ga; - StgWord **bufptr, **slotptr; - - nat bufsize; - nat pptr = 0, pptrs = 0, pvhs; - nat locn = 0; - nat size, ptrs, nonptrs, vhs; - char str[80]; - - /* NB: this whole routine is more or less a copy of UnpackGraph with all - unpacking components replaced by printing fcts - Long live higher-order fcts! - */ - /* Initialisation */ - //InitPackBuffer(); /* in case it isn't already init'd */ - InitClosureQueue(); - // ASSERT(gaga==PendingGABuffer); - graphroot = (StgClosure *)NULL; - - /* Unpack the header */ - bufsize = packBuffer->size; - bufptr = packBuffer->buffer; - parent = (StgClosure *)NULL; - ASSERT(bufsize > 0); - do { - /* check that we are not at the end of the buffer, yet */ - IF_DEBUG(sanity, ASSERT(*bufptr != END_OF_BUFFER_MARKER)); - - /* This is where we will ultimately save the closure's address */ - slotptr = bufptr; - locn = slotptr-(packBuffer->buffer); // index of closure in buffer - ASSERT(locn<=bufsize); - - /* First, check whether we have a GA, a PLC, or an OFFSET at hand */ - ga.weight = (rtsWeight) *bufptr++; - - if (ga.weight == 2) { // unglobalised closure to follow - // nothing to do; closure starts at *bufptr - } else if (ga.weight > 0) { // fill in GA - ga.payload.gc.gtid = (GlobalTaskId) *bufptr++; - ga.payload.gc.slot = (int) *bufptr++; - } else - ga.payload.plc = (StgPtr) *bufptr++; - - /* Now unpack the closure body, if there is one */ - if (isFixed(&ga)) { - /* It's a PLC */ - ASSERT(LOOKS_LIKE_STATIC(ga.payload.plc)); - } else if (isOffset(&ga)) { - ASSERT(ga.payload.gc.slot<=(int)bufsize); - } else { - /* normal closure */ - ASSERT(!RtsFlags.ParFlags.globalising==0 || LOOKS_LIKE_GA(&ga)); - - closure_start = (StgClosure*)bufptr; - ASSERT(LOOKS_LIKE_GHC_INFO((StgPtr)*bufptr)); - ip = get_closure_info((StgClosure *)bufptr, - &size, &ptrs, &nonptrs, &vhs, str); - - /* ToDo: check whether this is really needed */ - if (ip->type == FETCH_ME || ip->type == REMOTE_REF) { - size = _HS; - ptrs = nonptrs = vhs = 0; - } - /* ToDo: check whether this is really needed */ - if (ip->type == ARR_WORDS) { - ptrs = vhs = 0; - nonptrs = arr_words_words(((StgArrWords *)bufptr))+1; // payload+words - size = arr_words_sizeW((StgArrWords *)bufptr); - ASSERT(size==_HS+vhs+nonptrs); - } - /* special code for printing a PAP in a buffer */ - if (ip->type == PAP || ip->type == AP_UPD) { - vhs = 3; - ptrs = 0; - nonptrs = (nat)((StgPAP *)bufptr)->payload[0]; - size = _HS+vhs+ptrs+nonptrs; - } - - /* no checks on contents of closure (pointers aren't packed anyway) */ - ASSERT(_HS+vhs+nonptrs>=MIN_NONUPD_SIZE); - bufptr += _HS+vhs+nonptrs; - - /* Add to queue for processing */ - QueueClosure((StgClosure *)closure_start); - - /* No Common up needed for checking */ - - /* No Sort out the global address mapping for checking */ - - } /* normal closure case */ - - /* Locate next parent pointer */ - pptr++; - while (pptr + 1 > pptrs) { - parent = DeQueueClosure(); - - if (parent == NULL) - break; - else { - //ASSERT(LOOKS_LIKE_GHC_INFO((StgPtr)*parent)); - (void) get_closure_info(parent, &size, &pptrs, &nonptrs, - &pvhs, str); - pptr = 0; - } - } - } while (parent != NULL); - /* we unpacked exactly as many words as there are in the buffer */ - ASSERT(packBuffer->size == bufptr-(packBuffer->buffer)); - /* check for magic end-of-buffer word */ - IF_DEBUG(sanity, ASSERT(*bufptr == END_OF_BUFFER_MARKER)); -} -#else /* GRAN */ -void -PrintPacket(buffer) -rtsPackBuffer *buffer; -{ - // extern char *info_hdr_type(P_ infoptr); /* defined in Threads.lc */ - // extern char *display_info_type(P_ infoptr); /* defined in Threads.lc */ - - StgInfoTable *info; - nat size, ptrs, nonptrs, vhs; - char info_hdr_ty[80]; - char str1[80], str2[80], junk_str[80]; - - /* globalAddr ga; */ - - nat bufsize, unpacked_size ; - StgClosure *parent; - nat pptr = 0, pptrs = 0, pvhs; - - nat unpack_locn = 0; - nat gastart = unpack_locn; - nat closurestart = unpack_locn; - - StgTSO *tso; - StgClosure *closure, *p; - - nat i; - - fprintf(stderr, "*** Printing <<%d>> (buffer @ %p):\n", buffer->id, buffer); - fprintf(stderr, " size: %d; unpacked_size: %d; tso: %d (%p); buffer: %p\n", - buffer->size, buffer->unpacked_size, buffer->tso, buffer->buffer); - fputs(" contents: ", stderr); - for (unpack_locn=0; unpack_locn<buffer->size; unpack_locn++) { - closure = buffer->buffer[unpack_locn]; - fprintf(stderr, ", %p (%s)", - closure, info_type(closure)); - } - fputc('\n', stderr); - -#if 0 - /* traverse all elements of the graph; omitted for now, but might be usefule */ - InitClosureQueue(); - - tso = buffer->tso; - - /* Unpack the header */ - unpacked_size = buffer->unpacked_size; - bufsize = buffer->size; - - fprintf(stderr, "Packet %p, size %u (unpacked size is %u); demanded by TSO %d (%p)[PE %d]\n--- Begin ---\n", - buffer, bufsize, unpacked_size, - tso->id, tso, where_is((StgClosure*)tso)); - - do { - closurestart = unpack_locn; - closure = buffer->buffer[unpack_locn++]; - - fprintf(stderr, "[%u]: (%p) ", closurestart, closure); - - info = get_closure_info(closure, &size, &ptrs, &nonptrs, &vhs, str1); - strcpy(str2, str1); - fprintf(stderr, "(%s|%s) ", str1, str2); - - if (info->type == FETCH_ME || info->type == FETCH_ME_BQ || - IS_BLACK_HOLE(closure)) - size = ptrs = nonptrs = vhs = 0; - - if (closure_THUNK(closure)) { - if (closure_UNPOINTED(closure)) - fputs("UNPOINTED ", stderr); - else - fputs("POINTED ", stderr); - } - if (IS_BLACK_HOLE(closure)) { - fputs("BLACK HOLE\n", stderr); - } else { - /* Fixed header */ - fprintf(stderr, "FH ["); - for (i = 0, p = (StgClosure*)&(closure->header); i < _HS; i++, p++) - fprintf(stderr, " %p", *p); - - /* Variable header - if (vhs > 0) { - fprintf(stderr, "] VH [%p", closure->payload[_HS]); - - for (i = 1; i < vhs; i++) - fprintf(stderr, " %p", closure->payload[_HS+i]); - } - */ - fprintf(stderr, "] PTRS %u", ptrs); - - /* Non-pointers */ - if (nonptrs > 0) { - fprintf(stderr, " NPTRS [%p", closure->payload[_HS+vhs]); - - for (i = 1; i < nonptrs; i++) - fprintf(stderr, " %p", closure->payload[_HS+vhs+i]); - - putc(']', stderr); - } - putc('\n', stderr); - } - } while (unpack_locn<bufsize) ; /* (parent != NULL); */ - - fprintf(stderr, "--- End ---\n\n"); -#endif /* 0 */ -} -#endif /* PAR */ -#endif /* DEBUG || GRAN_CHECK */ - -#endif /* PAR || GRAN -- whole file */ - -//@node End of file, , Printing Packet Contents, Graph packing -//@subsection End of file - -//@index -//* AllocateHeap:: @cindex\s-+AllocateHeap -//* AmPacking:: @cindex\s-+AmPacking -//* CommonUp:: @cindex\s-+CommonUp -//* DeQueueClosure:: @cindex\s-+DeQueueClosure -//* DeQueueClosure:: @cindex\s-+DeQueueClosure -//* DonePacking:: @cindex\s-+DonePacking -//* FillInClosure:: @cindex\s-+FillInClosure -//* IS_BLACK_HOLE:: @cindex\s-+IS_BLACK_HOLE -//* IS_INDIRECTION:: @cindex\s-+IS_INDIRECTION -//* InitClosureQueue:: @cindex\s-+InitClosureQueue -//* InitPendingGABuffer:: @cindex\s-+InitPendingGABuffer -//* LocateNextParent:: @cindex\s-+LocateNextParent -//* NotYetPacking:: @cindex\s-+NotYetPacking -//* OffsetFor:: @cindex\s-+OffsetFor -//* Pack:: @cindex\s-+Pack -//* PackArray:: @cindex\s-+PackArray -//* PackClosure:: @cindex\s-+PackClosure -//* PackFetchMe:: @cindex\s-+PackFetchMe -//* PackGeneric:: @cindex\s-+PackGeneric -//* PackNearbyGraph:: @cindex\s-+PackNearbyGraph -//* PackOneNode:: @cindex\s-+PackOneNode -//* PackPAP:: @cindex\s-+PackPAP -//* PackPLC:: @cindex\s-+PackPLC -//* PackStkO:: @cindex\s-+PackStkO -//* PackTSO:: @cindex\s-+PackTSO -//* PendingGABuffer:: @cindex\s-+PendingGABuffer -//* PrintPacket:: @cindex\s-+PrintPacket -//* QueueClosure:: @cindex\s-+QueueClosure -//* QueueEmpty:: @cindex\s-+QueueEmpty -//* RoomToPack:: @cindex\s-+RoomToPack -//* SetGAandCommonUp:: @cindex\s-+SetGAandCommonUp -//* UnpackGA:: @cindex\s-+UnpackGA -//* UnpackGraph:: @cindex\s-+UnpackGraph -//* UnpackOffset:: @cindex\s-+UnpackOffset -//* UnpackPLC:: @cindex\s-+UnpackPLC -//* doGlobalGC:: @cindex\s-+doGlobalGC -//* get_closure_info:: @cindex\s-+get_closure_info -//* InitPackBuffer:: @cindex\s-+initPackBuffer -//* isFixed:: @cindex\s-+isFixed -//* isOffset:: @cindex\s-+isOffset -//* offsetTable:: @cindex\s-+offsetTable -//@end index - diff --git a/rts/parallel/ParInit.c b/rts/parallel/ParInit.c deleted file mode 100644 index 22c9119c89..0000000000 --- a/rts/parallel/ParInit.c +++ /dev/null @@ -1,322 +0,0 @@ -/* -------------------------------------------------------------------------- - Time-stamp: <Wed Mar 21 2001 16:37:16 Stardate: [-30]6363.46 hwloidl> - - Initialising the parallel RTS - - An extension based on Kevin Hammond's GRAPH for PVM version - P. Trinder, January 17th 1995. - Adapted for the new RTS - P. Trinder, July 1997. - H-W. Loidl, November 1999. - - ------------------------------------------------------------------------ */ - -#ifdef PAR /* whole file */ - -//@menu -//* Includes:: -//* Global variables:: -//* Initialisation Routines:: -//@end menu - -//@node Includes, Global variables -//@subsection Includes - -/* Evidently not Posix */ -/* #include "PosixSource.h" */ - -#include <setjmp.h> -#include "Rts.h" -#include "RtsFlags.h" -#include "RtsUtils.h" -#include "ParallelRts.h" -#include "Sparks.h" -#include "LLC.h" -#include "HLC.h" - -//@node Global variables, Initialisation Routines, Includes -//@subsection Global variables - -/* Global conditions defined here. */ - -rtsBool IAmMainThread = rtsFalse; /* Set for the main thread */ - -/* Task identifiers for various interesting global tasks. */ - -GlobalTaskId IOTask = 0, /* The IO Task Id */ - SysManTask = 0, /* The System Manager Task Id */ - mytid = 0; /* This PE's Task Id */ - -rtsTime main_start_time; /* When the program started */ -rtsTime main_stop_time; /* When the program finished */ -jmp_buf exit_parallel_system; /* How to abort from the RTS */ - - -//rtsBool fishing = rtsFalse; /* We have no fish out in the stream */ -rtsTime last_fish_arrived_at = 0; /* Time of arrival of most recent fish*/ -nat outstandingFishes = 0; /* Number of active fishes */ - -//@cindex spark queue -/* GranSim: a globally visible array of spark queues */ -rtsSpark *pending_sparks_hd[SPARK_POOLS], /* ptr to start of a spark pool */ - *pending_sparks_tl[SPARK_POOLS], /* ptr to end of a spark pool */ - *pending_sparks_lim[SPARK_POOLS], - *pending_sparks_base[SPARK_POOLS]; - -//@cindex spark_limit -/* max number of sparks permitted on the PE; - see RtsFlags.ParFlags.maxLocalSparks */ -nat spark_limit[SPARK_POOLS]; - -//@cindex PendingFetches -/* A list of fetch reply messages not yet processed; this list is filled - by awaken_blocked_queue and processed by processFetches */ -StgBlockedFetch *PendingFetches = END_BF_QUEUE; - -//@cindex allPEs -GlobalTaskId *allPEs; - -//@cindex nPEs -nat nPEs = 0; - -//@cindex sparksIgnored -nat sparksIgnored = 0, sparksCreated = 0, - threadsIgnored = 0, threadsCreated = 0; - -//@cindex advisory_thread_count -nat advisory_thread_count = 0; - -globalAddr theGlobalFromGA; - -/* For flag handling see RtsFlags.h */ - -//@node Prototypes -//@subsection Prototypes - -/* Needed for FISH messages (initialisation of random number generator) */ -void srand48 (long); -time_t time (time_t *); - -//@node Initialisation Routines, , Global variables -//@subsection Initialisation Routines - -/* - par_exit defines how to terminate the program. If the exit code is - non-zero (i.e. an error has occurred), the PE should not halt until - outstanding error messages have been processed. Otherwise, messages - might be sent to non-existent Task Ids. The infinite loop will actually - terminate, since STG_Exception will call myexit\tr{(0)} when - it received a PP_FINISH from the system manager task. -*/ -//@cindex shutdownParallelSystem -void -shutdownParallelSystem(StgInt n) -{ - /* use the file specified via -S */ - FILE *sf = RtsFlags.GcFlags.statsFile; - - IF_PAR_DEBUG(verbose, - if (n==0) - belch("==== entered shutdownParallelSystem ..."); - else - belch("==== entered shutdownParallelSystem (ERROR %d)...", n); - ); - - stopPEComms(n); - -#if 0 - if (sf!=(FILE*)NULL) - fprintf(sf, "PE %x: %u sparks created, %u sparks Ignored, %u threads created, %u threads Ignored", - (W_) mytid, sparksCreated, sparksIgnored, - threadsCreated, threadsIgnored); -#endif - - ShutdownEachPEHook(); -} - -//@cindex initParallelSystem -void -initParallelSystem(void) -{ - /* Don't buffer standard channels... */ - setbuf(stdout,NULL); - setbuf(stderr,NULL); - - srand48(time(NULL) * getpid()); /* Initialise Random-number generator seed*/ - /* used to select target of FISH message*/ - if (!InitPackBuffer()) - barf("InitPackBuffer"); - - if (!initMoreBuffers()) - barf("initMoreBuffers"); - - if (!initSparkPools()) - barf("initSparkPools"); -} - -/* - * SynchroniseSystem synchronises the reduction task with the system - * manager, and initialises the Global address tables (LAGA & GALA) - */ - -//@cindex synchroniseSystem -void -synchroniseSystem(void) -{ - /* Only in debug mode? */ - fprintf(stderr, "==== Starting parallel execution on %d processors ...\n", nPEs); - - InitEachPEHook(); /* HWL: hook to be execed on each PE */ - - /* Initialize global address tables */ - initGAtables(); - - initParallelSystem(); - - startPEComms(); -} - -/* - Do the startup stuff (this is PVM specific!). - Determines global vars: mytid, IAmMainThread, SysManTask, nPEs - Called at the beginning of RtsStartup.startupHaskell -*/ -void -startupParallelSystem(char *argv[]) { - mytid = pvm_mytid(); /* Connect to PVM */ - - if (*argv[0] == '-') { /* Look to see whether we're the Main Thread */ - IAmMainThread = rtsTrue; - sscanf(argv[0],"-%0X",&SysManTask); /* extract SysMan task ID*/ - argv++; /* Strip off flag argument */ - } else { - SysManTask = pvm_parent(); - } - - IF_PAR_DEBUG(verbose, - fprintf(stderr, "==== [%x] %s PE located SysMan at %x\n", - mytid, IAmMainThread?"Main":"Remote", SysManTask)); - - nPEs = atoi(argv[1]); -} - -/* - Exception handler during startup. -*/ -void * -processUnexpectedMessageDuringStartup(rtsPacket p) { - OpCode opCode; - GlobalTaskId sender_id; - - getOpcodeAndSender(p, &opCode, &sender_id); - - switch(opCode) { - case PP_FISH: - bounceFish(); - break; -#if defined(DIST) - case PP_REVAL: - bounceReval(); - break; -#endif - case PP_FINISH: - stg_exit(EXIT_SUCCESS); - break; - default: - fprintf(stderr,"== Task %x: Unexpected OpCode %x (%s) from %x in startPEComms\n", - mytid, opCode, getOpName(opCode), sender_id); - } -} - -void -startPEComms(void){ - - startUpPE(); - allPEs = (GlobalTaskId *) stgMallocBytes(sizeof(GlobalTaskId) * MAX_PES, - "(PEs)"); - - /* Send our tid and IAmMainThread flag back to SysMan */ - sendOp1(PP_READY, SysManTask, (StgWord)IAmMainThread); - /* Wait until we get the PE-Id table from Sysman */ - waitForPEOp(PP_PETIDS, SysManTask, processUnexpectedMessageDuringStartup); - - IF_PAR_DEBUG(verbose, - belch("==-- startPEComms: methinks we just received a PP_PETIDS message")); - - /* Digest the PE table we received */ - processPEtids(); -} - -void -processPEtids(void) { - long newPE; - nat i, sentPEs, currentPEs; - - nPEs=0; - - currentPEs = nPEs; - - IF_PAR_DEBUG(verbose, - belch("==-- processPEtids: starting to iterate over a PVM buffer")); - /* ToDo: this has to go into LLComms !!! */ - GetArgs(&sentPEs,1); - - ASSERT(sentPEs > currentPEs); - ASSERT(sentPEs < MAX_PES); /* enforced by SysMan too*/ - - for (i = 0; i < sentPEs; i++) { - GetArgs(&newPE,1); - if (i<currentPEs) { - ASSERT(newPE == allPEs[i]); - } else { -#if defined(DIST) - // breaks with PAR && !DEBUG - IF_PAR_DEBUG(verbose, - fprintf(stderr, "[%x] registering %d'th %x\n", mytid, i, newPE)); - if(!looks_like_tid(newPE)) - barf("unacceptable taskID %x\n",newPE); -#endif - allPEs[i] = newPE; - nPEs++; - registerTask(newPE); - } - } - - IF_PAR_DEBUG(verbose, - /* debugging */ - belch("++++ [%x] PE table as I see it:", mytid); - for (i = 0; i < sentPEs; i++) { - belch("++++ allPEs[%d] = %x", i, allPEs[i]); - }); -} - -void -stopPEComms(StgInt n) { - if (n != 0) { - /* In case sysman doesn't know about us yet... - pvm_initsend(PvmDataDefault); - PutArgs(&IAmMainThread,1); - pvm_send(SysManTask, PP_READY); - */ - sendOp(PP_READY, SysManTask); - } - - sendOp2(PP_FINISH, SysManTask, n, n); - waitForPEOp(PP_FINISH, SysManTask, NULL); - fflush(gr_file); - shutDownPE(); -} - -#endif /* PAR -- whole file */ - -//@index -//* PendingFetches:: @cindex\s-+PendingFetches -//* SynchroniseSystem:: @cindex\s-+SynchroniseSystem -//* allPEs:: @cindex\s-+allPEs -//* initParallelSystem:: @cindex\s-+initParallelSystem -//* nPEs:: @cindex\s-+nPEs -//* par_exit:: @cindex\s-+par_exit -//* spark queue:: @cindex\s-+spark queue -//* sparksIgnored:: @cindex\s-+sparksIgnored -//@end index - diff --git a/rts/parallel/ParInit.h b/rts/parallel/ParInit.h deleted file mode 100644 index a22a50bae6..0000000000 --- a/rts/parallel/ParInit.h +++ /dev/null @@ -1,19 +0,0 @@ -/* ----------------------------------------------------------------------------- - * ParInit.h,1 - * - * Phil Trinder - * July 1998 - * - * External Parallel Initialisation Interface - * - * ---------------------------------------------------------------------------*/ - -#ifndef PARINIT_H -#define PARINIT_H - -extern void RunParallelSystem (P_); -extern void initParallelSystem(void); -extern void SynchroniseSystem(void); -extern void par_exit(I_); - -#endif /* PARINIT_H */ diff --git a/rts/parallel/ParTicky.c b/rts/parallel/ParTicky.c deleted file mode 100644 index 07e3ba9390..0000000000 --- a/rts/parallel/ParTicky.c +++ /dev/null @@ -1,450 +0,0 @@ -/* ------------------------------------------------------------------------- - * - * (c) Hans-Wolfgang Loidl, 2000- - * - * Parallel ticky profiling, monitoring basic RTS operations in GUM. - * Similar in structure to TICKY_TICKY profiling, but doesn't need a - * separate way of building GHC. - *-------------------------------------------------------------------------- */ - -#if defined(PAR) && defined(PAR_TICKY) - -#include "Rts.h" -#include "RtsFlags.h" -#include "RtsUtils.h" -//#include "StoragePriv.h" -//#include "MBlock.h" -//#include "Schedule.h" -#include "GC.h" -#include "Stats.h" -#include "ParTicky.h" // ToDo: move into Rts.h -#include "ParallelRts.h" - -#if defined(PAR) && defined(HAVE_GETRUSAGE) -#include <sys/resource.h> -#endif - -/* external data */ -extern double ElapsedTimeStart; - -extern StgWord64 GC_tot_alloc; -extern StgWord64 GC_tot_copied; - -extern W_ MaxResidency; /* in words; for stats only */ -extern W_ ResidencySamples; /* for stats only */ - -/* ngIplu' {Stats.c}vo' */ -#define BIG_STRING_LEN 512 - -/* ngIplu' {Ticky.c}vo' */ -#define INTAVG(a,b) ((b == 0) ? 0.0 : ((double) (a) / (double) (b))) -#define PC(a) (100.0 * a) - -#define AVG(thing) \ - StgDouble avg##thing = INTAVG(tot##thing,ctr##thing) - - -#if 0 -void -set_foo_time(double *x) { - *x = usertime(); -} - -double -get_foo_time(double x) { - fprintf(stderr, "get_foo_time: %7.2f (%7.5f,%7.5f) \n", - usertime()-x,usertime(),x); - return (usertime()-x); -} -#endif - -static double start_time_GA = 0.0; -static double start_mark = 0.0; -static double start_pack = 0.0; -static double start_unpack = 0.0; - -void -par_ticky_Par_start (void) { -# if !defined(HAVE_GETRUSAGE) || irix_HOST_OS || defined(_WIN32) - fprintf(stderr, "|| sorry don't have RUSAGE\n"); - return ; -# else - FILE *sf = RtsFlags.GcFlags.statsFile; - struct rusage t; - double utime, stime; - - if (RtsFlags.GcFlags.giveStats>1 && sf != NULL) { - getrusage(RUSAGE_SELF, &t); - - utime = t.ru_utime.tv_sec + 1e-6*t.ru_utime.tv_usec; - stime = t.ru_stime.tv_sec + 1e-6*t.ru_stime.tv_usec; - - fprintf(stderr, "|| user time: %5.2f; system time: %5.2f\n", - utime, stime); - fprintf(stderr, "|| max RSS: %ld; int SM size: %ld; int USM data size: %ld; int USS size: %ld\n", - t.ru_maxrss, t.ru_ixrss, t.ru_idrss, t.ru_isrss); - } -#endif -} - -#if 0 -FYI: - struct rusage - { - struct timeval ru_utime; /* user time used */ - struct timeval ru_stime; /* system time used */ - long ru_maxrss; /* maximum resident set size */ - long ru_ixrss; /* integral shared memory size */ - long ru_idrss; /* integral unshared data size */ - long ru_isrss; /* integral unshared stack size */ - long ru_minflt; /* page reclaims */ - long ru_majflt; /* page faults */ - long ru_nswap; /* swaps */ - long ru_inblock; /* block input operations */ - long ru_oublock; /* block output operations */ - long ru_msgsnd; /* messages sent */ - long ru_msgrcv; /* messages received */ - long ru_nsignals; /* signals received */ - long ru_nvcsw; /* voluntary context switches */ - long ru_nivcsw; /* involuntary context switches */ - }; -#endif - - -void -par_ticky_rebuildGAtables_start(void) { - // collect parallel global statistics (currently done together with GC stats) - if (RtsFlags.ParFlags.ParStats.Global && - RtsFlags.GcFlags.giveStats > NO_GC_STATS) { - //set_foo_time(&start_time_GA); - start_time_GA = usertime(); - } -} - -void -par_ticky_rebuildGAtables_end(nat n, nat size_GA) { - // collect parallel global statistics (currently done together with GC stats) - if (RtsFlags.ParFlags.ParStats.Global && - RtsFlags.GcFlags.giveStats > NO_GC_STATS) { - static double foo = 0.0; - foo = usertime() - start_time_GA; // get_foo_time(start_time_GA); - globalParStats.cnt_rebuild_GA++; - globalParStats.tot_rebuild_GA += n; - if ( n > globalParStats.res_rebuild_GA ) - globalParStats.res_rebuild_GA = n; - // fprintf(stderr, "rebuildGAtables: footime=%7.2f (%11.5f, %11.5f)\n", - // foo, usertime(), start_time_GA); - globalParStats.time_rebuild_GA += foo; - globalParStats.tot_size_GA += size_GA; - if ( size_GA > globalParStats.res_size_GA ) - globalParStats.res_size_GA = size_GA; - } - // fprintf(stderr, ">> n: %d; size: %d;; tot: %d; res: %d\n", - // n, size_GA, globalParStats.tot_size_GA, globalParStats.res_size_GA); -} - -void -par_ticky_markLocalGAs_start(void) { - // collect parallel global statistics (currently done together with GC stats) - if (RtsFlags.ParFlags.ParStats.Global && - RtsFlags.GcFlags.giveStats > NO_GC_STATS) { - start_time_GA = usertime(); - } -} - -void -par_ticky_markLocalGAs_end(nat n) { - // collect parallel global statistics (currently done together with GC stats) - if (RtsFlags.ParFlags.ParStats.Global && - RtsFlags.GcFlags.giveStats > NO_GC_STATS) { - globalParStats.cnt_mark_GA++; - globalParStats.tot_mark_GA += n; - if ( n > globalParStats.res_mark_GA ) - globalParStats.res_mark_GA = n; - globalParStats.time_mark_GA += usertime() - start_time_GA; - } -} - -void -par_ticky_markSparkQueue_start(void) { - // collect parallel global statistics (currently done together with GC stats) - if (RtsFlags.ParFlags.ParStats.Global && - RtsFlags.GcFlags.giveStats > NO_GC_STATS) { - start_mark=usertime(); - } -} - -void -par_ticky_markSparkQueue_end(nat n) { - // collect parallel global statistics (currently done together with GC stats) - if (RtsFlags.ParFlags.ParStats.Global && - RtsFlags.GcFlags.giveStats > NO_GC_STATS) { - globalParStats.time_sparks += usertime() - start_mark; - - globalParStats.tot_sparks_marked += n; - if ( n > globalParStats.res_sparks_marked ) - globalParStats.res_sparks_marked = n; - } -} - -void -par_ticky_PackNearbyGraph_start (void) { - if (RtsFlags.ParFlags.ParStats.Global && - RtsFlags.GcFlags.giveStats > NO_GC_STATS) { - start_pack=usertime(); - } -} - -void -par_ticky_PackNearbyGraph_end(nat n, nat thunks) { - // collect parallel global statistics (currently done together with GC stats) - if (RtsFlags.ParFlags.ParStats.Global && - RtsFlags.GcFlags.giveStats > NO_GC_STATS) { - globalParStats.time_pack += usertime() - start_pack; - - globalParStats.tot_packets++; - globalParStats.tot_packet_size += n; - if ( n > globalParStats.res_packet_size ) - globalParStats.res_packet_size = n; - globalParStats.tot_thunks += thunks; - if ( thunks > globalParStats.res_thunks ) - globalParStats.res_thunks = thunks; - } -} - -void -par_ticky_UnpackGraph_start (void) { - if (RtsFlags.ParFlags.ParStats.Global && - RtsFlags.GcFlags.giveStats > NO_GC_STATS) { - start_unpack=usertime(); - } -} - -void -par_ticky_UnpackGraph_end(nat n, nat thunks) { - // collect parallel global statistics (currently done together with GC stats) - if (RtsFlags.ParFlags.ParStats.Global && - RtsFlags.GcFlags.giveStats > NO_GC_STATS) { - globalParStats.time_unpack += usertime() - start_unpack; - - globalParStats.rec_packets++; - globalParStats.rec_packet_size += n; - /* - if ( n > globalParStats.res_packet_size ) - globalParStats.res_packet_size = n; - */ - globalParStats.rec_thunks += thunks; - /* - if ( thunks > globalParStats.res_thunks ) - globalParStats.res_thunks = thunks; - */ - } -} - -void -par_ticky_TP (void) { - StgSparkPool *pool; - nat tp_size, sp_size; // stats only - - // Global stats gathering - /* the spark pool for the current PE */ - pool = &(MainRegTable.rSparks); // generalise to cap = &MainRegTable - - // Global statistics: residency of thread and spark pool - if (RtsFlags.ParFlags.ParStats.Global && - RtsFlags.GcFlags.giveStats > NO_GC_STATS) { - tp_size = run_queue_len() + 1; // add the TSO just poped - // No: there may be many blocked threads being awoken at the same time - // ASSERT(tp_size <= RtsFlags.ParFlags.maxThreads); - globalParStats.tot_tp += tp_size; - globalParStats.emp_tp += (tp_size==0) ? 1 : 0; - globalParStats.cnt_tp++; - if ( tp_size > globalParStats.res_tp) - globalParStats.res_tp = tp_size; - // fprintf(stderr, "run_queue_len() = %d (max %d)\n", run_queue_len(), globalParStats.res_tp); - sp_size = spark_queue_len(pool); - //ASSERT(sp_size <= RtsFlags.ParFlags.maxLocalSparks); - globalParStats.tot_sp += sp_size; - globalParStats.emp_sp += (sp_size==0) ? 1 : 0; - globalParStats.cnt_sp++; - if ( sp_size > globalParStats.res_sp) - globalParStats.res_sp = sp_size; - // fprintf(stderr, "spark_queue_len(pool) = %d (max %d)\n", spark_queue_len(pool), globalParStats.res_sp); - } -} - -void -globalParStat_exit(void) -{ - FILE *sf = RtsFlags.GcFlags.statsFile; - double time, etime; - - /* print only if GC stats is enabled, too; i.e. -sstderr */ - if (!(RtsFlags.ParFlags.ParStats.Global && - RtsFlags.GcFlags.giveStats > NO_GC_STATS)) - return; - - time = usertime(); - etime = elapsedtime() - ElapsedTimeStart; - // fprintf(stderr, "foo=%7.2f\n", time); - - if (sf != NULL){ - char temp[BIG_STRING_LEN]; - - // GC_tot_alloc += alloc; - fprintf(sf,"\n"); - - fprintf(sf, "%11d threads created\n", - globalParStats.tot_threads_created); - /* - Would need to add a ++ to the par macro to use this - - fprintf(sf, "%11d sparks created\n", - globalParStats.tot_sparks_created); - fprintf(sf, "%11d sparks ignored\n", - globalParStats.tot_sparks_ignored); - */ - showStgWord64(globalParStats.res_tp, temp, rtsTrue/*commas*/); - fprintf(sf, "%11s thread pool residency", temp); - fprintf(sf, " (avg: %3.2f; %d times (%2.2f%%) of %d empty)\n", - (double)globalParStats.tot_tp/(double)globalParStats.cnt_tp, - globalParStats.emp_tp, - globalParStats.emp_tp*100.0/(double)globalParStats.cnt_tp, - globalParStats.cnt_tp); - showStgWord64(globalParStats.res_sp, temp, rtsTrue/*commas*/); - fprintf(sf, "%11s spark pool residency", temp); - - fprintf(sf, " (avg: %3.2f; %d times (%2.2f%%) of %d empty)\n", - (double)globalParStats.tot_sp/(double)globalParStats.cnt_sp, - globalParStats.emp_sp, - globalParStats.emp_sp*100.0/(double)globalParStats.cnt_sp, - globalParStats.cnt_sp); - //showStgWord64(globalParStats.tot_fishes, temp, rtsTrue/*commas*/); - fprintf(sf, "%11d messages sent (%d fish, %d fetch, %d resume, %d schedule", - globalParStats.tot_fish_mess+globalParStats.tot_fetch_mess+ - globalParStats.tot_resume_mess+globalParStats.tot_schedule_mess, - globalParStats.tot_fish_mess, globalParStats.tot_fetch_mess, - globalParStats.tot_resume_mess, globalParStats.tot_schedule_mess); -#if defined(DIST) - fprintf(sf, "%d revals", globalParStats.tot_reval_mess); -#endif - fprintf(sf,")\n"); - fprintf(sf, "%11d messages received (%d fish, %d fetch, %d resume, %d schedule", - globalParStats.rec_fish_mess+globalParStats.rec_fetch_mess+ - globalParStats.rec_resume_mess+globalParStats.rec_schedule_mess, - globalParStats.rec_fish_mess, globalParStats.rec_fetch_mess, - globalParStats.rec_resume_mess, globalParStats.rec_schedule_mess); -#if defined(DIST) - fprintf(sf, "%d revals", globalParStats.rec_reval_mess); -#endif - fprintf(sf,")\n\n"); - - showStgWord64(globalParStats.tot_size_GA*sizeof(W_), temp, rtsTrue/*commas*/); - fprintf(sf, "%11s bytes of global heap in total ", temp); - fprintf(sf, "(%5.2f%% of total allocated heap)\n", - globalParStats.tot_size_GA*sizeof(W_)*100.0/(double)GC_tot_alloc*sizeof(W_)); - showStgWord64(globalParStats.res_size_GA*sizeof(W_), temp, rtsTrue/*commas*/); - fprintf(sf, "%11s bytes global heap residency ", temp); - fprintf(sf, "(%5.2f%% of max heap residency)\n", - globalParStats.res_size_GA*sizeof(W_)*100.0/(double)MaxResidency*sizeof(W_)); - - //showStgWord64(globalParStats.res_mark_GA, temp, rtsTrue/*commas*/); - //fprintf(sf, "%11s GAs residency in GALA table ", temp); - // showStgWord64(globalParStats.tot_mark_GA, temp, rtsTrue/*commas*/); - //fprintf(sf, "(avg %5.2f; %d samples)\n", - // (double)globalParStats.tot_mark_GA/(double)globalParStats.cnt_mark_GA, - // globalParStats.cnt_mark_GA); - - showStgWord64(globalParStats.local_alloc_GA, temp, rtsTrue/*commas*/); - fprintf(sf, "%11s GAs locally allocated (calls to makeGlobal)\n", temp); - - showStgWord64(globalParStats.tot_rebuild_GA, temp, rtsTrue/*commas*/); - fprintf(sf, "%11s live GAs in total (after rebuilding tables)\n", temp); - showStgWord64(globalParStats.res_rebuild_GA, temp, rtsTrue/*commas*/); - fprintf(sf, "%11s GAs residency (after rebuilding tables) ", temp); - fprintf(sf, "(avg %5.2f; %d samples)\n", - (double)globalParStats.tot_rebuild_GA/(double)globalParStats.cnt_rebuild_GA, - globalParStats.cnt_rebuild_GA); - showStgWord64(globalParStats.res_free_GA, temp, rtsTrue/*commas*/); - fprintf(sf, "%11s residency of freeing GAs", temp); - fprintf(sf, " (avg %5.2f; %d samples)\n", - (double)globalParStats.tot_free_GA/(double)globalParStats.cnt_free_GA, - globalParStats.cnt_free_GA); - - fprintf(sf, "%11.2fs spent marking GAs (%7.2f%% of %7.2fs)\n", - globalParStats.time_mark_GA, - globalParStats.time_mark_GA*100./time, time); - fprintf(sf, "%11.2fs spent rebuilding GALA tables (%7.2f%% of %7.2fs; %7.2f%% of %7.2fs)\n", - globalParStats.time_rebuild_GA, - globalParStats.time_rebuild_GA*100./time, time, - globalParStats.time_rebuild_GA*100./etime, etime); - - showStgWord64(globalParStats.tot_sparks_marked, temp, rtsTrue/*commas*/); - fprintf(sf, "%11s sparks marked\t", temp); - showStgWord64(globalParStats.res_sparks_marked, temp, rtsTrue/*commas*/); - fprintf(sf, "%6s spark mark residency\n", temp); - fprintf(sf, "%11.2fs spent marking sparks (%7.2f%% of %7.2fs; %7.2f%% of %7.2fs elapsed)\n", - globalParStats.time_sparks, - globalParStats.time_sparks*100./time, time, - globalParStats.time_sparks*100./etime, etime); - - fprintf(sf,"\n"); - - showStgWord64(globalParStats.tot_packets, temp, rtsTrue/*commas*/); - fprintf(sf, "%11s packets sent\n", temp); - showStgWord64(globalParStats.tot_packet_size, temp, rtsTrue/*commas*/); - fprintf(sf, "%11s bytes of graph sent in total (max %d; avg %.2f)\n", - temp, globalParStats.res_packet_size, - (double)globalParStats.tot_packet_size/(double)globalParStats.tot_packets); - showStgWord64(globalParStats.tot_thunks, temp, rtsTrue/*commas*/); - fprintf(sf, "%11s thunks sent in total (max %d; avg %.2f)\n", - temp, globalParStats.res_thunks, - (double)globalParStats.tot_thunks/(double)globalParStats.tot_packets); - fprintf(sf, "%11.2fs spent packing graph structures (%7.2f%% of %7.2fs; %7.2f%% of %7.2fs elapsed)\n", - globalParStats.time_pack, - globalParStats.time_pack*100./time, time, - globalParStats.time_pack*100./etime, etime); - - showStgWord64(globalParStats.rec_packets, temp, rtsTrue/*commas*/); - fprintf(sf, "%11s packets received\n", temp); - showStgWord64(globalParStats.rec_packet_size, temp, rtsTrue/*commas*/); - fprintf(sf, "%11s bytes of graph received in total (max %d; avg %.2f)\n", - temp, globalParStats.rec_res_packet_size, - (double)globalParStats.rec_packet_size/(double)globalParStats.rec_packets); - showStgWord64(globalParStats.rec_thunks, temp, rtsTrue/*commas*/); - fprintf(sf, "%11s thunks received in total (max %d; avg %.2f)\n", - temp, globalParStats.rec_res_thunks, - (double)globalParStats.rec_thunks/(double)globalParStats.rec_packets); - fprintf(sf, "%11.2fs spent unpacking graph structures (%7.2f%% of %7.2fs; %7.2f%% of %7.2fs elapsed)\n", - globalParStats.time_unpack, - globalParStats.time_unpack*100./time, time, - globalParStats.time_unpack*100./etime, etime); - - fprintf(sf,"\n"); - - showStgWord64(globalParStats.tot_arrs, temp, rtsTrue/*commas*/); - fprintf(sf, "%11s bytearrays sent; ", temp); - showStgWord64(globalParStats.tot_arr_size, temp, rtsTrue/*commas*/); - fprintf(sf, " %s bytes in total (avg %.2f)\n", - temp, - (double)globalParStats.tot_arr_size/(double)globalParStats.tot_arrs); - - fprintf(sf,"\n"); - - fprintf(sf, "%11d yields, %d stack overflows, %d heap overflows\n", - globalParStats.tot_yields, globalParStats.tot_stackover, - globalParStats.tot_heapover); - - fprintf(sf,"\n"); - - //fprintf(stderr, "Printing this pathetic statistics took %7.2fs (start @ %7.2f)\n", - // usertime()-time, time); - - fflush(sf); - // Open filehandle needed by other stats printing fcts - // fclose(sf); - } -} - -#endif - diff --git a/rts/parallel/ParTicky.h b/rts/parallel/ParTicky.h deleted file mode 100644 index 1d6e7435c9..0000000000 --- a/rts/parallel/ParTicky.h +++ /dev/null @@ -1,60 +0,0 @@ -/* -------------------------------------------------------------------------- - * - * (c) Hans-Wolfgang Loidl, 2000- - * - * Header for ParTicky.c - * - * --------------------------------------------------------------------------*/ - -#if defined(PAR_TICKY) - -/* macros */ -#define PAR_TICKY_PAR_START() par_ticky_Par_start () -#define PAR_TICKY_PAR_END() globalParStat_exit () -#define PAR_TICKY_REBUILD_GA_TABLES_START() par_ticky_rebuildGAtables_start() -#define PAR_TICKY_REBUILD_GA_TABLES_END(n, size_GA) par_ticky_rebuildGAtables_end(n, size_GA) -#define PAR_TICKY_MARK_LOCAL_GAS_START() par_ticky_markLocalGAs_start() -#define PAR_TICKY_MARK_LOCAL_GAS_END(n) par_ticky_markLocalGAs_end(n) -#define PAR_TICKY_MARK_SPARK_QUEUE_START() par_ticky_markSparkQueue_start() -#define PAR_TICKY_MARK_SPARK_QUEUE_END(n) par_ticky_markSparkQueue_end(n) -#define PAR_TICKY_PACK_NEARBY_GRAPH_START() (par_ticky_PackNearbyGraph_start()) -#define PAR_TICKY_PACK_NEARBY_GRAPH_END(n, thunks) par_ticky_PackNearbyGraph_end(n, thunks) -#define PAR_TICKY_UNPACK_GRAPH_START() par_ticky_UnpackGraph_start() -#define PAR_TICKY_UNPACK_GRAPH_END(n,thunks) par_ticky_UnpackGraph_end(n,thunks) -#define PAR_TICKY_TP() par_ticky_TP() -#define PAR_TICKY_CNT_FREE_GA() stats_CntFreeGA() - -/* prototypes */ -extern void par_ticky_Par_start (void) ; -extern void par_ticky_rebuildGAtables_start(void) ; -extern void par_ticky_rebuildGAtables_end(nat n, nat size_GA) ; -extern void par_ticky_markLocalGAs_start(void) ; -extern void par_ticky_markLocalGAs_end(nat n) ; -extern void par_ticky_markSparkQueue_start(void) ; -extern void par_ticky_markSparkQueue_end(nat n) ; -extern void par_ticky_PackNearbyGraph_start (void) ; -extern void par_ticky_PackNearbyGraph_end(nat n, nat thunks) ; -extern void par_ticky_UnpackGraph_start (void) ; -extern void par_ticky_UnpackGraph_end(nat n, nat thunks) ; -extern void par_ticky_TP (void) ; -extern void globalParStat_exit(void); - -#else - -#define PAR_TICKY_PAR_START() -#define PAR_TICKY_PAR_END() -#define PAR_TICKY_REBUILD_GA_TABLES_START() -#define PAR_TICKY_REBUILD_GA_TABLES_END(n, size_GA) -#define PAR_TICKY_MARK_LOCAL_GAS_START() -#define PAR_TICKY_MARK_LOCAL_GAS_END(n) -#define PAR_TICKY_MARK_SPARK_QUEUE_START() -#define PAR_TICKY_MARK_SPARK_QUEUE_END(n) -#define PAR_TICKY_PACK_NEARBY_GRAPH_START () -#define PAR_TICKY_PACK_NEARBY_GRAPH_END(n, thunks) -#define PAR_TICKY_UNPACK_GRAPH_START () -#define PAR_TICKY_UNPACK_GRAPH_END(n, thunks) -#define PAR_TICKY_TP () -#define PAR_TICKY_CNT_FREE_GA() - -#endif - diff --git a/rts/parallel/ParTypes.h b/rts/parallel/ParTypes.h deleted file mode 100644 index 910a6f2d99..0000000000 --- a/rts/parallel/ParTypes.h +++ /dev/null @@ -1,38 +0,0 @@ -/* --------------------------------------------------------------------------- - * Time-stamp: <Tue Nov 09 1999 16:31:38 Stardate: [-30]3873.44 hwloidl> - * - * Runtime system types for GUM - * - * ------------------------------------------------------------------------- */ - -#ifndef PARTYPES_H -#define PARTYPES_H - -#ifdef PAR /* all of it */ - -// now in Parallel.h -//typedef struct hashtable HashTable; -//typedef struct hashlist HashList; - -/* Global addresses now live in Parallel.h (needed in Closures.h) */ -// gaddr - -// now in Parallel.h -/* (GA, LA) pairs -typedef struct gala { - globalAddr ga; - StgPtr la; - struct gala *next; - rtsBool preferred; -} rtsGaLa; -*/ - -#if defined(GRAN) -typedef unsigned long TIME; -typedef unsigned char Proc; -typedef unsigned char EVTTYPE; -#endif - -#endif /* PAR */ - -#endif /* ! PARTYPES_H */ diff --git a/rts/parallel/Parallel.c b/rts/parallel/Parallel.c deleted file mode 100644 index 55c22c752a..0000000000 --- a/rts/parallel/Parallel.c +++ /dev/null @@ -1,1140 +0,0 @@ -/* - Time-stamp: <Wed Mar 21 2001 16:42:40 Stardate: [-30]6363.48 hwloidl> - - Basic functions for use in either GranSim or GUM. -*/ - -#if defined(GRAN) || defined(PAR) /* whole file */ - -//@menu -//* Includes:: -//* Variables and constants:: -//* Writing to the log-file:: -//* Global statistics:: -//* Dumping routines:: -//@end menu -//*/ fool highlight - -//@node Includes, Variables and constants -//@subsection Includes - -#include "Rts.h" -#include "RtsFlags.h" -#include "RtsUtils.h" -#include "Storage.h" -#include "GranSimRts.h" -#include "ParallelRts.h" - -//@node Variables and constants, Writing to the log-file, Includes -//@subsection Variables and constants - -/* Where to write the log file */ -FILE *gr_file = NULL; -char gr_filename[STATS_FILENAME_MAXLEN]; - -#if defined(PAR) -/* Global statistics */ -GlobalParStats globalParStats; -#endif - -#if defined(PAR) -StgWord64 startTime = 0; -#endif - -#if defined(PAR) && !defined(DEBUG) -// HAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACCCCCCCCCKKKKKKKKKKKK -// Definitely the wrong place for info_type in !DEBUG (see Printer.c) -- HWL - -static char *closure_type_names[] = { - "INVALID_OBJECT", /* 0 */ - "CONSTR", /* 1 */ - "CONSTR_1_0", /* 2 */ - "CONSTR_0_1", /* 3 */ - "CONSTR_2_0", /* 4 */ - "CONSTR_1_1", /* 5 */ - "CONSTR_0_2", /* 6 */ - "CONSTR_INTLIKE", /* 7 */ - "CONSTR_CHARLIKE", /* 8 */ - "CONSTR_STATIC", /* 9 */ - "CONSTR_NOCAF_STATIC", /* 10 */ - "FUN", /* 11 */ - "FUN_1_0", /* 12 */ - "FUN_0_1", /* 13 */ - "FUN_2_0", /* 14 */ - "FUN_1_1", /* 15 */ - "FUN_0_2", /* 16 */ - "FUN_STATIC", /* 17 */ - "THUNK", /* 18 */ - "THUNK_1_0", /* 19 */ - "THUNK_0_1", /* 20 */ - "THUNK_2_0", /* 21 */ - "THUNK_1_1", /* 22 */ - "THUNK_0_2", /* 23 */ - "THUNK_STATIC", /* 24 */ - "THUNK_SELECTOR", /* 25 */ - "BCO", /* 26 */ - "AP_UPD", /* 27 */ - "PAP", /* 28 */ - "IND", /* 29 */ - "IND_OLDGEN", /* 30 */ - "IND_PERM", /* 31 */ - "IND_OLDGEN_PERM", /* 32 */ - "IND_STATIC", /* 33 */ - "CAF_UNENTERED", /* 34 */ - "CAF_ENTERED", /* 35 */ - "CAF_BLACKHOLE", /* 36 */ - "RET_BCO", /* 37 */ - "RET_SMALL", /* 38 */ - "RET_VEC_SMALL", /* 39 */ - "RET_BIG", /* 40 */ - "RET_VEC_BIG", /* 41 */ - "RET_DYN", /* 42 */ - "UPDATE_FRAME", /* 43 */ - "CATCH_FRAME", /* 44 */ - "STOP_FRAME", /* 45 */ - "SEQ_FRAME", /* 46 */ - "BLACKHOLE", /* 47 */ - "BLACKHOLE_BQ", /* 48 */ - "SE_BLACKHOLE", /* 49 */ - "SE_CAF_BLACKHOLE", /* 50 */ - "MVAR", /* 51 */ - "ARR_WORDS", /* 52 */ - "MUT_ARR_PTRS", /* 53 */ - "MUT_ARR_PTRS_FROZEN", /* 54 */ - "MUT_VAR", /* 55 */ - "WEAK", /* 56 */ - "FOREIGN", /* 57 */ - "STABLE_NAME", /* 58 */ - "TSO", /* 59 */ - "BLOCKED_FETCH", /* 60 */ - "FETCH_ME", /* 61 */ - "FETCH_ME_BQ", /* 62 */ - "RBH", /* 63 */ - "EVACUATED", /* 64 */ - "REMOTE_REF", /* 65 */ - "N_CLOSURE_TYPES" /* 66 */ -}; - -char * -info_type(StgClosure *closure){ - return closure_type_names[get_itbl(closure)->type]; -} - -char * -info_type_by_ip(StgInfoTable *ip){ - return closure_type_names[ip->type]; -} - -void -info_hdr_type(StgClosure *closure, char *res){ - strcpy(res,closure_type_names[get_itbl(closure)->type]); -} -#endif - -//@node Writing to the log-file, Global statistics, Variables and constants -//@subsection Writing to the log-file -/* - Writing to the log-file - - These routines dump event-based info to the main log-file. - The code for writing log files is shared between GranSim and GUM. -*/ - -/* - * If you're not using GNUC and you're on a 32-bit machine, you're - * probably out of luck here. However, since CONCURRENT currently - * requires GNUC, I'm not too worried about it. --JSM - */ - -//@cindex init_gr_simulation -#if defined(GRAN) -void -init_gr_simulation(rts_argc, rts_argv, prog_argc, prog_argv) -char *prog_argv[], *rts_argv[]; -int prog_argc, rts_argc; -{ - nat i; - char *extension = RtsFlags.GranFlags.GranSimStats.Binary ? "gb" : "gr"; - - if (RtsFlags.GranFlags.GranSimStats.Global) - init_gr_stats(); - - /* init global constants for costs of basic operations */ - gran_arith_cost = RtsFlags.GranFlags.Costs.arith_cost; - gran_branch_cost = RtsFlags.GranFlags.Costs.branch_cost; - gran_load_cost = RtsFlags.GranFlags.Costs.load_cost; - gran_store_cost = RtsFlags.GranFlags.Costs.store_cost; - gran_float_cost = RtsFlags.GranFlags.Costs.float_cost; - - if (RtsFlags.GranFlags.GranSimStats.Suppressed) - return; - - if (!RtsFlags.GranFlags.GranSimStats.Full) - return; - - sprintf(gr_filename, GR_FILENAME_FMT, prog_argv[0], extension); - - if ((gr_file = fopen(gr_filename, "w")) == NULL) { - barf("Can't open granularity simulation report file %s\n", - gr_filename); - } - - setbuf(gr_file, NULL); /* turn buffering off */ - - /* write header with program name, options and setup to gr_file */ - fputs("Granularity Simulation for ", gr_file); - for (i = 0; i < prog_argc; ++i) { - fputs(prog_argv[i], gr_file); - fputc(' ', gr_file); - } - - if (rts_argc > 0) { - fputs("+RTS ", gr_file); - - for (i = 0; i < rts_argc; ++i) { - fputs(rts_argv[i], gr_file); - fputc(' ', gr_file); - } - } - - fputs("\nStart time: ", gr_file); - fputs(time_str(), gr_file); /* defined in RtsUtils.c */ - fputc('\n', gr_file); - - fputs("\n\n--------------------\n\n", gr_file); - - fputs("General Parameters:\n\n", gr_file); - - if (RtsFlags.GranFlags.Light) - fprintf(gr_file, "GrAnSim-Light\nPEs infinite, %s Scheduler, %sMigrate Threads %s, %s\n", - RtsFlags.GranFlags.DoFairSchedule?"Fair":"Unfair", - RtsFlags.GranFlags.DoThreadMigration?"":"Don't ", - RtsFlags.GranFlags.DoThreadMigration && RtsFlags.GranFlags.DoStealThreadsFirst?" Before Sparks":"", - RtsFlags.GranFlags.DoAsyncFetch ? "Asynchronous Fetch" : - "Block on Fetch"); - else - fprintf(gr_file, "PEs %u, %s Scheduler, %sMigrate Threads %s, %s\n", - RtsFlags.GranFlags.proc,RtsFlags.GranFlags.DoFairSchedule?"Fair":"Unfair", - RtsFlags.GranFlags.DoThreadMigration?"":"Don't ", - RtsFlags.GranFlags.DoThreadMigration && RtsFlags.GranFlags.DoStealThreadsFirst?" Before Sparks":"", - RtsFlags.GranFlags.DoAsyncFetch ? "Asynchronous Fetch" : - "Block on Fetch"); - - if (RtsFlags.GranFlags.DoBulkFetching) - if (RtsFlags.GranFlags.ThunksToPack) - fprintf(gr_file, "Bulk Fetching: Fetch %d Thunks in Each Packet (Packet Size = %d closures)\n", - RtsFlags.GranFlags.ThunksToPack, - RtsFlags.GranFlags.packBufferSize); - else - fprintf(gr_file, "Bulk Fetching: Fetch as many closures as possible (Packet Size = %d closures)\n", - RtsFlags.GranFlags.packBufferSize); - else - fprintf(gr_file, "Incremental Fetching: Fetch Exactly One Closure in Each Packet\n"); - - fprintf(gr_file, "Fetch Strategy(%u):If outstanding fetches %s\n", - RtsFlags.GranFlags.FetchStrategy, - RtsFlags.GranFlags.FetchStrategy==0 ? - " block (block-on-fetch)": - RtsFlags.GranFlags.FetchStrategy==1 ? - "only run runnable threads": - RtsFlags.GranFlags.FetchStrategy==2 ? - "create threads only from local sparks": - RtsFlags.GranFlags.FetchStrategy==3 ? - "create threads from local or global sparks": - RtsFlags.GranFlags.FetchStrategy==4 ? - "create sparks and steal threads if necessary": - "unknown"); - - if (RtsFlags.GranFlags.DoPrioritySparking) - fprintf(gr_file, "Priority Sparking (i.e. keep sparks ordered by priority)\n"); - - if (RtsFlags.GranFlags.DoPriorityScheduling) - fprintf(gr_file, "Priority Scheduling (i.e. keep threads ordered by priority)\n"); - - fprintf(gr_file, "Thread Creation Time %u, Thread Queue Time %u\n", - RtsFlags.GranFlags.Costs.threadcreatetime, - RtsFlags.GranFlags.Costs.threadqueuetime); - fprintf(gr_file, "Thread DeSchedule Time %u, Thread Schedule Time %u\n", - RtsFlags.GranFlags.Costs.threaddescheduletime, - RtsFlags.GranFlags.Costs.threadscheduletime); - fprintf(gr_file, "Thread Context-Switch Time %u\n", - RtsFlags.GranFlags.Costs.threadcontextswitchtime); - fputs("\n\n--------------------\n\n", gr_file); - - fputs("Communication Metrics:\n\n", gr_file); - fprintf(gr_file, - "Latency %u (1st) %u (rest), Fetch %u, Notify %u (Global) %u (Local)\n", - RtsFlags.GranFlags.Costs.latency, - RtsFlags.GranFlags.Costs.additional_latency, - RtsFlags.GranFlags.Costs.fetchtime, - RtsFlags.GranFlags.Costs.gunblocktime, - RtsFlags.GranFlags.Costs.lunblocktime); - fprintf(gr_file, - "Message Creation %u (+ %u after send), Message Read %u\n", - RtsFlags.GranFlags.Costs.mpacktime, - RtsFlags.GranFlags.Costs.mtidytime, - RtsFlags.GranFlags.Costs.munpacktime); - fputs("\n\n--------------------\n\n", gr_file); - - fputs("Instruction Metrics:\n\n", gr_file); - fprintf(gr_file, "Arith %u, Branch %u, Load %u, Store %u, Float %u, Alloc %u\n", - RtsFlags.GranFlags.Costs.arith_cost, - RtsFlags.GranFlags.Costs.branch_cost, - RtsFlags.GranFlags.Costs.load_cost, - RtsFlags.GranFlags.Costs.store_cost, - RtsFlags.GranFlags.Costs.float_cost, - RtsFlags.GranFlags.Costs.heapalloc_cost); - fputs("\n\n++++++++++++++++++++\n\n", gr_file); - -# if 0 - /* binary log files are currently not supported */ - if (RtsFlags.GranFlags.GranSimStats.Binary) - grputw(sizeof(rtsTime)); -# endif - - return (0); -} - -#elif defined(PAR) - -void init_gr_stats (void); - -void -init_gr_simulation(rts_argc, rts_argv, prog_argc, prog_argv) -char *prog_argv[], *rts_argv[]; -int prog_argc, rts_argc; -{ - nat i; - char time_string[TIME_STR_LEN], node_str[NODE_STR_LEN]; - char *extension = RtsFlags.ParFlags.ParStats.Binary ? "gb" : "gr"; - - sprintf(gr_filename, GR_FILENAME_FMT_GUM, prog_argv[0], thisPE, extension); - - if (!RtsFlags.ParFlags.ParStats.Full) - return; - - if (RtsFlags.ParFlags.ParStats.Global) - init_gr_stats(); - - if ((gr_file = fopen(gr_filename, "w")) == NULL) - barf("Can't open activity report file %s\n", gr_filename); - - setbuf(gr_file, NULL); /* turn buffering off */ - - /* write header with program name, options and setup to gr_file */ - for (i = 0; i < prog_argc; ++i) { - fputs(prog_argv[i], gr_file); - fputc(' ', gr_file); - } - - if (rts_argc > 0) { - fputs("+RTS ", gr_file); - - for (i = 0; i < rts_argc; ++i) { - fputs(rts_argv[i], gr_file); - fputc(' ', gr_file); - } - } - fputc('\n', gr_file); - - /* record the absolute start time to allow synchronisation of log-files */ - fputs("Start-Time: ", gr_file); - fputs(time_str(), gr_file); - fputc('\n', gr_file); - - ASSERT(startTime==0); - // startTime = msTime(); - startTime = CURRENT_TIME; - showStgWord64(CURRENT_TIME, time_string, rtsFalse/*no commas!*/); - fprintf(gr_file, "PE %2u [%s]: TIME\n", thisPE, time_string); - -# if 0 - ngoq Dogh'q' vImuS - IF_PAR_DEBUG(verbose, - belch("== Start-time: %ld (%s)", - startTime, time_string)); - - if (startTime > LL(1000000000)) { - fprintf(gr_file, "PE %2u [%lu%lu]: TIME\n", thisPE, - (rtsTime) (startTime / LL(1000000000)), - (rtsTime) (startTime % LL(1000000000))); - } else { - fprintf(gr_file, "PE %2u [%lu]: TIME\n", thisPE, (TIME) startTime); - } - /* binary log files are currently not supported */ - if (RtsFlags.GranFlags.GranSimStats.Binary) - grputw(sizeof(rtsTime)); -# endif - - return; -} - -void -init_gr_stats (void) { - // memset(&globalParStats, '\0', sizeof(GlobalParStats)); - - globalParStats.tot_mark_GA = globalParStats.tot_rebuild_GA = globalParStats.tot_free_GA = globalParStats.res_mark_GA = globalParStats.res_rebuild_GA = globalParStats.res_free_GA = globalParStats.tot_size_GA = globalParStats.res_size_GA = globalParStats.tot_global = globalParStats.tot_local = 0; - globalParStats.cnt_mark_GA = globalParStats.cnt_rebuild_GA = globalParStats.cnt_free_GA = globalParStats.res_free_GA = globalParStats.local_alloc_GA = 0; - - globalParStats.time_mark_GA = 0.0; - globalParStats.time_rebuild_GA = 0.0; - globalParStats.time_sparks = 0.0; - globalParStats.time_pack = 0.0; - - globalParStats.res_sp = globalParStats.res_tp = globalParStats.tot_sp = globalParStats.tot_tp = globalParStats.cnt_sp = globalParStats.cnt_tp = globalParStats.emp_sp = globalParStats.emp_tp = 0; - globalParStats.tot_packets = globalParStats.tot_packet_size = globalParStats.tot_thunks = globalParStats.res_packet_size = globalParStats.res_thunks = globalParStats.rec_res_packet_size = globalParStats.rec_res_thunks = 0; - - globalParStats.tot_fish_mess = globalParStats.tot_fetch_mess = globalParStats.tot_resume_mess = globalParStats.tot_schedule_mess = 0; - globalParStats.rec_fish_mess = globalParStats.rec_resume_mess = globalParStats.rec_schedule_mess = 0; - globalParStats.rec_fetch_mess = 0; -#if defined(DIST) - globalParStats.tot_reval_mess = 0; - globalParStats.rec_reval_mess = 0; -#endif - - globalParStats.tot_threads_created = globalParStats.tot_sparks_created = globalParStats.tot_sparks_ignored = globalParStats.tot_sparks_marked = globalParStats.res_sparks_created = globalParStats.res_sparks_ignored = globalParStats.res_sparks_marked = 0; - globalParStats.tot_yields = globalParStats.tot_stackover = globalParStats.tot_heapover = 0; - - globalParStats.tot_arrs = globalParStats.tot_arr_size = 0; -} - -#endif /* PAR */ - -//@cindex end_gr_simulation -#if defined(GRAN) -void -end_gr_simulation(void) -{ - char time_string[TIME_STR_LEN]; - - showStgWord64(CURRENT_TIME, time_string, rtsFalse/*no commas!*/); - - if (RtsFlags.GranFlags.GranSimStats.Suppressed) - return; - - /* Print event stats */ - if (RtsFlags.GranFlags.GranSimStats.Global) { - nat i; - - fprintf(stderr,"Total yields: %d\n", - globalGranStats.tot_yields); - - fprintf(stderr,"Total number of threads created: %d ; per PE:\n", - globalGranStats.tot_threads_created); - for (i=0; i<RtsFlags.GranFlags.proc; i++) { - fprintf(stderr," PE %d: %d\t", - i, globalGranStats.threads_created_on_PE[i]); - if (i+1 % 4 == 0) fprintf(stderr,"\n"); - } - if (RtsFlags.GranFlags.proc+1 % 4 != 0) fprintf(stderr,"\n"); - fprintf(stderr,"Total number of threads migrated: %d\n", - globalGranStats.tot_TSOs_migrated); - - fprintf(stderr,"Total number of sparks created: %d ; per PE:\n", - globalGranStats.tot_sparks_created); - for (i=0; i<RtsFlags.GranFlags.proc; i++) { - fprintf(stderr," PE %d: %d\t", - i, globalGranStats.sparks_created_on_PE[i]); - if (i+1 % 4 == 0) fprintf(stderr,"\n"); - } - if (RtsFlags.GranFlags.proc+1 % 4 != 0) fprintf(stderr,"\n"); - - fprintf(stderr,"Event statistics (number of events: %d):\n", - globalGranStats.noOfEvents); - for (i=0; i<=MAX_EVENT; i++) { - fprintf(stderr," %s (%d): \t%d \t%f%%\t%f%%\n", - event_names[i],i,globalGranStats.event_counts[i], - (float)(100*globalGranStats.event_counts[i])/(float)(globalGranStats.noOfEvents), - (i==ContinueThread ? 0.0 : - (float)(100*(globalGranStats.event_counts[i])/(float)(globalGranStats.noOfEvents-globalGranStats.event_counts[ContinueThread])) )); - } - fprintf(stderr,"Randomized steals: %ld sparks, %ld threads \n \t(Sparks: #%u (avg ntimes=%f; avg fl=%f)\n\t(Threads: %ld)", - globalGranStats.rs_sp_count, - globalGranStats.rs_t_count, - globalGranStats.no_of_steals, - (float)globalGranStats.ntimes_total/(float)stg_max(globalGranStats.no_of_steals,1), - (float)globalGranStats.fl_total/(float)stg_max(globalGranStats.no_of_steals,1), - globalGranStats.no_of_migrates); - fprintf(stderr,"Moved sparks: %d Withered sparks: %d (%.2f %%)\n", - globalGranStats.tot_sparks, globalGranStats.withered_sparks, - ( globalGranStats.tot_sparks == 0 ? 0 : - (float)(100*globalGranStats.withered_sparks)/(float)(globalGranStats.tot_sparks)) ); - /* Print statistics about priority sparking */ - if (RtsFlags.GranFlags.DoPrioritySparking) { - fprintf(stderr,"About Priority Sparking:\n"); - fprintf(stderr," Total no. NewThreads: %d Avg. spark queue len: %.2f \n", globalGranStats.tot_sq_probes, (float)globalGranStats.tot_sq_len/(float)globalGranStats.tot_sq_probes); - } - /* Print statistics about priority sparking */ - if (RtsFlags.GranFlags.DoPriorityScheduling) { - fprintf(stderr,"About Priority Scheduling:\n"); - fprintf(stderr," Total no. of StartThreads: %d (non-end: %d) Avg. thread queue len: %.2f\n", - globalGranStats.tot_add_threads, globalGranStats.non_end_add_threads, - (float)globalGranStats.tot_tq_len/(float)globalGranStats.tot_add_threads); - } - /* Blocking queue statistics */ - if (1) { - fprintf(stderr,"Blocking queue statistcs:\n"); - fprintf(stderr," Total no. of FMBQs generated: %d\n", - globalGranStats.tot_FMBQs); - fprintf(stderr," Total no. of bqs awakened: %d\n", - globalGranStats.tot_awbq); - fprintf(stderr," Total length of all bqs: %d\tAvg length of bqs: %.2f\n", - globalGranStats.tot_bq_len, (float)globalGranStats.tot_bq_len/(float)globalGranStats.tot_awbq); - fprintf(stderr," Percentage of local TSOs in BQs: %.2f\n", - (float)globalGranStats.tot_bq_len*100.0/(float)globalGranStats.tot_bq_len); - fprintf(stderr," Total time spent processing BQs: %lx\n", - globalGranStats.tot_bq_processing_time); - } - - /* Fetch misses and thunk stealing */ - fprintf(stderr,"Number of fetch misses: %d\n", - globalGranStats.fetch_misses); - - /* Print packet statistics if GUMM fetching is turned on */ - if (RtsFlags.GranFlags.DoBulkFetching) { - fprintf(stderr,"Packet statistcs:\n"); - fprintf(stderr," Total no. of packets: %d Avg. packet size: %.2f \n", globalGranStats.tot_packets, (float)globalGranStats.tot_packet_size/(float)globalGranStats.tot_packets); - fprintf(stderr," Total no. of thunks: %d Avg. thunks/packet: %.2f \n", globalGranStats.tot_thunks, (float)globalGranStats.tot_thunks/(float)globalGranStats.tot_packets); - fprintf(stderr," Total no. of cuts: %d Avg. cuts/packet: %.2f\n", globalGranStats.tot_cuts, (float)globalGranStats.tot_cuts/(float)globalGranStats.tot_packets); - /* - if (closure_queue_overflows>0) - fprintf(stderr," Number of closure queue overflows: %u\n", - closure_queue_overflows); - */ - } - } /* RtsFlags.GranFlags.GranSimStats.Global */ - -# if defined(GRAN_COUNT) -# error "GRAN_COUNT not supported; should be parallel ticky profiling, really" - fprintf(stderr,"Update count statistics:\n"); - fprintf(stderr," Total number of updates: %u\n",nUPDs); - fprintf(stderr," Needed to awaken BQ: %u with avg BQ len of: %f\n", - nUPDs_BQ,(float)BQ_lens/(float)nUPDs_BQ); - fprintf(stderr," Number of PAPs: %u\n",nPAPs); -# endif - - fprintf(stderr, "Simulation finished after @ %s @ cycles. %d sparks created, %d sparks ignored. Check %s for details.\n", - time_string, sparksCreated, sparksIgnored, gr_filename); - - if (RtsFlags.GranFlags.GranSimStats.Full) - fclose(gr_file); -} - -#elif defined(PAR) - -/* - Under GUM we print only one line. -*/ -void -end_gr_simulation(void) -{ - char time_string[TIME_STR_LEN]; - - showStgWord64(CURRENT_TIME-startTime, time_string, rtsFalse/*no commas!*/); - - fprintf(stderr, "Computation finished after @ %s @ ms. %d sparks created, %d sparks ignored. Check %s for details.\n", - time_string, sparksCreated, sparksIgnored, gr_filename); - - if (RtsFlags.ParFlags.ParStats.Full) - fclose(gr_file); -} -#endif /* PAR */ - -//@node Global statistics, Dumping routines, Writing to the log-file -//@subsection Global statistics -/* - Called at the end of execution -*/ - -//@node Dumping routines, , Global statistics -//@subsection Dumping routines - -//@cindex DumpGranEvent -void -DumpGranEvent(name, tso) -GranEventType name; -StgTSO *tso; -{ - DumpRawGranEvent(CURRENT_PROC, (PEs)0, name, tso, &stg_END_TSO_QUEUE_closure, (StgInt)0, (StgInt)0); -} - -//@cindex DumpRawGranEvent -void -DumpRawGranEvent(proc, p, name, tso, node, sparkname, len) -PEs proc, p; /* proc ... where it happens; p ... where node lives */ -GranEventType name; -StgTSO *tso; -StgClosure *node; -StgInt sparkname, len; -{ -# if defined(GRAN) - DumpVeryRawGranEvent(TIME_ON_PROC(proc), - proc, p, name, tso, node, sparkname, len); -# elif defined(PAR) - DumpVeryRawGranEvent(CURRENT_TIME, - proc, p, name, tso, node, sparkname, len); -# endif -} - -//@cindex DumpVeryRawGranEvent -void -DumpVeryRawGranEvent(time, proc, p, name, tso, node, sparkname, len) -rtsTime time; -PEs proc, p; /* proc ... where it happens; p ... where node lives */ -GranEventType name; -StgTSO *tso; -StgClosure *node; -StgInt sparkname, len; -{ - FILE *output_file; // DEBUGGING ONLY !!!!!!!!!!!!!!!!!!!!!!!!!1 - StgWord id; - char time_string[TIME_STR_LEN], node_str[NODE_STR_LEN]; -# if defined(GRAN) - showStgWord64(time, - time_string, rtsFalse/*no commas!*/); -# elif defined(PAR) - showStgWord64(time, - time_string, rtsFalse/*no commas!*/); -# endif - output_file = gr_file; - -# if defined(GRAN) - - if (RtsFlags.GranFlags.GranSimStats.Full) - ASSERT(output_file!=NULL); - - if (RtsFlags.GranFlags.GranSimStats.Suppressed) - return; -# elif defined(PAR) - - if (RtsFlags.ParFlags.ParStats.Full) - ASSERT(output_file!=NULL); - - if (RtsFlags.ParFlags.ParStats.Suppressed) - return; - -# endif - - id = tso == NULL ? -1 : tso->id; - if (node==stgCast(StgClosure*,&stg_END_TSO_QUEUE_closure)) - strcpy(node_str,"________"); /* "END_TSO_QUEUE"); */ - else - sprintf(node_str,"0x%-6lx",node); - - if (name > GR_EVENT_MAX) - name = GR_EVENT_MAX; - - if (BINARY_STATS) - barf("binary log files not yet supported"); -#if 0 - /* ToDo: fix code for writing binary GrAnSim statistics */ - switch (name) { - case GR_START: - case GR_STARTQ: - grputw(name); - grputw(proc); - abort(); /* die please: a single word */ - /* doesn't represent long long times */ - grputw(TIME_ON_PROC(proc)); - grputw((StgWord)node); - break; - case GR_FETCH: - case GR_REPLY: - case GR_BLOCK: - grputw(name); - grputw(proc); - abort(); /* die please: a single word */ - /* doesn't represent long long times */ - grputw(TIME_ON_PROC(proc)); /* this line is bound to */ - grputw(id); /* do the wrong thing */ - break; - default: - grputw(name); - grputw(proc); - abort(); /* die please: a single word */ - /* doesn't represent long long times */ - grputw(TIME_ON_PROC(proc)); - grputw((StgWord)node); - } -#endif - else /* !BINARY_STATS */ - switch (name) { - case GR_START: - case GR_STARTQ: - fprintf(output_file,"PE %2u [%s]: %-9s\t%lx\t%s\t[SN %u]\t[sparks %u]\n", - proc,time_string,gran_event_names[name], - id,node_str,sparkname,len); - break; - case GR_FETCH: - case GR_REPLY: - case GR_BLOCK: - case GR_STOLEN: - case GR_STOLENQ: - case GR_STEALING: - fprintf(output_file, "PE %2u [%s]: %-9s\t%lx \t%s\t(from %2u)\n", - proc, time_string, gran_event_names[name], - id,node_str,p); - break; - case GR_RESUME: - case GR_RESUMEQ: - case GR_SCHEDULE: - case GR_DESCHEDULE: - fprintf(output_file,"PE %2u [%s]: %-9s\t%lx \n", - proc,time_string,gran_event_names[name],id); - break; - case GR_ALLOC: - fprintf(output_file,"PE %2u [%s]: %-9s\t%lx\t \tallocating %u words\n", - proc,time_string,gran_event_names[name],id,len); - break; - default: - fprintf(output_file,"PE %2u [%s]: %-9s\t%lx\t%s\t[sparks %u]\n", - proc,time_string,gran_event_names[name],id,node_str,len); - } -} - -//@cindex DumpGranInfo -void -DumpEndEvent(proc, tso, mandatory_thread) -PEs proc; -StgTSO *tso; -rtsBool mandatory_thread; -{ - FILE *output_file; // DEBUGGING ONLY !!!!!!!!!!!!!!!!!!!!!!!!!1 - char time_string[TIME_STR_LEN]; -# if defined(GRAN) - showStgWord64(TIME_ON_PROC(proc), - time_string, rtsFalse/*no commas!*/); -# elif defined(PAR) - showStgWord64(CURRENT_TIME, - time_string, rtsFalse/*no commas!*/); -# endif - - output_file = gr_file; - ASSERT(output_file!=NULL); -#if defined(GRAN) - if (RtsFlags.GranFlags.GranSimStats.Suppressed) - return; -#endif - - if (BINARY_STATS) { - barf("binary log files not yet supported"); -#if 0 - grputw(GR_END); - grputw(proc); - abort(); /* die please: a single word doesn't represent long long times */ - grputw(CURRENT_TIME); /* this line is bound to fail */ - grputw(tso->id); -#ifdef PAR - grputw(0); - grputw(0); - grputw(0); - grputw(0); - grputw(0); - grputw(0); - grputw(0); - grputw(0); - grputw(0); - grputw(0); - grputw(0); - grputw(0); -#else - grputw(tso->gran.sparkname); - grputw(tso->gran.startedat); - grputw(tso->gran.exported); - grputw(tso->gran.basicblocks); - grputw(tso->gran.allocs); - grputw(tso->gran.exectime); - grputw(tso->gran.blocktime); - grputw(tso->gran.blockcount); - grputw(tso->gran.fetchtime); - grputw(tso->gran.fetchcount); - grputw(tso->gran.localsparks); - grputw(tso->gran.globalsparks); -#endif - grputw(mandatory_thread); -#endif /* 0 */ - } else { - - /* - * NB: DumpGranEvent cannot be used because PE may be wrong - * (as well as the extra info) - */ - fprintf(output_file, "PE %2u [%s]: END %lx, SN %u, ST %lu, EXP %s, BB %u, HA %u, RT %u, BT %u (%u), FT %u (%u), LS %u, GS %u, MY %s\n" - ,proc - ,time_string - ,tso->id -#if defined(GRAN) - ,tso->gran.sparkname - ,tso->gran.startedat - ,((tso->gran.exported) ? 'T' : 'F') - ,tso->gran.basicblocks - ,tso->gran.allocs - ,tso->gran.exectime - ,tso->gran.blocktime - ,tso->gran.blockcount - ,tso->gran.fetchtime - ,tso->gran.fetchcount - ,tso->gran.localsparks - ,tso->gran.globalsparks -#elif defined(PAR) - ,tso->par.sparkname - ,tso->par.startedat - ,(tso->par.exported) ? "T" : "F" - ,tso->par.basicblocks - ,tso->par.allocs - ,tso->par.exectime - ,tso->par.blocktime - ,tso->par.blockcount - ,tso->par.fetchtime - ,tso->par.fetchcount - ,tso->par.localsparks - ,tso->par.globalsparks -#endif - ,(mandatory_thread ? "T" : "F") - ); - } -} - -//@cindex DumpTSO -void -DumpTSO(tso) -StgTSO *tso; -{ - FILE *output_file; // DEBUGGING ONLY !!!!!!!!!!!!!!!!!!!!!!!!!1 - - output_file = gr_file; - ASSERT(output_file!=NULL); - fprintf(stderr,"TSO 0x%lx, NAME 0x%lx, ID %u, LINK 0x%lx, TYPE %s\n" - ,tso -#if defined(GRAN) - ,tso->gran.sparkname -#elif defined(PAR) - ,tso->par.sparkname -#endif - ,tso->id - ,tso->link - ,/*tso->state==T_MAIN?"MAIN": - TSO_TYPE(tso)==T_FAIL?"FAIL": - TSO_TYPE(tso)==T_REQUIRED?"REQUIRED": - TSO_TYPE(tso)==T_ADVISORY?"ADVISORY": - */ - "???" - ); - - fprintf(output_file,"TSO %lx: SN %u, ST %u, GBL %c, BB %u, HA %u, RT %u, BT %u (%u), FT %u (%u) LS %u, GS %u\n" - ,tso->id -#if defined(GRAN) - ,tso->gran.sparkname - ,tso->gran.startedat - ,tso->gran.exported?'T':'F' - ,tso->gran.basicblocks - ,tso->gran.allocs - ,tso->gran.exectime - ,tso->gran.blocktime - ,tso->gran.blockcount - ,tso->gran.fetchtime - ,tso->gran.fetchcount - ,tso->gran.localsparks - ,tso->gran.globalsparks -#elif defined(PAR) - ,tso->par.sparkname - ,tso->par.startedat - ,tso->par.exported?'T':'F' - ,tso->par.basicblocks - ,tso->par.allocs - ,tso->par.exectime - ,tso->par.blocktime - ,tso->par.blockcount - ,tso->par.fetchtime - ,tso->par.fetchcount - ,tso->par.localsparks - ,tso->par.globalsparks -#endif - ); -} - -#if 0 -/* - ToDo: fix binary output of log files, and support new log file format. -*/ -/* - Output a terminate event and an 8-byte time. -*/ - -//@cindex grterminate -void -grterminate(v) -rtsTime v; -{ - if (!BINARY_STATS) - barf("grterminate: binary statistics not enabled\n"); - -# if defined(GRAN) - if (RtsFlags.GranFlags.GranSimStats.Suppressed) - return; -# endif - - DumpGranEvent(GR_TERMINATE, stgCast(StgTSO*,&stg_END_TSO_QUEUE_closure)); - - if (sizeof(rtsTime) == 4) { - putc('\0', gr_file); - putc('\0', gr_file); - putc('\0', gr_file); - putc('\0', gr_file); - } else { - putc(v >> 56l, gr_file); - putc((v >> 48l) & 0xffl, gr_file); - putc((v >> 40l) & 0xffl, gr_file); - putc((v >> 32l) & 0xffl, gr_file); - } - putc((v >> 24l) & 0xffl, gr_file); - putc((v >> 16l) & 0xffl, gr_file); - putc((v >> 8l) & 0xffl, gr_file); - putc(v & 0xffl, gr_file); -} - -/* - Length-coded output: first 3 bits contain length coding - - 00x 1 byte - 01x 2 bytes - 10x 4 bytes - 110 8 bytes - 111 5 or 9 bytes -*/ - -//@cindex grputw -void -grputw(v) -rtsTime v; -{ - if (!BINARY_STATS) - barf("grputw: binary statistics not enabled\n"); - -# if defined(GRAN) - if (RtsFlags.GranFlags.GranSimStats.Suppressed) - return; -# endif - - if (v <= 0x3fl) { /* length v = 1 byte */ - fputc(v & 0x3f, gr_file); - } else if (v <= 0x3fffl) { /* length v = 2 byte */ - fputc((v >> 8l) | 0x40l, gr_file); - fputc(v & 0xffl, gr_file); - } else if (v <= 0x3fffffffl) { /* length v = 4 byte */ - fputc((v >> 24l) | 0x80l, gr_file); - fputc((v >> 16l) & 0xffl, gr_file); - fputc((v >> 8l) & 0xffl, gr_file); - fputc(v & 0xffl, gr_file); - } else if (sizeof(TIME) == 4) { - fputc(0x70, gr_file); - fputc((v >> 24l) & 0xffl, gr_file); - fputc((v >> 16l) & 0xffl, gr_file); - fputc((v >> 8l) & 0xffl, gr_file); - fputc(v & 0xffl, gr_file); - } else { - if (v <= 0x3fffffffffffffl) - putc((v >> 56l) | 0x60l, gr_file); - else { - putc(0x70, gr_file); - putc((v >> 56l) & 0xffl, gr_file); - } - - putc((v >> 48l) & 0xffl, gr_file); - putc((v >> 40l) & 0xffl, gr_file); - putc((v >> 32l) & 0xffl, gr_file); - putc((v >> 24l) & 0xffl, gr_file); - putc((v >> 16l) & 0xffl, gr_file); - putc((v >> 8l) & 0xffl, gr_file); - putc(v & 0xffl, gr_file); - } -} -#endif /* 0 */ - -/* - extracting specific info out of a closure; used in packing (GranSim, GUM) -*/ -//@cindex get_closure_info -StgInfoTable* -get_closure_info(StgClosure* node, nat *size, nat *ptrs, nat *nonptrs, - nat *vhs, char *info_hdr_ty) -{ - StgInfoTable *info; - - ASSERT(LOOKS_LIKE_COOL_CLOSURE(node)); - info = get_itbl(node); - /* the switch shouldn't be necessary, really; just use default case */ - switch (info->type) { - case RBH: - { - StgInfoTable *rip = REVERT_INFOPTR(info); // closure to revert to - *size = sizeW_fromITBL(rip); - *ptrs = (nat) (rip->layout.payload.ptrs); - *nonptrs = (nat) (rip->layout.payload.nptrs); - *vhs = *size - *ptrs - *nonptrs - sizeofW(StgHeader); -#if 0 /* DEBUG */ - info_hdr_type(node, info_hdr_ty); -#else - strcpy(info_hdr_ty, "RBH"); -#endif - return rip; // NB: we return the reverted info ptr for a RBH!!!!!! - } - -#if defined(PAR) - /* Closures specific to GUM */ - case FETCH_ME: - *size = sizeofW(StgFetchMe); - *ptrs = (nat)0; - *nonptrs = (nat)0; - *vhs = *size - *ptrs - *nonptrs - sizeofW(StgHeader); -#if 0 /* DEBUG */ - info_hdr_type(node, info_hdr_ty); -#else - strcpy(info_hdr_ty, "FETCH_ME"); -#endif - return info; - -#ifdef DIST - case REMOTE_REF: //same as for FETCH_ME... - *size = sizeofW(StgFetchMe); - *ptrs = (nat)0; - *nonptrs = (nat)0; - *vhs = *size - *ptrs - *nonptrs - sizeofW(StgHeader); -#if 0 /* DEBUG */ - info_hdr_type(node, info_hdr_ty); -#else - strcpy(info_hdr_ty, "REMOTE_REF"); -#endif - return info; -#endif /* DIST */ - - case FETCH_ME_BQ: - *size = sizeofW(StgFetchMeBlockingQueue); - *ptrs = (nat)0; - *nonptrs = (nat)0; - *vhs = *size - *ptrs - *nonptrs - sizeofW(StgHeader); -#if 0 /* DEBUG */ - info_hdr_type(node, info_hdr_ty); -#else - strcpy(info_hdr_ty, "FETCH_ME_BQ"); -#endif - return info; - - case BLOCKED_FETCH: - *size = sizeofW(StgBlockedFetch); - *ptrs = (nat)0; - *nonptrs = (nat)0; - *vhs = *size - *ptrs - *nonptrs - sizeofW(StgHeader); -#if 0 /* DEBUG */ - info_hdr_type(node, info_hdr_ty); -#else - strcpy(info_hdr_ty, "BLOCKED_FETCH"); -#endif - return info; -#endif /* PAR */ - - /* these magic constants are outrageous!! why does the ITBL lie about it? */ - case THUNK_SELECTOR: - *size = THUNK_SELECTOR_sizeW(); - *ptrs = 1; - *nonptrs = MIN_UPD_SIZE-*ptrs; // weird - *vhs = *size - *ptrs - *nonptrs - sizeofW(StgHeader); - return info; - - case ARR_WORDS: - /* ToDo: check whether this can be merged with the default case */ - *size = arr_words_sizeW((StgArrWords *)node); - *ptrs = 0; - *nonptrs = arr_words_words(((StgArrWords *)node)); - *vhs = *size - *ptrs - *nonptrs - sizeofW(StgHeader); - return info; - - case PAP: - /* ToDo: check whether this can be merged with the default case */ - *size = pap_sizeW((StgPAP *)node); - *ptrs = 0; - *nonptrs = 0; - *vhs = *size - *ptrs - *nonptrs - sizeofW(StgHeader); - return info; - - case AP_UPD: - /* ToDo: check whether this can be merged with the default case */ - *size = AP_sizeW(((StgAP_UPD *)node)->n_args); - *ptrs = 0; - *nonptrs = 0; - *vhs = *size - *ptrs - *nonptrs - sizeofW(StgHeader); - return info; - - default: - *size = sizeW_fromITBL(info); - *ptrs = (nat) (info->layout.payload.ptrs); - *nonptrs = (nat) (info->layout.payload.nptrs); - *vhs = *size - *ptrs - *nonptrs - sizeofW(StgHeader); -#if 0 /* DEBUG */ - info_hdr_type(node, info_hdr_ty); -#else - strcpy(info_hdr_ty, "UNKNOWN"); -#endif - return info; - } -} - -//@cindex IS_BLACK_HOLE -rtsBool -IS_BLACK_HOLE(StgClosure* node) -{ - // StgInfoTable *info; - ASSERT(LOOKS_LIKE_COOL_CLOSURE(node)); - switch (get_itbl(node)->type) { - case BLACKHOLE: - case BLACKHOLE_BQ: - case RBH: - case FETCH_ME: - case FETCH_ME_BQ: - return rtsTrue; - default: - return rtsFalse; - } -//return ((info->type == BLACKHOLE || info->type == RBH) ? rtsTrue : rtsFalse); -} - -//@cindex IS_INDIRECTION -StgClosure * -IS_INDIRECTION(StgClosure* node) -{ - StgInfoTable *info; - ASSERT(LOOKS_LIKE_COOL_CLOSURE(node)); - info = get_itbl(node); - switch (info->type) { - case IND: - case IND_OLDGEN: - case IND_PERM: - case IND_OLDGEN_PERM: - case IND_STATIC: - /* relies on indirectee being at same place for all these closure types */ - return (((StgInd*)node) -> indirectee); -#if 0 - case EVACUATED: // counting as ind to use in GC routines, too - // could use the same code as above (evacuee is at same pos as indirectee) - return (((StgEvacuated *)node) -> evacuee); -#endif - default: - return NULL; - } -} - -//@cindex unwindInd -StgClosure * -UNWIND_IND (StgClosure *closure) -{ - StgClosure *next; - - while ((next = IS_INDIRECTION((StgClosure *)closure)) != NULL) - closure = next; - - ASSERT(next==(StgClosure *)NULL); - ASSERT(LOOKS_LIKE_COOL_CLOSURE(closure)); - return closure; -} - -#endif /* GRAN || PAR whole file */ diff --git a/rts/parallel/ParallelDebug.c b/rts/parallel/ParallelDebug.c deleted file mode 100644 index 5616a9a945..0000000000 --- a/rts/parallel/ParallelDebug.c +++ /dev/null @@ -1,1955 +0,0 @@ -/* - Time-stamp: <Sun Mar 18 2001 19:32:56 Stardate: [-30]6349.07 hwloidl> - - Various debugging routines for GranSim and GUM -*/ - -#if defined(DEBUG) && (defined(GRAN) || defined(PAR)) /* whole file */ - -//@node Debugging routines for GranSim and GUM, , , -//@section Debugging routines for GranSim and GUM - -//@menu -//* Includes:: -//* Constants and Variables:: -//* Closures:: -//* Threads:: -//* Events:: -//* Sparks:: -//* Processors:: -//* Shortcuts:: -//* Printing info type:: -//* Printing Pack:et Contents:: -//* End of File:: -//@end menu -//*/ - -//@node Includes, Prototypes, Debugging routines for GranSim and GUM, Debugging routines for GranSim and GUM -//@subsection Includes - -#include "Rts.h" -#include "RtsFlags.h" -#include "GranSimRts.h" -#include "ParallelRts.h" -#include "StgMiscClosures.h" -#include "Printer.h" -# if defined(DEBUG) -# include "Hash.h" -# include "Storage.h" -# include "ParallelDebug.h" -# endif - -//@node Prototypes, Constants and Variables, Includes, Debugging routines for GranSim and GUM -//@subsection Prototypes -/* -rtsBool isOffset(globalAddr *ga); -rtsBool isFixed(globalAddr *ga); -*/ -//@node Constants and Variables, Closures, Prototypes, Debugging routines for GranSim and GUM -//@subsection Constants and Variables - -static HashTable *tmpClosureTable; // used in GraphFingerPrint and PrintGraph - -#if defined(PAR) -static char finger_print_char[] = { - '/', /* INVALID_OBJECT 0 */ - 'C', /* CONSTR 1 */ - 'C', /* CONSTR_1_0 2 */ - 'C', /* CONSTR_0_1 3 */ - 'C', /* CONSTR_2_0 4 */ - 'C', /* CONSTR_1_1 5 */ - 'C', /* CONSTR_0_2 6 */ - 'I', /* CONSTR_INTLIKE 7 */ - 'I', /* CONSTR_CHARLIKE 8 */ - 'S', /* CONSTR_STATIC 9 */ - 'S', /* CONSTR_NOCAF_STATIC 10 */ - 'F', /* FUN 11 */ - 'F', /* FUN_1_0 12 */ - 'F', /* FUN_0_1 13 */ - 'F', /* FUN_2_0 14 */ - 'F', /* FUN_1_1 15 */ - 'F', /* FUN_0_2 16 */ - 'S', /* FUN_STATIC 17 */ - 'T', /* THUNK 18 */ - 'T', /* THUNK_1_0 19 */ - 'T', /* THUNK_0_1 20 */ - 'T', /* THUNK_2_0 21 */ - 'T', /* THUNK_1_1 22 */ - 'T', /* THUNK_0_2 23 */ - 'S', /* THUNK_STATIC 24 */ - 'E', /* THUNK_SELECTOR 25 */ - 'b', /* BCO 26 */ - 'p', /* AP_UPD 27 */ - 'p', /* PAP 28 */ - '_', /* IND 29 */ - '_', /* IND_OLDGEN 30 */ - '_', /* IND_PERM 31 */ - '_', /* IND_OLDGEN_PERM 32 */ - '_', /* IND_STATIC 33 */ - '?', /* ***unused*** 34 */ - '?', /* ***unused*** 35 */ - '^', /* RET_BCO 36 */ - '^', /* RET_SMALL 37 */ - '^', /* RET_VEC_SMALL 38 */ - '^', /* RET_BIG 39 */ - '^', /* RET_VEC_BIG 40 */ - '^', /* RET_DYN 41 */ - '~', /* UPDATE_FRAME 42 */ - '~', /* CATCH_FRAME 43 */ - '~', /* STOP_FRAME 44 */ - '~', /* SEQ_FRAME 45 */ - 'o', /* CAF_BLACKHOLE 46 */ - 'o', /* BLACKHOLE 47 */ - 'o', /* BLACKHOLE_BQ 48 */ - 'o', /* SE_BLACKHOLE 49 */ - 'o', /* SE_CAF_BLACKHOLE 50 */ - 'm', /* MVAR 51 */ - 'a', /* ARR_WORDS 52 */ - 'a', /* MUT_ARR_PTRS 53 */ - 'a', /* MUT_ARR_PTRS_FROZEN 54 */ - 'q', /* MUT_VAR 55 */ - 'w', /* WEAK 56 */ - 'f', /* FOREIGN 57 */ - 's', /* STABLE_NAME 58 */ - '@', /* TSO 59 */ - '#', /* BLOCKED_FETCH 60 */ - '>', /* FETCH_ME 61 */ - '>', /* FETCH_ME_BQ 62 */ - '$', /* RBH 63 */ - 'v', /* EVACUATED 64 */ - '>' /* REMOTE_REF 65 */ - /* ASSERT(there are N_CLOSURE_TYPES (==66) in this arrary) */ -}; -#endif /* PAR */ - -#if defined(GRAN) && defined(GRAN_CHECK) -//@node Closures, Threads, Constants and Variables, Debugging routines for GranSim and GUM -//@subsection Closures - -void -G_PRINT_NODE(node) -StgClosure* node; -{ - StgInfoTable *info_ptr; - StgTSO* bqe; - nat size = 0, ptrs = 0, nonptrs = 0, i, vhs = 0; - char info_hdr_ty[80], info_ty[80]; - - if (node==NULL) { - fprintf(stderr,"NULL\n"); - return; - } else if (node==END_TSO_QUEUE) { - fprintf(stderr,"END_TSO_QUEUE\n"); - return; - } - /* size_and_ptrs(node,&size,&ptrs); */ - info_ptr = get_closure_info(node, &size, &ptrs, &nonptrs, &vhs, info_hdr_ty); - - /* vhs = var_hdr_size(node); */ - display_info_type(info_ptr,info_ty); - - fprintf(stderr,"Node: 0x%lx", node); - -#if defined(PAR) - fprintf(stderr," [GA: 0x%lx]",GA(node)); -#endif - -#if defined(USE_COST_CENTRES) - fprintf(stderr," [CC: 0x%lx]",CC_HDR(node)); -#endif - -#if defined(GRAN) - fprintf(stderr," [Bitmask: 0%lo]",PROCS(node)); -#endif - - if (info_ptr->type==TSO) - fprintf(stderr," TSO: 0x%lx (%x) IP: 0x%lx (%s), type %s \n ", - (StgTSO*)node, ((StgTSO*)node)->id, info_ptr, info_hdr_ty, info_ty); - else - fprintf(stderr," IP: 0x%lx (%s), type %s \n VHS: %d, size: %ld, ptrs:%ld, nonptrs: %ld\n ", - info_ptr,info_hdr_ty,info_ty,vhs,size,ptrs,nonptrs); - - /* For now, we ignore the variable header */ - - fprintf(stderr," Ptrs: "); - for(i=0; i < ptrs; ++i) - { - if ( (i+1) % 6 == 0) - fprintf(stderr,"\n "); - fprintf(stderr," 0x%lx[P]",node->payload[i]); - }; - - fprintf(stderr," Data: "); - for(i=0; i < nonptrs; ++i) - { - if( (i+1) % 6 == 0) - fprintf(stderr,"\n "); - fprintf(stderr," %lu[D]",node->payload[ptrs+i]); - } - fprintf(stderr, "\n"); - - - switch (info_ptr->type) - { - case TSO: - fprintf(stderr,"\n TSO_LINK: %#lx", - ((StgTSO*)node)->link); - break; - - case BLACKHOLE: - case RBH: - bqe = ((StgBlockingQueue*)node)->blocking_queue; - fprintf(stderr," BQ of %#lx: ", node); - G_PRINT_BQ(bqe); - break; - case FETCH_ME: - case FETCH_ME_BQ: - printf("Panic: found FETCH_ME or FETCH_ME_BQ Infotable in GrAnSim system.\n"); - break; - default: - /* do nothing */ - } -} - -void -G_PPN(node) /* Extracted from PrintPacket in Pack.lc */ -StgClosure* node; -{ - StgInfoTable *info ; - nat size = 0, ptrs = 0, nonptrs = 0, i, vhs = 0, locn = 0; - char info_type[80]; - - /* size_and_ptrs(node,&size,&ptrs); */ - info = get_closure_info(node, &size, &ptrs, &nonptrs, &vhs, info_type); - - if (info->type == FETCH_ME || info->type == FETCH_ME_BQ || - info->type == BLACKHOLE || info->type == RBH ) - size = ptrs = nonptrs = vhs = 0; - - if (closure_THUNK(node)) { - if (!closure_UNPOINTED(node)) - fputs("SHARED ", stderr); - else - fputs("UNSHARED ", stderr); - } - if (info->type==BLACKHOLE) { - fputs("BLACK HOLE\n", stderr); - } else { - /* Fixed header */ - fprintf(stderr, "(%s) FH [%#lx", info_type, node[locn++]); - for (i = 1; i < _HS; i++) - fprintf(stderr, " %#lx", node[locn++]); - - /* Variable header */ - if (vhs > 0) { - fprintf(stderr, "] VH [%#lx", node->payload[0]); - - for (i = 1; i < vhs; i++) - fprintf(stderr, " %#lx", node->payload[i]); - } - - fprintf(stderr, "] PTRS %u", ptrs); - - /* Non-pointers */ - if (nonptrs > 0) { - fprintf(stderr, " NPTRS [%#lx", node->payload[ptrs]); - - for (i = 1; i < nonptrs; i++) - fprintf(stderr, " %#lx", node->payload[ptrs+i]); - - putc(']', stderr); - } - putc('\n', stderr); - } - -} - -#if 0 -// ToDo: fix this!! -- HWL -void -G_INFO_TABLE(node) -StgClosure *node; -{ - StgInfoTable *info_ptr; - nat size = 0, ptrs = 0, nonptrs = 0, vhs = 0; - char info_type[80], hdr_type[80]; - - info_hdr_type(info_ptr, hdr_type); - - // get_itbl(node); - info_ptr = get_closure_info(node, &size, &ptrs, &nonptrs, &vhs, info_type); - fprintf(stderr,"%s Info Ptr @0x%lx; Entry: 0x%lx; Size: %lu; Ptrs: %lu\n\n", - info_type,info_ptr,(W_) ENTRY_CODE(info_ptr), - size, ptrs); - // INFO_SIZE(info_ptr),INFO_NoPTRS(info_ptr)); - - if (closure_THUNK(node) && !closure_UNPOINTED(node) ) { - fprintf(stderr," RBH InfoPtr: %#lx\n", - RBH_INFOPTR(info_ptr)); - } - -#if defined(PAR) - fprintf(stderr,"Enter Flush Entry: 0x%lx;\tExit Flush Entry: 0x%lx\n",INFO_FLUSHENT(info_ptr),INFO_FLUSH(info_ptr)); -#endif - -#if defined(USE_COST_CENTRES) - fprintf(stderr,"Cost Centre (?): 0x%lx\n",INFO_CAT(info_ptr)); -#endif - -#if defined(_INFO_COPYING) - fprintf(stderr,"Evacuate Entry: 0x%lx;\tScavenge Entry: 0x%lx\n", - INFO_EVAC_2S(info_ptr),INFO_SCAV_2S(info_ptr)); -#endif - -#if defined(_INFO_COMPACTING) - fprintf(stderr,"Scan Link: 0x%lx;\tScan Move: 0x%lx\n", - (W_) INFO_SCAN_LINK_1S(info_ptr), (W_) INFO_SCAN_MOVE_1S(info_ptr)); - fprintf(stderr,"Mark: 0x%lx;\tMarked: 0x%lx;\t", - (W_) INFO_MARK_1S(info_ptr), (W_) INFO_MARKED_1S(info_ptr)); -#if 0 /* avoid INFO_TYPE */ - if(BASE_INFO_TYPE(info_ptr)==INFO_SPEC_TYPE) - fprintf(stderr,"plus specialised code\n"); - else - fprintf(stderr,"Marking: 0x%lx\n",(W_) INFO_MARKING_1S(info_ptr)); -#endif /* 0 */ -#endif /* _INFO_COMPACTING */ -} -#endif /* 0 */ - -//@cindex G_PRINT_BQ -void -G_PRINT_BQ(node) -StgClosure* node; -{ - StgInfoTable *info; - StgTSO *tso, *last; - char str[80], str0[80]; - - fprintf(stderr,"\n[PE %d] @ %lu BQ: ", - CurrentProc,CurrentTime[CurrentProc]); - if ( node == (StgClosure*)NULL ) { - fprintf(stderr," NULL.\n"); - return; - } - if ( node == END_TSO_QUEUE ) { - fprintf(stderr," _|_\n"); - return; - } - tso = ((StgBlockingQueue*)node)->blocking_queue; - while (node != END_TSO_QUEUE) { - PEs proc; - - /* Find where the tso lives */ - proc = where_is(node); - info = get_itbl(node); - - switch (info->type) { - case TSO: - strcpy(str0,"TSO"); - break; - case BLOCKED_FETCH: - strcpy(str0,"BLOCKED_FETCH"); - break; - default: - strcpy(str0,"???"); - break; - } - - if(proc == CurrentProc) - fprintf(stderr," %#lx (%x) L %s,", - node, ((StgBlockingQueue*)node)->blocking_queue, str0); - else - fprintf(stderr," %#lx (%x) G (PE %d) %s,", - node, ((StgBlockingQueue*)node)->blocking_queue, proc, str0); - - last = tso; - tso = last->link; - } - if ( tso == END_TSO_QUEUE ) - fprintf(stderr," _|_\n"); -} - -//@node Threads, Events, Closures, Debugging routines for GranSim and GUM -//@subsection Threads - -void -G_CURR_THREADQ(verbose) -StgInt verbose; -{ - fprintf(stderr,"Thread Queue on proc %d: ", CurrentProc); - G_THREADQ(run_queue_hd, verbose); -} - -void -G_THREADQ(closure, verbose) -StgTSO* closure; -StgInt verbose; -{ - StgTSO* x; - - fprintf(stderr,"Thread Queue: "); - for (x=closure; x!=END_TSO_QUEUE; x=x->link) - if (verbose) - G_TSO(x,0); - else - fprintf(stderr," %#lx",x); - - if (closure==END_TSO_QUEUE) - fprintf(stderr,"NIL\n"); - else - fprintf(stderr,"\n"); -} - -void -G_TSO(closure,verbose) -StgTSO* closure; -StgInt verbose; -{ - - if (closure==END_TSO_QUEUE) { - fprintf(stderr,"TSO at %#lx is END_TSO_QUEUE!\n"); - return; - } - - if ( verbose & 0x08 ) { /* short info */ - fprintf(stderr,"[TSO @ %#lx, PE %d]: Id: %#lx, Link: %#lx\n", - closure,where_is(closure), - closure->id,closure->link); - return; - } - - fprintf(stderr,"TSO at %#lx has the following contents:\n", - closure); - - fprintf(stderr,"> Id: \t%#lx",closure->id); - // fprintf(stderr,"\tstate: \t%#lx",closure->state); - fprintf(stderr,"\twhat_next: \t%#lx",closure->what_next); - fprintf(stderr,"\tlink: \t%#lx\n",closure->link); - fprintf(stderr,"\twhy_blocked: \t%d", closure->why_blocked); - fprintf(stderr,"\tblock_info: \t%p\n", closure->block_info); - // fprintf(stderr,"\tType: \t%s\n",type_name[TSO_TYPE(closure)]); - fprintf(stderr,">PRI: \t%#lx", closure->gran.pri); - fprintf(stderr,"\tMAGIC: \t%#lx %s\n", closure->gran.magic, - (closure->gran.magic==TSO_MAGIC ? "it IS a TSO" : "THIS IS NO TSO!!")); - if ( verbose & 0x04 ) { - fprintf(stderr, "Stack: stack @ %#lx (stack_size: %u; max_stack_size: %u)\n", - closure->stack, closure->stack_size, closure->max_stack_size); - fprintf(stderr, " sp: %#lx, su: %#lx, splim: %#lx\n", - closure->sp, closure->su, closure->splim); - } - // fprintf(stderr,"\n"); - if (verbose & 0x01) { - // fprintf(stderr,"} LOCKED: \t%#lx",closure->locked); - fprintf(stderr,"} SPARKNAME: \t%#lx\n", closure->gran.sparkname); - fprintf(stderr,"} STARTEDAT: \t%#lx", closure->gran.startedat); - fprintf(stderr,"\tEXPORTED: \t%#lx\n", closure->gran.exported); - fprintf(stderr,"} BASICBLOCKS: \t%#lx", closure->gran.basicblocks); - fprintf(stderr,"\tALLOCS: \t%#lx\n", closure->gran.allocs); - fprintf(stderr,"} EXECTIME: \t%#lx", closure->gran.exectime); - fprintf(stderr,"\tFETCHTIME: \t%#lx\n", closure->gran.fetchtime); - fprintf(stderr,"} FETCHCOUNT: \t%#lx", closure->gran.fetchcount); - fprintf(stderr,"\tBLOCKTIME: \t%#lx\n", closure->gran.blocktime); - fprintf(stderr,"} BLOCKCOUNT: \t%#lx", closure->gran.blockcount); - fprintf(stderr,"\tBLOCKEDAT: \t%#lx\n", closure->gran.blockedat); - fprintf(stderr,"} GLOBALSPARKS:\t%#lx", closure->gran.globalsparks); - fprintf(stderr,"\tLOCALSPARKS:\t%#lx\n", closure->gran.localsparks); - } - if ( verbose & 0x02 ) { - fprintf(stderr,"BQ that starts with this TSO: "); - G_PRINT_BQ(closure); - } -} - -//@node Events, Sparks, Threads, Debugging routines for GranSim and GUM -//@subsection Events - -void -G_EVENT(event, verbose) -rtsEventQ event; -StgInt verbose; -{ - if (verbose) { - print_event(event); - }else{ - fprintf(stderr," %#lx",event); - } -} - -void -G_EVENTQ(verbose) -StgInt verbose; -{ - extern rtsEventQ EventHd; - rtsEventQ x; - - fprintf(stderr,"RtsEventQ (hd @%#lx):\n",EventHd); - for (x=EventHd; x!=NULL; x=x->next) { - G_EVENT(x,verbose); - } - if (EventHd==NULL) - fprintf(stderr,"NIL\n"); - else - fprintf(stderr,"\n"); -} - -void -G_PE_EQ(pe,verbose) -PEs pe; -StgInt verbose; -{ - extern rtsEventQ EventHd; - rtsEventQ x; - - fprintf(stderr,"RtsEventQ (hd @%#lx):\n",EventHd); - for (x=EventHd; x!=NULL; x=x->next) { - if (x->proc==pe) - G_EVENT(x,verbose); - } - if (EventHd==NULL) - fprintf(stderr,"NIL\n"); - else - fprintf(stderr,"\n"); -} - -//@node Sparks, Processors, Events, Debugging routines for GranSim and GUM -//@subsection Sparks - -void -G_SPARK(spark, verbose) -rtsSparkQ spark; -StgInt verbose; -{ - if (spark==(rtsSpark*)NULL) { - belch("G_SPARK: NULL spark; aborting"); - return; - } - if (verbose) - print_spark(spark); - else - fprintf(stderr," %#lx",spark); -} - -void -G_SPARKQ(spark,verbose) -rtsSparkQ spark; -StgInt verbose; -{ - rtsSparkQ x; - - if (spark==(rtsSpark*)NULL) { - belch("G_SPARKQ: NULL spark; aborting"); - return; - } - - fprintf(stderr,"RtsSparkQ (hd @%#lx):\n",spark); - for (x=spark; x!=NULL; x=x->next) { - G_SPARK(x,verbose); - } - if (spark==NULL) - fprintf(stderr,"NIL\n"); - else - fprintf(stderr,"\n"); -} - -void -G_CURR_SPARKQ(verbose) -StgInt verbose; -{ - G_SPARKQ(pending_sparks_hd,verbose); -} - -//@node Processors, Shortcuts, Sparks, Debugging routines for GranSim and GUM -//@subsection Processors - -void -G_PROC(proc,verbose) -StgInt proc; -StgInt verbose; -{ - extern rtsEventQ EventHd; - extern char *proc_status_names[]; - - fprintf(stderr,"Status of proc %d at time %d (%#lx): %s (%s)\n", - proc,CurrentTime[proc],CurrentTime[proc], - (CurrentProc==proc)?"ACTIVE":"INACTIVE", - proc_status_names[procStatus[proc]]); - G_THREADQ(run_queue_hds[proc],verbose & 0x2); - if ( (CurrentProc==proc) ) - G_TSO(CurrentTSO,1); - - if (EventHd!=NULL) - fprintf(stderr,"Next event (%s) is on proc %d\n", - event_names[EventHd->evttype],EventHd->proc); - - if (verbose & 0x1) { - fprintf(stderr,"\nREQUIRED sparks: "); - G_SPARKQ(pending_sparks_hds[proc],1); - fprintf(stderr,"\nADVISORY_sparks: "); - G_SPARKQ(pending_sparks_hds[proc],1); - } -} - -//@node Shortcuts, Printing info type, Processors, Debugging routines for GranSim and GUM -//@subsection Shortcuts - -/* Debug Processor */ -void -GP(proc) -StgInt proc; -{ G_PROC(proc,1); -} - -/* Debug Current Processor */ -void -GCP(){ G_PROC(CurrentProc,2); } - -/* Debug TSO */ -void -GT(StgPtr tso){ - G_TSO(tso,1); -} - -/* Debug CurrentTSO */ -void -GCT(){ - fprintf(stderr,"Current Proc: %d\n",CurrentProc); - G_TSO(CurrentTSO,1); -} - -/* Shorthand for debugging event queue */ -void -GEQ() { G_EVENTQ(1); } - -/* Shorthand for debugging thread queue of a processor */ -void -GTQ(PEs p) { G_THREADQ(run_queue_hds[p],1); } - -/* Shorthand for debugging thread queue of current processor */ -void -GCTQ() { G_THREADQ(run_queue_hds[CurrentProc],1); } - -/* Shorthand for debugging spark queue of a processor */ -void -GSQ(PEs p) { G_SPARKQ(pending_sparks_hds[p],1); } - -/* Shorthand for debugging spark queue of current processor */ -void -GCSQ() { G_CURR_SPARKQ(1); } - -/* Shorthand for printing a node */ -void -GN(StgPtr node) { G_PRINT_NODE(node); } - -/* Shorthand for printing info table */ -#if 0 -// ToDo: fix -- HWL -void -GIT(StgPtr node) { G_INFO_TABLE(node); } -#endif - -void -printThreadQPtrs(void) -{ - PEs p; - for (p=0; p<RtsFlags.GranFlags.proc; p++) { - fprintf(stderr,", PE %d: (hd=%p,tl=%p)", - run_queue_hds[p], run_queue_tls[p]); - } -} - -void -printThreadQ(StgTSO *tso) { G_THREADQ(tso, 0); }; - -void -printSparkQ(rtsSpark *spark) { G_SPARKQ(spark, 0); }; - -void -printThreadQ_verbose(StgTSO *tso) { G_THREADQ(tso, 1); }; - -void -printSparkQ_verbose(rtsSpark *spark) { G_SPARKQ(spark, 1); }; - -/* Shorthand for some of ADRs debugging functions */ - -#endif /* GRAN && GRAN_CHECK*/ - -#if 0 -void -DEBUG_PRINT_NODE(node) -StgPtr node; -{ - W_ info_ptr = INFO_PTR(node); - StgInt size = 0, ptrs = 0, i, vhs = 0; - char info_type[80]; - - info_hdr_type(info_ptr, info_type); - - size_and_ptrs(node,&size,&ptrs); - vhs = var_hdr_size(node); - - fprintf(stderr,"Node: 0x%lx", (W_) node); - -#if defined(PAR) - fprintf(stderr," [GA: 0x%lx]",GA(node)); -#endif - -#if defined(PROFILING) - fprintf(stderr," [CC: 0x%lx]",CC_HDR(node)); -#endif - -#if defined(GRAN) - fprintf(stderr," [Bitmask: 0%lo]",PROCS(node)); -#endif - - fprintf(stderr," IP: 0x%lx (%s), size %ld, %ld ptrs\n", - info_ptr,info_type,size,ptrs); - - /* For now, we ignore the variable header */ - - for(i=0; i < size; ++i) - { - if(i == 0) - fprintf(stderr,"Data: "); - - else if(i % 6 == 0) - fprintf(stderr,"\n "); - - if(i < ptrs) - fprintf(stderr," 0x%lx[P]",*(node+_HS+vhs+i)); - else - fprintf(stderr," %lu[D]",*(node+_HS+vhs+i)); - } - fprintf(stderr, "\n"); -} - - -#define INFO_MASK 0x80000000 - -void -DEBUG_TREE(node) -StgPtr node; -{ - W_ size = 0, ptrs = 0, i, vhs = 0; - - /* Don't print cycles */ - if((INFO_PTR(node) & INFO_MASK) != 0) - return; - - size_and_ptrs(node,&size,&ptrs); - vhs = var_hdr_size(node); - - DEBUG_PRINT_NODE(node); - fprintf(stderr, "\n"); - - /* Mark the node -- may be dangerous */ - INFO_PTR(node) |= INFO_MASK; - - for(i = 0; i < ptrs; ++i) - DEBUG_TREE((StgPtr)node[i+vhs+_HS]); - - /* Unmark the node */ - INFO_PTR(node) &= ~INFO_MASK; -} - - -void -DEBUG_INFO_TABLE(node) -StgPtr node; -{ - W_ info_ptr = INFO_PTR(node); - char *iStgPtrtype = info_hdr_type(info_ptr); - - fprintf(stderr,"%s Info Ptr @0x%lx; Entry: 0x%lx; Size: %lu; Ptrs: %lu\n\n", - iStgPtrtype,info_ptr,(W_) ENTRY_CODE(info_ptr),INFO_SIZE(info_ptr),INFO_NoPTRS(info_ptr)); -#if defined(PAR) - fprintf(stderr,"Enter Flush Entry: 0x%lx;\tExit Flush Entry: 0x%lx\n",INFO_FLUSHENT(info_ptr),INFO_FLUSH(info_ptr)); -#endif - -#if defined(PROFILING) - fprintf(stderr,"Cost Centre (?): 0x%lx\n",INFO_CAT(info_ptr)); -#endif - -#if defined(_INFO_COPYING) - fprintf(stderr,"Evacuate Entry: 0x%lx;\tScavenge Entry: 0x%lx\n", - INFO_EVAC_2S(info_ptr),INFO_SCAV_2S(info_ptr)); -#endif - -#if defined(_INFO_COMPACTING) - fprintf(stderr,"Scan Link: 0x%lx;\tScan Move: 0x%lx\n", - (W_) INFO_SCAN_LINK_1S(info_ptr), (W_) INFO_SCAN_MOVE_1S(info_ptr)); - fprintf(stderr,"Mark: 0x%lx;\tMarked: 0x%lx;\t", - (W_) INFO_MARK_1S(info_ptr), (W_) INFO_MARKED_1S(info_ptr)); -#if 0 /* avoid INFO_TYPE */ - if(BASE_INFO_TYPE(info_ptr)==INFO_SPEC_TYPE) - fprintf(stderr,"plus specialised code\n"); - else - fprintf(stderr,"Marking: 0x%lx\n",(W_) INFO_MARKING_1S(info_ptr)); -#endif /* 0 */ -#endif /* _INFO_COMPACTING */ -} -#endif /* 0 */ - -//@node Printing info type, Printing Packet Contents, Shortcuts, Debugging routines for GranSim and GUM -//@subsection Printing info type - -char * -display_info_type(closure, str) -StgClosure *closure; -char *str; -{ - strcpy(str,""); - if ( closure_HNF(closure) ) - strcat(str,"|_HNF "); - else if ( closure_BITMAP(closure) ) - strcat(str,"|_BTM"); - else if ( !closure_SHOULD_SPARK(closure) ) - strcat(str,"|_NS"); - else if ( closure_STATIC(closure) ) - strcat(str,"|_STA"); - else if ( closure_THUNK(closure) ) - strcat(str,"|_THU"); - else if ( closure_MUTABLE(closure) ) - strcat(str,"|_MUT"); - else if ( closure_UNPOINTED(closure) ) - strcat(str,"|_UPT"); - else if ( closure_SRT(closure) ) - strcat(str,"|_SRT"); - - return(str); -} - -/* - PrintPacket is in Pack.c because it makes use of closure queues -*/ - -#if defined(GRAN) || defined(PAR) - -/* - Print graph rooted at q. The structure of this recursive printing routine - should be the same as in the graph traversals when packing a graph in - GUM. Thus, it demonstrates the structure of such a generic graph - traversal, and in particular, how to extract pointer and non-pointer info - from the multitude of different heap objects available. - - {evacuate}Daq ngoqvam nIHlu'pu'!! -*/ - -void -PrintGraph(StgClosure *p, int indent_level) -{ - void PrintGraph_(StgClosure *p, int indent_level); - - ASSERT(tmpClosureTable==NULL); - - /* init hash table */ - tmpClosureTable = allocHashTable(); - - /* now do the real work */ - PrintGraph_(p, indent_level); - - /* nuke hash table */ - freeHashTable(tmpClosureTable, NULL); - tmpClosureTable = NULL; -} - -/* - This is the actual worker functions. - All recursive calls should be made to this function. -*/ -void -PrintGraph_(StgClosure *p, int indent_level) -{ - StgPtr x, q; - rtsBool printed = rtsFalse; - nat i, j; - const StgInfoTable *info; - - /* check whether we have met this node already to break cycles */ - if (lookupHashTable(tmpClosureTable, (StgWord)p)) { // ie. already touched - /* indentation */ - for (j=0; j<indent_level; j++) - fputs(" ", stderr); - - fprintf(stderr, "#### cylce to %p", p); - return; - } - - /* record that we are processing this closure */ - insertHashTable(tmpClosureTable, (StgWord) p, (void *)rtsTrue/*non-NULL*/); - - q = p; /* save ptr to object */ - - /* indentation */ - for (j=0; j<indent_level; j++) - fputs(" ", stderr); - - ASSERT(p!=(StgClosure*)NULL); - ASSERT(LOOKS_LIKE_STATIC(p) || - LOOKS_LIKE_GHC_INFO(GET_INFO((StgClosure *)p)) || - IS_HUGS_CONSTR_INFO(GET_INFO((StgClosure *)p))); - - printClosure(p); // prints contents of this one closure - - /* indentation */ - for (j=0; j<indent_level; j++) - fputs(" ", stderr); - - info = get_itbl((StgClosure *)p); - /* the rest of this fct recursively traverses the graph */ - switch (info -> type) { - - case BCO: - { - StgBCO* bco = stgCast(StgBCO*,p); - nat i; - fprintf(stderr, "BCO (%p)\n", p); - /* - for (i = 0; i < bco->n_ptrs; i++) { - // bcoConstCPtr(bco,i) = - PrintGraph_(bcoConstCPtr(bco,i), indent_level+1); - } - */ - // p += bco_sizeW(bco); - break; - } - - case MVAR: - /* treat MVars specially, because we don't want to PrintGraph the - * mut_link field in the middle of the closure. - */ - { - StgMVar *mvar = ((StgMVar *)p); - // evac_gen = 0; - fprintf(stderr, "MVAR (%p) with 3 pointers (head, tail, value)\n", p); - // (StgClosure *)mvar->head = - PrintGraph_((StgClosure *)mvar->head, indent_level+1); - // (StgClosure *)mvar->tail = - PrintGraph_((StgClosure *)mvar->tail, indent_level+1); - //(StgClosure *)mvar->value = - PrintGraph_((StgClosure *)mvar->value, indent_level+1); - // p += sizeofW(StgMVar); - // evac_gen = saved_evac_gen; - break; - } - - case THUNK_2_0: - if (!printed) { - fprintf(stderr, "THUNK_2_0 (%p) with 2 pointers\n", p); - printed = rtsTrue; - } - case FUN_2_0: - if (!printed) { - fprintf(stderr, "FUN_2_0 (%p) with 2 pointers\n", p); - printed = rtsTrue; - } - // scavenge_srt(info); - case CONSTR_2_0: - if (!printed) { - fprintf(stderr, "CONSTR_2_0 (%p) with 2 pointers\n", p); - printed = rtsTrue; - } - // ((StgClosure *)p)->payload[0] = - PrintGraph_(((StgClosure *)p)->payload[0], - indent_level+1); - // ((StgClosure *)p)->payload[1] = - PrintGraph_(((StgClosure *)p)->payload[1], - indent_level+1); - // p += sizeofW(StgHeader) + 2; - break; - - case THUNK_1_0: - // scavenge_srt(info); - fprintf(stderr, "THUNK_1_0 (%p) with 1 pointer\n", p); - // ((StgClosure *)p)->payload[0] = - PrintGraph_(((StgClosure *)p)->payload[0], - indent_level+1); - // p += sizeofW(StgHeader) + 2; /* MIN_UPD_SIZE */ - break; - - case FUN_1_0: - if (!printed) { - fprintf(stderr, "FUN_1_0 (%p) with 1 pointer\n", p); - printed = rtsTrue; - } - // scavenge_srt(info); - case CONSTR_1_0: - if (!printed) { - fprintf(stderr, "CONSTR_2_0 (%p) with 2 pointers\n", p); - printed = rtsTrue; - } - // ((StgClosure *)p)->payload[0] = - PrintGraph_(((StgClosure *)p)->payload[0], - indent_level+1); - // p += sizeofW(StgHeader) + 1; - break; - - case THUNK_0_1: - fprintf(stderr, "THUNK_0_1 (%p) with 0 pointers\n", p); - // scavenge_srt(info); - // p += sizeofW(StgHeader) + 2; /* MIN_UPD_SIZE */ - break; - - case FUN_0_1: - fprintf(stderr, "FUN_0_1 (%p) with 0 pointers\n", p); - //scavenge_srt(info); - case CONSTR_0_1: - fprintf(stderr, "CONSTR_0_1 (%p) with 0 pointers\n", p); - //p += sizeofW(StgHeader) + 1; - break; - - case THUNK_0_2: - if (!printed) { - fprintf(stderr, "THUNK_0_2 (%p) with 0 pointers\n", p); - printed = rtsTrue; - } - case FUN_0_2: - if (!printed) { - fprintf(stderr, "FUN_0_2 (%p) with 0 pointers\n", p); - printed = rtsTrue; - } - // scavenge_srt(info); - case CONSTR_0_2: - if (!printed) { - fprintf(stderr, "CONSTR_0_2 (%p) with 0 pointers\n", p); - printed = rtsTrue; - } - // p += sizeofW(StgHeader) + 2; - break; - - case THUNK_1_1: - if (!printed) { - fprintf(stderr, "THUNK_1_1 (%p) with 1 pointer\n", p); - printed = rtsTrue; - } - case FUN_1_1: - if (!printed) { - fprintf(stderr, "FUN_1_1 (%p) with 1 pointer\n", p); - printed = rtsTrue; - } - // scavenge_srt(info); - case CONSTR_1_1: - if (!printed) { - fprintf(stderr, "CONSTR_1_1 (%p) with 1 pointer\n", p); - printed = rtsTrue; - } - // ((StgClosure *)p)->payload[0] = - PrintGraph_(((StgClosure *)p)->payload[0], - indent_level+1); - // p += sizeofW(StgHeader) + 2; - break; - - case FUN: - if (!printed) { - fprintf(stderr, "FUN (%p) with %d pointers\n", p, info->layout.payload.ptrs); - printed = rtsTrue; - } - /* fall through */ - - case THUNK: - if (!printed) { - fprintf(stderr, "THUNK (%p) with %d pointers\n", p, info->layout.payload.ptrs); - printed = rtsTrue; - } - // scavenge_srt(info); - /* fall through */ - - case CONSTR: - if (!printed) { - fprintf(stderr, "CONSTR (%p) with %d pointers\n", p, info->layout.payload.ptrs); - printed = rtsTrue; - } - /* basically same as loop in STABLE_NAME case */ - for (i=0; i<info->layout.payload.ptrs; i++) - PrintGraph_(((StgClosure *)p)->payload[i], - indent_level+1); - break; - /* NOT fall through */ - - case WEAK: - if (!printed) { - fprintf(stderr, "WEAK (%p) with %d pointers\n", p, info->layout.payload.ptrs); - printed = rtsTrue; - } - /* fall through */ - - case FOREIGN: - if (!printed) { - fprintf(stderr, "FOREIGN (%p) with %d pointers\n", p, info->layout.payload.ptrs); - printed = rtsTrue; - } - /* fall through */ - - case STABLE_NAME: - { - StgPtr end; - - if (!printed) { - fprintf(stderr, "STABLE_NAME (%p) with %d pointers (not followed!)\n", - p, info->layout.payload.ptrs); - printed = rtsTrue; - } - end = (StgPtr)((StgClosure *)p)->payload + info->layout.payload.ptrs; - for (p = (StgPtr)((StgClosure *)p)->payload; p < end; p++) { - // (StgClosure *)*p = - //PrintGraph_((StgClosure *)*p, indent_level+1); - fprintf(stderr, ", %p", *p); - } - //fputs("\n", stderr); - // p += info->layout.payload.nptrs; - break; - } - - case IND_PERM: - //if (step->gen->no != 0) { - // SET_INFO(((StgClosure *)p), &IND_OLDGEN_PERM_info); - //} - if (!printed) { - fprintf(stderr, "IND_PERM (%p) with indirection to\n", - p, ((StgIndOldGen *)p)->indirectee); - printed = rtsTrue; - } - /* fall through */ - - case IND_OLDGEN_PERM: - if (!printed) { - fprintf(stderr, "IND_OLDGEN_PERM (%p) with indirection to %p\n", - p, ((StgIndOldGen *)p)->indirectee); - printed = rtsTrue; - } - // ((StgIndOldGen *)p)->indirectee = - PrintGraph_(((StgIndOldGen *)p)->indirectee, - indent_level+1); - //if (failed_to_evac) { - // failed_to_evac = rtsFalse; - // recordOldToNewPtrs((StgMutClosure *)p); - //} - // p += sizeofW(StgIndOldGen); - break; - - case MUT_VAR: - /* ignore MUT_CONSs */ - fprintf(stderr, "MUT_VAR (%p) pointing to %p\n", p, ((StgMutVar *)p)->var); - if (((StgMutVar *)p)->header.info != &stg_MUT_CONS_info) { - //evac_gen = 0; - PrintGraph_(((StgMutVar *)p)->var, indent_level+1); - //evac_gen = saved_evac_gen; - } - //p += sizeofW(StgMutVar); - break; - - case CAF_BLACKHOLE: - if (!printed) { - fprintf(stderr, "CAF_BLACKHOLE (%p) with 0 pointers\n", p); - printed = rtsTrue; - } - case SE_CAF_BLACKHOLE: - if (!printed) { - fprintf(stderr, "SE_CAF_BLACKHOLE (%p) with 0 pointers\n", p); - printed = rtsTrue; - } - case SE_BLACKHOLE: - if (!printed) { - fprintf(stderr, "SE_BLACKHOLE (%p) with 0 pointers\n", p); - printed = rtsTrue; - } - case BLACKHOLE: - if (!printed) { - fprintf(stderr, "BLACKHOLE (%p) with 0 pointers\n", p); - printed = rtsTrue; - } - //p += BLACKHOLE_sizeW(); - break; - - case BLACKHOLE_BQ: - { - StgBlockingQueue *bh = (StgBlockingQueue *)p; - // (StgClosure *)bh->blocking_queue = - fprintf(stderr, "BLACKHOLE_BQ (%p) pointing to %p\n", - p, (StgClosure *)bh->blocking_queue); - PrintGraph_((StgClosure *)bh->blocking_queue, indent_level+1); - //if (failed_to_evac) { - // failed_to_evac = rtsFalse; - // recordMutable((StgMutClosure *)bh); - //} - // p += BLACKHOLE_sizeW(); - break; - } - - case THUNK_SELECTOR: - { - StgSelector *s = (StgSelector *)p; - fprintf(stderr, "THUNK_SELECTOR (%p) pointing to %p\n", - p, s->selectee); - PrintGraph_(s->selectee, indent_level+1); - // p += THUNK_SELECTOR_sizeW(); - break; - } - - case IND: - fprintf(stderr, "IND (%p) pointing to %p\n", p, ((StgInd*)p)->indirectee); - PrintGraph_(((StgInd*)p)->indirectee, indent_level+1); - break; - - case IND_OLDGEN: - fprintf(stderr, "IND_OLDGEN (%p) pointing to %p\n", - p, ((StgIndOldGen*)p)->indirectee); - PrintGraph_(((StgIndOldGen*)p)->indirectee, indent_level+1); - break; - - case CONSTR_INTLIKE: - fprintf(stderr, "CONSTR_INTLIKE (%p) with 0 pointers\n", p); - break; - case CONSTR_CHARLIKE: - fprintf(stderr, "CONSTR_CHARLIKE (%p) with 0 pointers\n", p); - break; - case CONSTR_STATIC: - fprintf(stderr, "CONSTR_STATIC (%p) with 0 pointers\n", p); - break; - case CONSTR_NOCAF_STATIC: - fprintf(stderr, "CONSTR_NOCAF_STATIC (%p) with 0 pointers\n", p); - break; - case THUNK_STATIC: - fprintf(stderr, "THUNK_STATIC (%p) with 0 pointers\n", p); - break; - case FUN_STATIC: - fprintf(stderr, "FUN_STATIC (%p) with 0 pointers\n", p); - break; - case IND_STATIC: - fprintf(stderr, "IND_STATIC (%p) with 0 pointers\n", p); - break; - - case RET_BCO: - fprintf(stderr, "RET_BCO (%p) with 0 pointers\n", p); - break; - case RET_SMALL: - fprintf(stderr, "RET_SMALL (%p) with 0 pointers\n", p); - break; - case RET_VEC_SMALL: - fprintf(stderr, "RET_VEC_SMALL (%p) with 0 pointers\n", p); - break; - case RET_BIG: - fprintf(stderr, "RET_BIG (%p) with 0 pointers\n", p); - break; - case RET_VEC_BIG: - fprintf(stderr, "RET_VEC_BIG (%p) with 0 pointers\n", p); - break; - case RET_DYN: - fprintf(stderr, "RET_DYN (%p) with 0 pointers\n", p); - break; - case UPDATE_FRAME: - fprintf(stderr, "UPDATE_FRAME (%p) with 0 pointers\n", p); - break; - case STOP_FRAME: - fprintf(stderr, "STOP_FRAME (%p) with 0 pointers\n", p); - break; - case CATCH_FRAME: - fprintf(stderr, "CATCH_FRAME (%p) with 0 pointers\n", p); - break; - case SEQ_FRAME: - fprintf(stderr, "SEQ_FRAME (%p) with 0 pointers\n", p); - break; - - case AP_UPD: /* same as PAPs */ - fprintf(stderr, "AP_UPD (%p) with 0 pointers\n", p); - case PAP: - /* Treat a PAP just like a section of stack, not forgetting to - * PrintGraph_ the function pointer too... - */ - { - StgPAP* pap = stgCast(StgPAP*,p); - - fprintf(stderr, "PAP (%p) pointing to %p\n", p, pap->fun); - // pap->fun = - //PrintGraph_(pap->fun, indent_level+1); - //scavenge_stack((P_)pap->payload, (P_)pap->payload + pap->n_args); - //p += pap_sizeW(pap); - break; - } - - case ARR_WORDS: - /* an array of (non-mutable) words */ - fprintf(stderr, "ARR_WORDS (%p) of %d non-ptrs (maybe a string?)\n", - p, arr_words_words((StgArrWords *)q)); - break; - - case MUT_ARR_PTRS: - /* follow everything */ - { - StgPtr next; - - fprintf(stderr, "MUT_ARR_PTRS (%p) with %d pointers (not followed)\n", - p, mut_arr_ptrs_sizeW((StgMutArrPtrs*)p)); - // evac_gen = 0; /* repeatedly mutable */ - next = p + mut_arr_ptrs_sizeW((StgMutArrPtrs*)p); - for (p = (P_)((StgMutArrPtrs *)p)->payload; p < next; p++) { - // (StgClosure *)*p = - // PrintGraph_((StgClosure *)*p, indent_level+1); - fprintf(stderr, ", %p", *p); - } - fputs("\n", stderr); - //evac_gen = saved_evac_gen; - break; - } - - case MUT_ARR_PTRS_FROZEN: - /* follow everything */ - { - StgPtr start = p, next; - - fprintf(stderr, "MUT_ARR_PTRS (%p) with %d pointers (not followed)", - p, mut_arr_ptrs_sizeW((StgMutArrPtrs*)p)); - next = p + mut_arr_ptrs_sizeW((StgMutArrPtrs*)p); - for (p = (P_)((StgMutArrPtrs *)p)->payload; p < next; p++) { - // (StgClosure *)*p = - // PrintGraph_((StgClosure *)*p, indent_level+1); - fprintf(stderr, ", %p", *p); - } - fputs("\n", stderr); - //if (failed_to_evac) { - /* we can do this easier... */ - // recordMutable((StgMutClosure *)start); - // failed_to_evac = rtsFalse; - //} - break; - } - - case TSO: - { - StgTSO *tso; - - tso = (StgTSO *)p; - fprintf(stderr, "TSO (%p) with link field %p\n", p, (StgClosure *)tso->link); - // evac_gen = 0; - /* chase the link field for any TSOs on the same queue */ - // (StgClosure *)tso->link = - PrintGraph_((StgClosure *)tso->link, indent_level+1); - //if (tso->blocked_on) { - // tso->blocked_on = PrintGraph_(tso->blocked_on); - //} - /* scavenge this thread's stack */ - //scavenge_stack(tso->sp, &(tso->stack[tso->stack_size])); - //evac_gen = saved_evac_gen; - //p += tso_sizeW(tso); - break; - } - -#if defined(GRAN) || defined(PAR) - case RBH: - { - StgInfoTable *rip = REVERT_INFOPTR(get_itbl(p)); - //if (LOOKS_LIKE_GHC_INFO(rip)) - // fprintf(stderr, "RBH (%p) with 0 pointers (reverted type=%s)\n", - // p, info_type_by_ip(rip)); - //else - fprintf(stderr, "RBH (%p) with 0 pointers (reverted IP=%x)\n", - p, rip); - } - break; -#endif -#if defined(PAR) - case BLOCKED_FETCH: - fprintf(stderr, "BLOCKED_FETCH (%p) with 0 pointers (link=%p)\n", - p, ((StgBlockedFetch *)p)->link); - break; - case FETCH_ME: - fprintf(stderr, "FETCH_ME (%p) with 0 pointers\n", p); - break; - case FETCH_ME_BQ: - fprintf(stderr, "FETCH_ME_BQ (%p) with 0 pointers (blocking_queue=%p)\n", - p, ((StgFetchMeBlockingQueue *)p)->blocking_queue); - break; -#endif - -#ifdef DIST - case REMOTE_REF: - fprintf(stderr, "REMOTE_REF (%p) with 0 pointers\n", p); - break; -#endif - - case EVACUATED: - fprintf(stderr, "EVACUATED (%p) with 0 pointers (evacuee=%p)\n", - p, ((StgEvacuated *)p)->evacuee); - break; - - default: - barf("PrintGraph_: unknown closure %d (%s)", - info -> type, info_type(info)); - } - - /* If we didn't manage to promote all the objects pointed to by - * the current object, then we have to designate this object as - * mutable (because it contains old-to-new generation pointers). - */ - //if (failed_to_evac) { - // mkMutCons((StgClosure *)q, &generations[evac_gen]); - // failed_to_evac = rtsFalse; - //} -} - -# if defined(PAR) -/* - Generate a finger-print for a graph. - A finger-print is a string, with each char representing one node; - depth-first traversal -*/ - -void -GraphFingerPrint(StgClosure *p, char *finger_print) -{ - void GraphFingerPrint_(StgClosure *p, char *finger_print); - - ASSERT(tmpClosureTable==NULL); - ASSERT(strlen(finger_print)==0); - - /* init hash table */ - tmpClosureTable = allocHashTable(); - - /* now do the real work */ - GraphFingerPrint_(p, finger_print); - - /* nuke hash table */ - freeHashTable(tmpClosureTable, NULL); - tmpClosureTable = NULL; -} - -/* - This is the actual worker functions. - All recursive calls should be made to this function. -*/ -void -GraphFingerPrint_(StgClosure *p, char *finger_print) -{ - StgPtr x, q; - rtsBool printed = rtsFalse; - nat i, j, len; - const StgInfoTable *info; - - q = p; /* save ptr to object */ - len = strlen(finger_print); - ASSERT(len<=MAX_FINGER_PRINT_LEN); - /* at most 7 chars for this node (I think) */ - if (len+7>=MAX_FINGER_PRINT_LEN) - return; - - /* check whether we have met this node already to break cycles */ - if (lookupHashTable(tmpClosureTable, (StgWord)p)) { // ie. already touched - strcat(finger_print, "#"); - return; - } - - /* record that we are processing this closure */ - insertHashTable(tmpClosureTable, (StgWord) p, (void *)rtsTrue/*non-NULL*/); - - ASSERT(p!=(StgClosure*)NULL); - ASSERT(LOOKS_LIKE_STATIC(p) || - LOOKS_LIKE_GHC_INFO(GET_INFO((StgClosure *)p)) || - IS_HUGS_CONSTR_INFO(GET_INFO((StgClosure *)p))); - - info = get_itbl((StgClosure *)p); - // append char for this node - finger_print[len] = finger_print_char[info->type]; finger_print[len+1] = '\0'; - /* the rest of this fct recursively traverses the graph */ - switch (info -> type) { - - case BCO: - { - StgBCO* bco = stgCast(StgBCO*,p); - nat i; - //%% fprintf(stderr, "BCO (%p) with %d pointers\n", p, bco->n_ptrs); - /* - for (i = 0; i < bco->n_ptrs; i++) { - // bcoConstCPtr(bco,i) = - GraphFingerPrint_(bcoConstCPtr(bco,i), finger_print); - } - */ - // p += bco_sizeW(bco); - break; - } - - case MVAR: - break; - - case THUNK_2_0: - case FUN_2_0: - case CONSTR_2_0: - // append char for this node - strcat(finger_print, "22("); - GraphFingerPrint_(((StgClosure *)p)->payload[0], finger_print); - GraphFingerPrint_(((StgClosure *)p)->payload[1], finger_print); - if (strlen(finger_print)+2<MAX_FINGER_PRINT_LEN) - strcat(finger_print, ")"); - break; - - case THUNK_1_0: - case FUN_1_0: - case CONSTR_1_0: - // append char for this node - strcat(finger_print, "12("); - GraphFingerPrint_(((StgClosure *)p)->payload[0], finger_print); - if (strlen(finger_print)+2<MAX_FINGER_PRINT_LEN) - strcat(finger_print, ")"); - break; - - case THUNK_0_1: - case FUN_0_1: - case CONSTR_0_1: - // append char for this node - strcat(finger_print, "01"); - break; - - case THUNK_0_2: - case FUN_0_2: - case CONSTR_0_2: - // append char for this node - strcat(finger_print, "02"); - break; - - case THUNK_1_1: - case FUN_1_1: - case CONSTR_1_1: - // append char for this node - strcat(finger_print, "11("); - GraphFingerPrint_(((StgClosure *)p)->payload[0], finger_print); - if (strlen(finger_print)+2<MAX_FINGER_PRINT_LEN) - strcat(finger_print, ")"); - break; - - case FUN: - case THUNK: - case CONSTR: - /* basically same as loop in STABLE_NAME case */ - { - char str[6]; - sprintf(str,"%d?(",info->layout.payload.ptrs); - strcat(finger_print,str); - for (i=0; i<info->layout.payload.ptrs; i++) - GraphFingerPrint_(((StgClosure *)p)->payload[i], finger_print); - if (strlen(finger_print)+2<MAX_FINGER_PRINT_LEN) - strcat(finger_print, ")"); - } - break; - - case WEAK: - case FOREIGN: - case STABLE_NAME: - { - StgPtr end; - char str[6]; - sprintf(str,"%d?", info->layout.payload.ptrs); - strcat(finger_print,str); - - //end = (StgPtr)((StgClosure *)p)->payload + info->layout.payload.ptrs; - //for (p = (StgPtr)((StgClosure *)p)->payload; p < end; p++) { - // GraphFingerPrint_((StgClosure *)*p, finger_print); - //} - break; - } - - case IND_PERM: - case IND_OLDGEN_PERM: - GraphFingerPrint_(((StgIndOldGen *)p)->indirectee, finger_print); - break; - - case MUT_VAR: - /* ignore MUT_CONSs */ - if (((StgMutVar *)p)->header.info != &stg_MUT_CONS_info) { - GraphFingerPrint_(((StgMutVar *)p)->var, finger_print); - } - break; - - case CAF_BLACKHOLE: - case SE_CAF_BLACKHOLE: - case SE_BLACKHOLE: - case BLACKHOLE: - break; - - case BLACKHOLE_BQ: - { - StgBlockingQueue *bh = (StgBlockingQueue *)p; - // GraphFingerPrint_((StgClosure *)bh->blocking_queue, finger_print); - break; - } - - case THUNK_SELECTOR: - { - StgSelector *s = (StgSelector *)p; - GraphFingerPrint_(s->selectee, finger_print); - break; - } - - case IND: - GraphFingerPrint_(((StgInd*)p)->indirectee, finger_print); - break; - - case IND_OLDGEN: - GraphFingerPrint_(((StgIndOldGen*)p)->indirectee, finger_print); - break; - - case IND_STATIC: - GraphFingerPrint_(((StgIndOldGen*)p)->indirectee, finger_print); - break; - - case CONSTR_INTLIKE: - case CONSTR_CHARLIKE: - case CONSTR_STATIC: - case CONSTR_NOCAF_STATIC: - case THUNK_STATIC: - case FUN_STATIC: - break; - - case RET_BCO: - case RET_SMALL: - case RET_VEC_SMALL: - case RET_BIG: - case RET_VEC_BIG: - case RET_DYN: - case UPDATE_FRAME: - case STOP_FRAME: - case CATCH_FRAME: - case SEQ_FRAME: - break; - - case AP_UPD: /* same as PAPs */ - case PAP: - /* Treat a PAP just like a section of stack, not forgetting to - * GraphFingerPrint_ the function pointer too... - */ - { - StgPAP* pap = stgCast(StgPAP*,p); - char str[6]; - sprintf(str,"%d",pap->n_args); - strcat(finger_print,str); - //GraphFingerPrint_(pap->fun, finger_print); // ?? - break; - } - - case ARR_WORDS: - { - char str[6]; - sprintf(str,"%d",arr_words_words((StgArrWords*)p)); - strcat(finger_print,str); - } - break; - - case MUT_ARR_PTRS: - /* follow everything */ - { - char str[6]; - sprintf(str,"%d",((StgMutArrPtrs*)p)->ptrs); - strcat(finger_print,str); - } - { - StgPtr next; - //next = p + mut_arr_ptrs_sizeW((StgMutArrPtrs*)p); - //for (p = (P_)((StgMutArrPtrs *)p)->payload; p < next; p++) { - // GraphFingerPrint_((StgClosure *)*p, finger_print); - //} - break; - } - - case MUT_ARR_PTRS_FROZEN: - /* follow everything */ - { - char str[6]; - sprintf(str,"%d",((StgMutArrPtrs*)p)->ptrs); - strcat(finger_print,str); - } - { - StgPtr start = p, next; - //next = p + mut_arr_ptrs_sizeW((StgMutArrPtrs*)p); - //for (p = (P_)((StgMutArrPtrs *)p)->payload; p < next; p++) { - // GraphFingerPrint_((StgClosure *)*p, finger_print); - //} - break; - } - - case TSO: - { - StgTSO *tso = (StgTSO *)p; - char str[6]; - sprintf(str,"%d",tso->id); - strcat(finger_print,str); - } - //GraphFingerPrint_((StgClosure *)tso->link, indent_level+1); - break; - -#if defined(GRAN) || defined(PAR) - case RBH: - { - // use this - // StgInfoTable *rip = REVERT_INFOPTR(get_itbl(p)); - } - break; -#endif -#if defined(PAR) - case BLOCKED_FETCH: - break; - case FETCH_ME: - break; - case FETCH_ME_BQ: - break; -#endif -#ifdef DIST - case REMOTE_REF: - break; -#endif - case EVACUATED: - break; - - default: - barf("GraphFingerPrint_: unknown closure %d (%s)", - info -> type, info_type(info)); - } - -} -# endif /* PAR */ - -/* - Do a sanity check on the whole graph, down to a recursion level of level. - Same structure as PrintGraph (nona). -*/ -void -checkGraph(StgClosure *p, int rec_level) -{ - StgPtr x, q; - nat i, j; - const StgInfoTable *info; - - if (rec_level==0) - return; - - q = p; /* save ptr to object */ - - /* First, the obvious generic checks */ - ASSERT(p!=(StgClosure*)NULL); - checkClosure(p); /* see Sanity.c for what's actually checked */ - - info = get_itbl((StgClosure *)p); - /* the rest of this fct recursively traverses the graph */ - switch (info -> type) { - - case BCO: - { - StgBCO* bco = stgCast(StgBCO*,p); - nat i; - /* - for (i = 0; i < bco->n_ptrs; i++) { - checkGraph(bcoConstCPtr(bco,i), rec_level-1); - } - */ - break; - } - - case MVAR: - /* treat MVars specially, because we don't want to PrintGraph the - * mut_link field in the middle of the closure. - */ - { - StgMVar *mvar = ((StgMVar *)p); - checkGraph((StgClosure *)mvar->head, rec_level-1); - checkGraph((StgClosure *)mvar->tail, rec_level-1); - checkGraph((StgClosure *)mvar->value, rec_level-1); - break; - } - - case THUNK_2_0: - case FUN_2_0: - case CONSTR_2_0: - checkGraph(((StgClosure *)p)->payload[0], rec_level-1); - checkGraph(((StgClosure *)p)->payload[1], rec_level-1); - break; - - case THUNK_1_0: - checkGraph(((StgClosure *)p)->payload[0], rec_level-1); - break; - - case FUN_1_0: - case CONSTR_1_0: - checkGraph(((StgClosure *)p)->payload[0], rec_level-1); - break; - - case THUNK_0_1: - break; - - case FUN_0_1: - case CONSTR_0_1: - break; - - case THUNK_0_2: - case FUN_0_2: - case CONSTR_0_2: - break; - - case THUNK_1_1: - case FUN_1_1: - case CONSTR_1_1: - checkGraph(((StgClosure *)p)->payload[0], rec_level-1); - break; - - case FUN: - case THUNK: - case CONSTR: - for (i=0; i<info->layout.payload.ptrs; i++) - checkGraph(((StgClosure *)p)->payload[i], rec_level-1); - break; - - case WEAK: - case FOREIGN: - case STABLE_NAME: - { - StgPtr end; - - end = (StgPtr)((StgClosure *)p)->payload + info->layout.payload.ptrs; - for (p = (StgPtr)((StgClosure *)p)->payload; p < end; p++) { - checkGraph(*(StgClosure **)p, rec_level-1); - } - break; - } - - case IND_PERM: - case IND_OLDGEN_PERM: - checkGraph(((StgIndOldGen *)p)->indirectee, rec_level-1); - break; - - case MUT_VAR: - /* ignore MUT_CONSs */ - if (((StgMutVar *)p)->header.info != &stg_MUT_CONS_info) { - checkGraph(((StgMutVar *)p)->var, rec_level-1); - } - break; - - case CAF_BLACKHOLE: - case SE_CAF_BLACKHOLE: - case SE_BLACKHOLE: - case BLACKHOLE: - break; - - case BLACKHOLE_BQ: - break; - - case THUNK_SELECTOR: - { - StgSelector *s = (StgSelector *)p; - checkGraph(s->selectee, rec_level-1); - break; - } - - case IND: - checkGraph(((StgInd*)p)->indirectee, rec_level-1); - break; - - case IND_OLDGEN: - checkGraph(((StgIndOldGen*)p)->indirectee, rec_level-1); - break; - - case CONSTR_INTLIKE: - break; - case CONSTR_CHARLIKE: - break; - case CONSTR_STATIC: - break; - case CONSTR_NOCAF_STATIC: - break; - case THUNK_STATIC: - break; - case FUN_STATIC: - break; - case IND_STATIC: - break; - - case RET_BCO: - break; - case RET_SMALL: - break; - case RET_VEC_SMALL: - break; - case RET_BIG: - break; - case RET_VEC_BIG: - break; - case RET_DYN: - break; - case UPDATE_FRAME: - break; - case STOP_FRAME: - break; - case CATCH_FRAME: - break; - case SEQ_FRAME: - break; - - case AP_UPD: /* same as PAPs */ - case PAP: - /* Treat a PAP just like a section of stack, not forgetting to - * checkGraph the function pointer too... - */ - { - StgPAP* pap = stgCast(StgPAP*,p); - - checkGraph(pap->fun, rec_level-1); - break; - } - - case ARR_WORDS: - break; - - case MUT_ARR_PTRS: - /* follow everything */ - { - StgPtr next; - - next = p + mut_arr_ptrs_sizeW((StgMutArrPtrs*)p); - for (p = (P_)((StgMutArrPtrs *)p)->payload; p < next; p++) { - checkGraph(*(StgClosure **)p, rec_level-1); - } - break; - } - - case MUT_ARR_PTRS_FROZEN: - /* follow everything */ - { - StgPtr start = p, next; - - next = p + mut_arr_ptrs_sizeW((StgMutArrPtrs*)p); - for (p = (P_)((StgMutArrPtrs *)p)->payload; p < next; p++) { - checkGraph(*(StgClosure **)p, rec_level-1); - } - break; - } - - case TSO: - { - StgTSO *tso; - - tso = (StgTSO *)p; - checkGraph((StgClosure *)tso->link, rec_level-1); - break; - } - -#if defined(GRAN) || defined(PAR) - case RBH: - break; -#endif -#if defined(PAR) - case BLOCKED_FETCH: - break; - case FETCH_ME: - break; - case FETCH_ME_BQ: - break; -#endif - case EVACUATED: - barf("checkGraph: found EVACUATED closure %p (%s)", - p, info_type(p)); - break; - - default: - } -} - -#endif /* GRAN */ - -#endif /* GRAN || PAR */ - -//@node End of File, , Printing Packet Contents, Debugging routines for GranSim and GUM -//@subsection End of File diff --git a/rts/parallel/ParallelDebug.h b/rts/parallel/ParallelDebug.h deleted file mode 100644 index f8aaeb85d4..0000000000 --- a/rts/parallel/ParallelDebug.h +++ /dev/null @@ -1,79 +0,0 @@ -/* - Time-stamp: <Tue Mar 06 2001 00:25:14 Stardate: [-30]6285.08 hwloidl> - - Prototypes of all parallel debugging functions. -*/ - -#ifndef PARALLEL_DEBUG_H -#define PARALLEL_DEBUG_H - -#if defined(DEBUG) && (defined(GRAN) || defined(PAR)) -/* max length of the string holding a finger-print for a graph */ -#define MAX_FINGER_PRINT_LEN 10000 -// (10*RtsFlags.ParFlags.packBufferSize) -#endif - -#if defined(DEBUG) && defined(GRAN) -void G_PRINT_NODE(StgClosure* node); -void G_PPN(StgClosure* node); -void G_INFO_TABLE(StgClosure* node); -void G_CURR_THREADQ(StgInt verbose); -void G_THREADQ(StgTSO* closure, StgInt verbose); -void G_TSO(StgTSO* closure, StgInt verbose); -void G_EVENT(rtsEventQ event, StgInt verbose); -void G_EVENTQ(StgInt verbose); -void G_PE_EQ(PEs pe, StgInt verbose); -void G_SPARK(rtsSparkQ spark, StgInt verbose); -void G_SPARKQ(rtsSparkQ spark, StgInt verbose); -void G_CURR_SPARKQ(StgInt verbose); -void G_PROC(StgInt proc, StgInt verbose); -void GP(StgInt proc); -void GCP(void); -void GT(StgPtr tso); -void GCT(void); -void GEQ(void); -void GTQ(PEs p); -void GCTQ(void); -void GSQ(PEs p); -void GCSQ(void); -void GN(StgPtr node); -void GIT(StgPtr node); -#endif - -#if defined(GRAN) || defined(PAR) - -char *display_info_type(StgClosure *closure, char *str); -void info_hdr_type(StgClosure *closure, char *res); -char *info_type(StgClosure *closure); -char *info_type_by_ip(StgInfoTable *ip); - -void PrintPacket(rtsPackBuffer *buffer); -void PrintGraph(StgClosure *p, int indent_level); -void GraphFingerPrint(StgClosure *p, char *finger_print); -void checkGraph(StgClosure *p, int rec_level); - -void checkPacket(rtsPackBuffer *packBuffer); - -#endif /* GRAN || PAR */ - -#if defined(PAR) - -/* don't want to import Schedule.h and Sanity.h everywhere */ -extern void print_bq (StgClosure *node); -extern void checkBQ (StgBlockingQueueElement *bqe, StgClosure *closure); - -void checkGAGAMap(globalAddr *gagamap, int nGAs); -extern rtsBool isOnLiveIndTable(globalAddr *ga); -extern void rebuildGAtables(rtsBool full); -extern void rebuildLAGAtable(void); -extern void checkLAGAtable(rtsBool check_closures); -extern void checkHeapChunk(StgPtr start, StgPtr end); -extern void printGA (globalAddr *ga); -extern void printGALA (GALA *gala); -extern void printLiveIndTable(void); -extern void printRemoteGATable(void); -extern void printLAGAtable(void); - -#endif - -#endif /* PARALLEL_DEBUG_H */ diff --git a/rts/parallel/ParallelRts.h b/rts/parallel/ParallelRts.h deleted file mode 100644 index d421296d19..0000000000 --- a/rts/parallel/ParallelRts.h +++ /dev/null @@ -1,253 +0,0 @@ -/* -------------------------------------------------------------------------- - Time-stamp: <Tue Mar 06 2001 00:25:50 Stardate: [-30]6285.08 hwloidl> - - Variables and functions specific to the parallel RTS (i.e. GUM or GranSim) - ----------------------------------------------------------------------- */ - -#ifndef PARALLEL_RTS_H -#define PARALLEL_RTS_H - -#include "ParTicky.h" - -/* HWL HACK: compile time sanity checks; shouldn't be necessary at all */ -#if defined(PAR) && defined(GRAN) -# error "Both PAR and GRAN defined" -#endif - -#if defined(DEBUG) -/* Paranoia debugging: we add an end-of-buffer marker to every pack buffer - (only when sanity checking RTS is enabled, of course) */ -#define DEBUG_HEADROOM 1 -#define END_OF_BUFFER_MARKER 0x1111bbbb -#define GARBAGE_MARKER 0x1111eeee -#else -#define DEBUG_HEADROOM 0 -#endif /* DEBUG */ - -#if defined(GRAN) || defined(PAR) - -#if defined(GRAN) - -/* Statistics info */ -extern nat tot_packets, tot_packet_size, tot_cuts, tot_thunks; - -/* Pack.c */ -rtsPackBuffer *PackNearbyGraph(StgClosure* closure, StgTSO* tso, - nat *packBufferSize, GlobalTaskId dest); -rtsPackBuffer *PackOneNode(StgClosure* closure, StgTSO* tso, - nat *packBufferSize); -rtsPackBuffer *PackTSO(StgTSO *tso, nat *packBufferSize); -rtsPackBuffer *PackStkO(StgPtr stko, nat *packBufferSize); -void PackFetchMe(StgClosure *closure); - -/* Unpack.c */ -StgClosure* UnpackGraph(rtsPackBuffer* buffer); -void InitPendingGABuffer(nat size); - -/* RBH.c */ -StgClosure *convertToRBH(StgClosure *closure); -void convertFromRBH(StgClosure *closure); - -/* HLComms.c */ -rtsFetchReturnCode blockFetch(StgTSO* tso, PEs proc, StgClosure* bh); -void blockThread(StgTSO *tso); - -#endif -#if defined(PAR) - -/* Statistics info */ - -/* global structure for collecting statistics */ -typedef struct GlobalParStats_ { - /* GALA and LAGA table info */ - nat tot_mark_GA, tot_rebuild_GA, tot_free_GA, - res_mark_GA, res_rebuild_GA, res_free_GA, - cnt_mark_GA, cnt_rebuild_GA, cnt_free_GA, - res_size_GA, tot_size_GA, local_alloc_GA, tot_global, tot_local; - - /* time spent managing the GAs */ - double time_mark_GA, time_rebuild_GA; - - /* spark queue stats */ - nat res_sp, tot_sp, cnt_sp, emp_sp; - // nat tot_sq_len, tot_sq_probes, tot_sparks; - /* thread queue stats */ - nat res_tp, tot_tp, cnt_tp, emp_tp; - //nat tot_add_threads, tot_tq_len, non_end_add_threads; - - /* packet statistics */ - nat tot_packets, tot_packet_size, tot_thunks, - res_packet_size, res_thunks, - rec_packets, rec_packet_size, rec_thunks, - rec_res_packet_size, rec_res_thunks; - /* time spent packing stuff */ - double time_pack, time_unpack; - - /* thread stats */ - nat tot_threads_created; - - /* spark stats */ - //nat pruned_sparks, withered_sparks; - nat tot_sparks_created, tot_sparks_ignored, tot_sparks_marked, - res_sparks_created, res_sparks_ignored, res_sparks_marked; // , sparks_created_on_PE[MAX_PROC]; - double time_sparks; - - /* scheduling stats */ - nat tot_yields, tot_stackover, tot_heapover; - - /* message statistics */ - nat tot_fish_mess, tot_fetch_mess, tot_resume_mess, tot_schedule_mess; - nat rec_fish_mess, rec_fetch_mess, rec_resume_mess, rec_schedule_mess; -#if defined(DIST) - nat tot_reval_mess; - nat rec_reval_mess; -#endif - - /* blocking queue statistics - rtsTime tot_bq_processing_time; - nat tot_bq_len, tot_bq_len_local, tot_awbq, tot_FMBQs; - */ - - /* specialised info on arrays (for GPH/Maple mainly) */ - nat tot_arrs, tot_arr_size; -} GlobalParStats; - -extern GlobalParStats globalParStats; - -void globalParStat_exit(void); - -/* Pack.c */ -rtsBool InitPackBuffer(void); -rtsPackBuffer *PackNearbyGraph(StgClosure* closure, StgTSO* tso, - nat *packBufferSize, GlobalTaskId dest); - -/* Unpack.c */ -void CommonUp(StgClosure *src, StgClosure *dst); -StgClosure *UnpackGraph(rtsPackBuffer *buffer, globalAddr **gamap, - nat *nGAs); - -/* RBH.c */ -StgClosure *convertToRBH(StgClosure *closure); -void convertToFetchMe(StgRBH *rbh, globalAddr *ga); - -/* HLComms.c */ -void blockFetch(StgBlockedFetch *bf, StgClosure *bh); -void blockThread(StgTSO *tso); - -/* Global.c */ -void GALAdeprecate(globalAddr *ga); - -/* HLComms.c */ -nat pending_fetches_len(void); - -/* ParInit.c */ -void initParallelSystem(void); -void shutdownParallelSystem(StgInt n); -void synchroniseSystem(void); -void par_exit(I_); - -#endif - -/* this routine should be moved to a more general module; currently in Pack.c -StgInfoTable* get_closure_info(StgClosure* node, - nat *size, nat *ptrs, nat *nonptrs, nat *vhs, - char *info_hdr_ty); -*/ -void doGlobalGC(void); - -//@node GC routines, Debugging routines, Spark handling routines -//@subsection GC routines - -#if defined(PAR) -/* HLComms.c */ -void freeRemoteGA(int pe, globalAddr *ga); -void sendFreeMessages(void); -void markPendingFetches(rtsBool major_gc); - -/* Global.c */ -void markLocalGAs(rtsBool full); -void RebuildGAtables(rtsBool full); -void RebuildLAGAtable(void); -#endif - -//@node Debugging routines, Generating .gr profiles, GC routines -//@subsection Debugging routines - -#if defined(PAR) -void printGA (globalAddr *ga); -void printGALA (GALA *gala); -void printLAGAtable(void); - -rtsBool isOnLiveIndTable(globalAddr *ga); -rtsBool isOnRemoteGATable(globalAddr *ga); -void checkFreeGALAList(void); -void checkFreeIndirectionsList(void); -#endif - -//@node Generating .gr profiles, Index, Debugging routines -//@subsection Generating .gr profiles - -#define STATS_FILENAME_MAXLEN 128 - -/* Where to write the log file */ -//@cindex gr_file -//@cindex gr_filename -extern FILE *gr_file; -extern char gr_filename[STATS_FILENAME_MAXLEN]; - -//@cindex init_gr_stats -//@cindex init_gr_simulation -//@cindex end_gr_simulation -void init_gr_stats (void); -void init_gr_simulation(int rts_argc, char *rts_argv[], - int prog_argc, char *prog_argv[]); -void end_gr_simulation(void); - -// TODO: move fcts in here (as static inline) -StgInfoTable* get_closure_info(StgClosure* node, nat *size, nat *ptrs, nat *nonptrs, nat *vhs, char *info_hdr_ty); -rtsBool IS_BLACK_HOLE(StgClosure* node); -StgClosure *IS_INDIRECTION(StgClosure* node) ; -StgClosure *UNWIND_IND (StgClosure *closure); - - -#endif /* defined(PAR) || defined(GRAN) */ - -//@node Common macros, Index, Generating .gr profiles -//@subsection Common macros - -#define LOOKS_LIKE_PTR(r) \ - (LOOKS_LIKE_STATIC_CLOSURE(r) || \ - ((HEAP_ALLOCED(r) && Bdescr((P_)r)->free != (void *)-1))) - -/* see Sanity.c for this kind of test; doing this in these basic fcts - is paranoid (nuke it after debugging!) -*/ - -/* pathetic version of the check whether p can be a closure */ -#define LOOKS_LIKE_COOL_CLOSURE(p) 1 - -//LOOKS_LIKE_GHC_INFO(get_itbl(p)) - - /* Is it a static closure (i.e. in the data segment)? */ \ - /* -#define LOOKS_LIKE_COOL_CLOSURE(p) \ - ((LOOKS_LIKE_STATIC(p)) ? \ - closure_STATIC(p) \ - : !closure_STATIC(p) && LOOKS_LIKE_PTR(p)) - */ - -#endif /* PARALLEL_RTS_H */ - -//@node Index, , Index -//@subsection Index - -//@index -//* IS_BLACK_HOLE:: @cindex\s-+IS_BLACK_HOLE -//* IS_INDIRECTION:: @cindex\s-+IS_INDIRECTION -//* end_gr_simulation:: @cindex\s-+end_gr_simulation -//* get_closure_info:: @cindex\s-+get_closure_info -//* gr_file:: @cindex\s-+gr_file -//* gr_filename:: @cindex\s-+gr_filename -//* init_gr_simulation:: @cindex\s-+init_gr_simulation -//* unwindInd:: @cindex\s-+unwindInd -//@end index diff --git a/rts/parallel/RBH.c b/rts/parallel/RBH.c deleted file mode 100644 index 1612209027..0000000000 --- a/rts/parallel/RBH.c +++ /dev/null @@ -1,337 +0,0 @@ -/* - Time-stamp: <Tue Mar 13 2001 19:07:13 Stardate: [-30]6323.98 hwloidl> - - Revertible Black Hole Manipulation. - Used in GUM and GranSim during the packing of closures. These black holes - must be revertible because a GC might occur while the packet is being - transmitted. In this case all RBHs have to be reverted. - */ - -#if defined(PAR) || defined(GRAN) /* whole file */ - -#include "Rts.h" -#include "RtsFlags.h" -#include "RtsUtils.h" -#include "GranSimRts.h" -#include "ParallelRts.h" -# if defined(DEBUG) -# include "ParallelDebug.h" -# endif -#include "Storage.h" // for recordMutable -#include "StgMacros.h" // inlined IS_... fcts - -/* - Turn a closure into a revertible black hole. After the conversion, the - first two words of the closure (after the fixed header, of course) will - be a link to the mutables list (if appropriate for the garbage - collector), and a pointer to the blocking queue. The blocking queue is - terminated by a 2-word SPEC closure which holds the original contents of - the first two words of the closure. -*/ - -//@menu -//* Externs and prototypes:: -//* Conversion Functions:: -//* Index:: -//@end menu - -//@node Externs and prototypes, Conversion Functions -//@section Externs and prototypes - -EXTFUN(stg_RBH_Save_0_info); -EXTFUN(stg_RBH_Save_1_info); -EXTFUN(stg_RBH_Save_2_info); - -//@node Conversion Functions, Index, Externs and prototypes -//@section Conversion Functions - -/* - A closure is turned into an RBH upon packing it (see PackClosure in Pack.c). - This is needed in case we have to do a GC before the packet is turned - into a graph on the PE receiving the packet. -*/ -//@cindex convertToRBH -StgClosure * -convertToRBH(closure) -StgClosure *closure; -{ - StgRBHSave *rbh_save; - StgInfoTable *info_ptr, *rbh_info_ptr, *old_info; - nat size, ptrs, nonptrs, vhs; - char str[80]; - - /* - Closure layout before this routine runs amuck: - +------------------- - | HEADER | DATA ... - +------------------- - | FIXED_HS | - */ - /* - Turn closure into an RBH. This is done by modifying the info_ptr, - grabbing the info_ptr of the RBH for this closure out of its - ITBL. Additionally, we have to save the words from the closure, which - will hold the link to the blocking queue. For this purpose we use the - RBH_Save_N closures, with N being the number of pointers for this - closure. */ - IF_GRAN_DEBUG(pack, - belch("*>:: %p (%s): Converting closure into an RBH", - closure, info_type(closure))); - IF_PAR_DEBUG(pack, - belch("*>:: %p (%s): Converting closure into an RBH", - closure, info_type(closure))); - - ASSERT(closure_THUNK(closure)); - - IF_GRAN_DEBUG(pack, - old_info = get_itbl(closure)); - - /* Allocate a new closure for the holding data ripped out of closure */ - if ((rbh_save = (StgRBHSave *)allocate(_HS + 2)) == NULL) - return NULL; /* have to Garbage Collect; check that in the caller! */ - - info_ptr = get_closure_info(closure, &size, &ptrs, &nonptrs, &vhs, str); - ASSERT(size >= _HS+MIN_UPD_SIZE); - - /* Fill in the RBH_Save closure with the original data from closure */ - rbh_save->payload[0] = (StgPtr) ((StgRBH *)closure)->blocking_queue; - rbh_save->payload[1] = (StgPtr) ((StgRBH *)closure)->mut_link; - - /* Set the info_ptr for the rbh_Save closure according to the number of - pointers in the original */ - - rbh_info_ptr = (StgInfoTable *) (ptrs == 0 ? &stg_RBH_Save_0_info : - ptrs == 1 ? &stg_RBH_Save_1_info : - &stg_RBH_Save_2_info); - SET_INFO(rbh_save, rbh_info_ptr); - /* same bitmask as the original closure */ - SET_GRAN_HDR(rbh_save, PROCS(closure)); - - /* Init the blocking queue of the RBH and have it point to the saved data */ - ((StgRBH *)closure)->blocking_queue = (StgBlockingQueueElement *)rbh_save; - - ASSERT(LOOKS_LIKE_GHC_INFO(RBH_INFOPTR(get_itbl(closure)))); - /* Turn the closure into a RBH; a great system, indeed! */ - SET_INFO(closure, RBH_INFOPTR(get_itbl(closure))); - - /* - add closure to the mutable list! - do this after having turned the closure into an RBH, because an - RBH is mutable but the closure it was before wasn't mutable - */ - recordMutable((StgMutClosure *)closure); - - //IF_GRAN_DEBUG(pack, - /* sanity check; make sure that reverting the RBH yields the - orig closure, again */ - //ASSERT(REVERT_INFOPTR(get_itbl(closure))==old_info)); - - /* - Closure layout after this routine has run amuck: - +--------------------- - | RBH-HEADER | | | ... - +--------------|---|-- - | FIXED_HS | | v - | Mutable-list ie another StgMutClosure - v - +--------- - | RBH_SAVE with 0-2 words of DATA - +--------- - */ - - return closure; -} - -/* - An RBH closure is turned into a FETCH_ME when reveiving an ACK message - indicating that the transferred closure has been unpacked on the other PE - (see processAck in HLComms.c). The ACK also contains the new GA of the - closure to which the FETCH_ME closure has to point. - - Converting a closure to a FetchMe is trivial, unless the closure has - acquired a blocking queue. If that has happened, we first have to awaken - the blocking queue. What a nuisance! Fortunately, @AwakenBlockingQueue@ - should now know what to do. - - A note on GrAnSim: In GrAnSim we don't have FetchMe closures. However, - we have to turn a RBH back to its original form when the simulated - transfer of the closure has been finished. Therefore we need the - @convertFromRBH@ routine below. After converting the RBH back to its - original form and awakening all TSOs, the first TSO will reenter the - closure which is now local and carry on merrily reducing it (the other - TSO will be less merrily blocked on the now local closure; we're costing - the difference between local and global blocks in the BQ code). -- HWL -*/ - -# if defined(PAR) - -EXTFUN(stg_FETCH_ME_info); - -//@cindex convertToFetchMe -void -convertToFetchMe(rbh, ga) -StgRBH *rbh; -globalAddr *ga; -{ - // StgInfoTable *ip = get_itbl(rbh); - StgBlockingQueueElement *bqe = rbh->blocking_queue; - - ASSERT(get_itbl(rbh)->type==RBH); - - IF_PAR_DEBUG(pack, - belch("**:: Converting RBH %p (%s) into a FETCH_ME for GA ((%x, %d, %x))", - rbh, info_type(rbh), - ga->payload.gc.gtid, ga->payload.gc.slot, ga->weight)); - - /* put closure on mutables list, while it is still a RBH */ - recordMutable((StgMutClosure *)rbh); - - /* actually turn it into a FETCH_ME */ - SET_INFO((StgClosure *)rbh, &stg_FETCH_ME_info); - - /* set the global pointer in the FETCH_ME closure to the given value */ - ((StgFetchMe *)rbh)->ga = ga; - - IF_PAR_DEBUG(pack, - if (get_itbl(bqe)->type==TSO || get_itbl(bqe)->type==BLOCKED_FETCH) - belch("**:: Awakening non-empty BQ of RBH closure %p (first TSO is %d (%p)", - rbh, ((StgTSO *)bqe)->id, ((StgTSO *)bqe))); - - /* awaken all TSOs and BLOCKED_FETCHES on the blocking queue */ - if (get_itbl(bqe)->type==TSO || get_itbl(bqe)->type==BLOCKED_FETCH) - awakenBlockedQueue(bqe, (StgClosure *)rbh); -} -# else /* GRAN */ -/* Prototype */ -// void UnlinkFromMUT(StgPtr closure); - -/* - This routine in fact reverts the RBH into its original form; this code - should be of interest for GUM, too, but is not needed in the current version. - convertFromRBH is called where GUM uses convertToFetchMe. -*/ -void -convertFromRBH(closure) -StgClosure *closure; -{ - StgBlockingQueueElement *bqe = ((StgRBH*)closure)->blocking_queue; - char str[NODE_STR_LEN]; // debugging only - StgInfoTable *rip = REVERT_INFOPTR(get_itbl(closure)); // debugging only - - IF_GRAN_DEBUG(pack, - if (get_itbl(bqe)->type==TSO) - sprintf(str, "%d (%p)", - ((StgTSO *)bqe)->id, ((StgTSO *)bqe)); - else - strcpy(str, "empty"); - belch("*<:: Reverting RBH %p (%s) into a ??? closure again; BQ start: %s", - closure, info_type(closure), str)); - - ASSERT(get_itbl(closure)->type==RBH); - - /* awakenBlockedQueue also restores the RBH_Save closure - (have to call it even if there are no TSOs in the queue!) */ - awakenBlockedQueue(bqe, closure); - - /* Put back old info pointer (grabbed from the RBH's info table). - We do that *after* awakening the BQ to be sure node is an RBH when - calling awakenBlockedQueue (different in GUM!) - */ - SET_INFO(closure, REVERT_INFOPTR(get_itbl(closure))); - - /* put closure on mutables list */ - recordMutable((StgMutClosure *)closure); - -# if 0 /* rest of this fct */ - /* ngoq ngo' */ - /* FETCHME_GA(closure) = ga; */ - if (IS_MUTABLE(INFO_PTR(bqe))) { - PROC old_proc = CurrentProc, /* NB: For AwakenBlockingQueue, */ - new_proc = where_is(closure); /* CurentProc must be where */ - /* closure lives. */ - CurrentProc = new_proc; - -# if defined(GRAN_CHECK) - if (RTSflags.GranFlags.debug & 0x100) - fprintf(stderr,"===== AwBQ of node 0x%lx (%s) [PE %2u]\n", - closure, (isSpec ? "SPEC_RBH" : "GEN_RBH"), new_proc); -# endif - - rbh_save = AwakenBlockingQueue(bqe); /* AwakenBlockingQueue(bqe); */ - CurrentProc = old_proc; - } else { - rbh_save = bqe; - } - - /* Put data from special RBH save closures back into the closure */ - if ( rbh_save == NULL ) { - fprintf(stderr,"convertFromRBH: No RBH_Save_? closure found at end of BQ!\n"); - EXIT(EXIT_FAILURE); - } else { - closure[isSpec ? SPEC_HS : GEN_HS] = rbh_save[SPEC_HS]; - closure[(isSpec ? SPEC_HS : GEN_HS) + 1] = rbh_save[SPEC_HS + 1]; - } -# endif /* 0 */ - -# if 0 && (defined(GCap) || defined(GCgn)) - /* ngoq ngo' */ - /* If we convert from an RBH in the old generation, - we have to make sure it goes on the mutables list */ - - if(closure <= StorageMgrInfo.OldLim) { - if (IS_MUTABLE(INFO_PTR(closure)) && MUT_LINK(closure) == MUT_NOT_LINKED) { - MUT_LINK(closure) = (StgWord) StorageMgrInfo.OldMutables; - StorageMgrInfo.OldMutables = closure; - } - } -# endif /* 0 */ -} -#endif /* PAR */ - -/* Remove closure from the mutables list */ -#if 0 -/* ngoq ngo' */ -void -UnlinkFromMUT(StgPtr closure) -{ - StgPtr curr = StorageMgrInfo.OldMutables, prev = NULL; - - while (curr != NULL && curr != closure) { - ASSERT(MUT_LINK(curr)!=MUT_NOT_LINKED); - prev=curr; - curr=MUT_LINK(curr); - } - if (curr==closure) { - if (prev==NULL) - StorageMgrInfo.OldMutables = MUT_LINK(curr); - else - MUT_LINK(prev) = MUT_LINK(curr); - MUT_LINK(curr) = MUT_NOT_LINKED; - } - -# if 0 && (defined(GCap) || defined(GCgn)) - { - closq newclos; - extern closq ex_RBH_q; - - newclos = (closq) stgMallocBytes(sizeof(struct clos), "UnlinkFromMUT"); - CLOS_CLOSURE(newclos) = closure; - CLOS_PREV(newclos) = NULL; - CLOS_NEXT(newclos) = ex_RBH_q; - if (ex_RBH_q!=NULL) - CLOS_PREV(ex_RBH_q) = newclos; - ex_RBH_q = newclos; - } -# endif -} -#endif /* PAR */ - -#endif /* PAR || GRAN -- whole file */ - -//@node Index, , Conversion Functions -//@section Index - -//@index -//* convertToFetchMe:: @cindex\s-+convertToFetchMe -//* convertToRBH:: @cindex\s-+convertToRBH -//@end index diff --git a/rts/parallel/SysMan.c b/rts/parallel/SysMan.c deleted file mode 100644 index 40bcf6a19e..0000000000 --- a/rts/parallel/SysMan.c +++ /dev/null @@ -1,650 +0,0 @@ -/* ---------------------------------------------------------------------------- - Time-stamp: <Wed Mar 21 2001 17:16:28 Stardate: [-30]6363.59 hwloidl> - - GUM System Manager Program - Handles startup, shutdown and global synchronisation of the parallel system. - - The Parade/AQUA Projects, Glasgow University, 1994-1995. - GdH/APART Projects, Heriot-Watt University, Edinburgh, 1997-2000. - - ------------------------------------------------------------------------- */ - -//@node GUM System Manager Program, , , -//@section GUM System Manager Program - -//@menu -//* General docu:: -//* Includes:: -//* Macros etc:: -//* Variables:: -//* Prototypes:: -//* Aux startup and shutdown fcts:: -//* Main fct:: -//* Message handlers:: -//* Auxiliary fcts:: -//* Index:: -//@end menu - -//@node General docu, Includes, GUM System Manager Program, GUM System Manager Program -//@subsection General docu - -/* -The Sysman task currently controls initiation, termination, of a -parallel Haskell program running under GUM. In the future it may -control global GC synchronisation and statistics gathering. Based on -K. Hammond's SysMan.lc in Graph for PVM. SysMan is unusual in that it -is not part of the executable produced by ghc: it is a free-standing -program that spawns PVM tasks (logical PEs) to evaluate the -program. After initialisation it runs in parallel with the PE tasks, -awaiting messages. - -OK children, buckle down for some serious weirdness, it works like this ... - -o The argument vector (argv) for SysMan has one the following 2 shapes: - -------------------------------------------------------------------------------- -| SysMan path | debug flag | pvm-executable path | Num. PEs | Program Args ...| -------------------------------------------------------------------------------- - -------------------------------------------------------------------- -| SysMan path | pvm-executable path | Num. PEs | Program Args ... | -------------------------------------------------------------------- - -The "pvm-executable path" is an absolute path of where PVM stashes the -code for each PE. The arguments passed on to each PE-executable -spawned by PVM are: - -------------------------------- -| Num. PEs | Program Args ... | -------------------------------- - -The arguments passed to the Main-thread PE-executable are - -------------------------------------------------------------------- -| main flag | pvm-executable path | Num. PEs | Program Args ... | -------------------------------------------------------------------- - -o SysMan's algorithm is as follows. - -o use PVM to spawn (nPE-1) PVM tasks -o fork SysMan to create the main-thread PE. This permits the main-thread to - read and write to stdin and stdout. -o Wait for all the PE-tasks to reply back saying they are ready and if they were the - main thread or not. -o Broadcast an array of the PE task-ids out to all of the PE-tasks. -o Enter a loop awaiting incoming messages, e.g. failure, Garbage-collection, - termination. - -The forked Main-thread algorithm, in SysMan, is as follows. - -o disconnects from PVM. -o sets a flag in argv to indicate that it is the main thread. -o `exec's a copy of the pvm-executable (i.e. the program being run) - - -The pvm-executable run by each PE-task, is initialised as follows. - -o Registers with PVM, obtaining a task-id. -o If it was main it gets SysMan's task-id from argv otherwise it can use pvm_parent. -oSends a ready message to SysMan together with a flag indicating if it was main or not. -o Receives from SysMan the array of task-ids of the other PEs. -o If the number of task-ids sent was larger than expected then it must have been a task - generated after the rest of the program had started, so it sends its own task-id message - to all the tasks it was told about. -o Begins execution. - -*/ - -//@node Includes, Macros etc, General docu, GUM System Manager Program -//@subsection Includes - -/* Evidently not Posix */ -/* #include "PosixSource.h" */ - -#include "Rts.h" -#include "ParTypes.h" -#include "LLC.h" -#include "Parallel.h" -#include "ParallelRts.h" // stats only - -//@node Macros etc, Variables, Includes, GUM System Manager Program -//@subsection Macros etc - -/* SysMan is put on top of the GHC routine that does the RtsFlags handling. - So, we cannot use the standard macros. For the time being we use a macro - that is fixed at compile time. -*/ - -#ifdef IF_PAR_DEBUG -#undef IF_PAR_DEBUG -#endif - -/* debugging enabled */ -//#define IF_PAR_DEBUG(c,s) { s; } -/* debugging disabled */ -#define IF_PAR_DEBUG(c,s) /* nothing */ - -void *stgMallocBytes (int n, char *msg); - -//@node Variables, Prototypes, Macros etc, GUM System Manager Program -//@subsection Variables - -/* - The following definitions included so that SysMan can be linked with Low - Level Communications module (LLComms). They are not used in SysMan. -*/ -GlobalTaskId mytid; - -static unsigned PEsArrived = 0; -static GlobalTaskId gtids[MAX_PES]; -static GlobalTaskId sysman_id, sender_id; -static unsigned PEsTerminated = 0; -static rtsBool Finishing = rtsFalse; -static long PEbuffer[MAX_PES]; -nat nSpawn = 0; // current no. of spawned tasks (see gtids) -nat nPEs = 0; // number of PEs specified on startup -nat nextPE; -/* PVM-ish variables */ -char *petask, *pvmExecutable; -char **pargv; -int cc, spawn_flag = PvmTaskDefault; - -#if 0 && defined(PAR_TICKY) -/* ToDo: use allGlobalParStats to collect stats of all PEs */ -GlobalParStats *allGlobalParStats[MAX_PES]; -#endif - -//@node Prototypes, Aux startup and shutdown fcts, Variables, GUM System Manager Program -//@subsection Prototypes - -/* prototypes for message handlers called from the main loop of SysMan */ -void newPE(int nbytes, int opcode, int sender_id); -void readyPE(int nbytes, int opcode, int sender_id); -void finishPE(int nbytes, int opcode, int sender_id, int exit_code); - -//@node Aux startup and shutdown fcts, Main fct, Prototypes, GUM System Manager Program -//@subsection Aux startup and shutdown fcts - -/* - Create the PE Tasks. We spawn (nPEs-1) pvm threads: the Main Thread - (which starts execution and performs IO) is created by forking SysMan -*/ -static int -createPEs(int total_nPEs) { - int i, spawn_nPEs, iSpawn = 0, nArch, nHost; - struct pvmhostinfo *hostp; - int sysman_host; - - spawn_nPEs = total_nPEs-1; - if (spawn_nPEs > 0) { - IF_PAR_DEBUG(verbose, - fprintf(stderr, "==== [%x] Spawning %d PEs(%s) ...\n", - sysman_id, spawn_nPEs, petask); - fprintf(stderr, " args: "); - for (i = 0; pargv[i]; ++i) - fprintf(stderr, "%s, ", pargv[i]); - fprintf(stderr, "\n")); - - pvm_config(&nHost,&nArch,&hostp); - sysman_host=pvm_tidtohost(sysman_id); - - /* create PEs on the specific machines in the specified order! */ - for (i=0; (iSpawn<spawn_nPEs) && (i<nHost); i++) - if (hostp[i].hi_tid != sysman_host) { - checkComms(pvm_spawn(petask, pargv, spawn_flag+PvmTaskHost, - hostp[i].hi_name, 1, gtids+iSpawn), - "SysMan startup"); - IF_PAR_DEBUG(verbose, - fprintf(stderr, "==== [%x] Spawned PE %d onto %s\n", - sysman_id, i, hostp[i].hi_name)); - iSpawn++; - } - - /* create additional PEs anywhere you like */ - if (iSpawn<spawn_nPEs) { - checkComms(pvm_spawn(petask, pargv, spawn_flag, "", - spawn_nPEs-iSpawn, gtids+iSpawn), - "SysMan startup"); - IF_PAR_DEBUG(verbose, - fprintf(stderr,"==== [%x] Spawned %d additional PEs anywhere\n", - sysman_id, spawn_nPEs-iSpawn)); - } - } - -#if 0 - /* old code with random placement of PEs; make that a variant? */ -# error "Broken startup in SysMan" - { /* let pvm place the PEs anywhere; not used anymore */ - checkComms(pvm_spawn(petask, pargv, spawn_flag, "", spawn_nPEs, gtids),"SysMan startup"); - IF_PAR_DEBUG(verbose, - fprintf(stderr,"==== [%x] Spawned\n", sysman_id)); - - } -#endif - - // iSpawn=spawn_nPEs; - - return iSpawn; -} - -/* - Check if this pvm task is in the list of tasks we spawned and are waiting - on, if so then remove it. -*/ - -static rtsBool -alreadySpawned (GlobalTaskId g) { - unsigned int i; - - for (i=0; i<nSpawn; i++) - if (g==gtids[i]) { - nSpawn--; - gtids[i] = gtids[nSpawn]; //the last takes its place - return rtsTrue; - } - return rtsFalse; -} - -static void -broadcastFinish(void) { - int i,j; - int tids[MAX_PES]; /* local buffer of all surviving PEs */ - - for (i=0, j=0; i<nPEs; i++) - if (PEbuffer[i]) - tids[j++]=PEbuffer[i]; //extract valid tids - - IF_PAR_DEBUG(verbose, - fprintf(stderr,"==== [%x] Broadcasting Finish to %d PEs; initiating shutdown\n", - sysman_id, j)); - - /* ToDo: move into LLComms.c */ - pvm_initsend(PvmDataDefault); - pvm_mcast(tids,j,PP_FINISH); -} - -static void -broadcastPEtids (void) { - nat i; - - IF_PAR_DEBUG(verbose, - fprintf(stderr,"==== [%x] SysMan sending PE table to all PEs\n", sysman_id); - /* debugging */ - fprintf(stderr,"++++ [%x] PE table as seen by SysMan:\n", mytid); - for (i = 0; i < nPEs; i++) { - fprintf(stderr,"++++ PEbuffer[%d] = %x\n", i, PEbuffer[i]); - } - ) - - broadcastOpN(PP_PETIDS, PEGROUP, nPEs, &PEbuffer); -} - -//@node Main fct, Message handlers, Aux startup and shutdown fcts, GUM System Manager Program -//@subsection Main fct - -//@cindex main -int -main (int argc, char **argv) { - int rbufid; - int opcode, nbytes, nSpawn; - unsigned int i; - - setbuf(stdout, NULL); // disable buffering of stdout - setbuf(stderr, NULL); // disable buffering of stderr - - IF_PAR_DEBUG(verbose, - fprintf(stderr, - "==== RFP: GdH enabled SysMan reporting for duty\n")); - - if (argc > 1) { - if (*argv[1] == '-') { - spawn_flag = PvmTaskDebug; - argv[1] = argv[0]; - argv++; argc--; - } - sysman_id = pvm_mytid(); /* This must be the first PVM call */ - - if (sysman_id<0) { - fprintf(stderr, "==== PVM initialisation failure\n"); - exit(EXIT_FAILURE); - } - - /* - Get the full path and filename of the pvm executable (stashed in some - PVM directory), and the number of PEs from the command line. - */ - pvmExecutable = argv[1]; - nPEs = atoi(argv[2]); - - if (nPEs==0) { - /* as usual 0 means infinity: use all PEs specified in PVM config */ - int nArch, nHost; - struct pvmhostinfo *hostp; - - /* get info on PVM config */ - pvm_config(&nHost,&nArch,&hostp); - nPEs=nHost; - sprintf(argv[2],"%d",nPEs); /* ToCheck: does this work on all archs */ - } - - /* get the name of the binary to execute */ - if ((petask = getenv(PETASK)) == NULL) // PETASK set by driver - petask = PETASK; - - IF_PAR_DEBUG(verbose, - fprintf(stderr,"==== [%x] nPEs: %d; executable: |%s|\n", - sysman_id, nPEs, petask)); - - /* Check that we can create the number of PE and IMU tasks requested. - ^^^ - This comment is most entertaining since we haven't been using IMUs - for the last 10 years or so -- HWL */ - if ((nPEs > MAX_PES) || (nPEs<1)) { - fprintf(stderr,"==** SysMan: No more than %d PEs allowed (%d requested)\n Reconfigure GUM setting MAX_PE in ghc/includes/Parallel.h to a higher value\n", - MAX_PES, nPEs); - exit(EXIT_FAILURE); - } - - IF_PAR_DEBUG(verbose, - fprintf(stderr,"==== [%x] is SysMan Task\n", sysman_id)); - - /* Initialise the PE task arguments from Sysman's arguments */ - pargv = argv + 2; - - /* Initialise list of all PE identifiers */ - PEsArrived=0; - nextPE=1; - for (i=0; i<nPEs; i++) - PEbuffer[i]=0; - - /* start up the required number of PEs */ - nSpawn = createPEs(nPEs); - - /* - Create the MainThread PE by forking SysMan. This arcane coding - is required to allow MainThread to read stdin and write to stdout. - PWT 18/1/96 - */ - //nPEs++; /* Record that the number of PEs is increasing */ - if ((cc = fork())) { - checkComms(cc,"SysMan fork"); /* Parent continues as SysMan */ - - PEbuffer[0]=0; /* we accept the first main and assume its valid. */ - PEsArrived=1; /* assume you've got main */ - - IF_PAR_DEBUG(verbose, - fprintf(stderr,"==== [%x] Sysman successfully initialized!\n", - sysman_id)); - -//@cindex message handling loop - /* ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */ - /* Main message handling loop */ - /* ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */ - /* Process incoming messages */ - while (1) { - if ((rbufid = pvm_recv(ANY_TASK, ANY_OPCODE)) < 0) { - pvm_perror("==** Sysman: Receiving Message (pvm_recv)"); - /* never reached */ - } - - pvm_bufinfo(rbufid, &nbytes, &opcode, &sender_id); - - /* very low level debugging - IF_PAR_DEBUG(verbose, - fprintf(stderr,"== [%x] SysMan: Message received by SysMan: rbufid=%x, nbytes = %d, opcode = %x, sender_id = %x\n", - sysman_id, rbufid, nbytes, opcode, sender_id)); - */ - - switch (opcode) { - - case PP_NEWPE: /* a new PE is registering for work */ - newPE(nbytes, opcode, sender_id); - break; - - case PP_READY: /* startup complete; let PEs start working */ - readyPE(nbytes, opcode, sender_id); - break; - - - case PP_GC_INIT: /* start global GC */ - /* This Function not yet implemented for GUM */ - fprintf(stderr,"==** Global GC requested by PE %x. Not yet implemented for GUM!\n", - sender_id); - break; - - case PP_STATS_ON: /* enable statistics gathering */ - fprintf(stderr,"==** PP_STATS_ON requested by %x. Not yet implemented for GUM!\n", - sender_id); - break; - - case PP_STATS_OFF: /* disable statistics gathering */ - fprintf(stderr,"==** PP_STATS_OFF requested by %x. Not yet implemented for GUM!\n", - sender_id); - break; - - case PP_FINISH: - { - int exit_code = getExitCode(nbytes, &sender_id); - finishPE(nbytes, opcode, sender_id, exit_code); - break; - - default: - { - /* - char *opname = GetOpName(opcode); - fprintf(stderr,"Sysman: Unrecognised opcode %s (%x)\n", - opname,opcode); */ - fprintf(stderr,"==** Qagh: Sysman: Unrecognised opcode (%x)\n", - opcode); - } - break; - } /* switch */ - } /* else */ - } /* while 1 */ - /* end of SysMan!! */ - } else { - /* forked main thread begins here */ - IF_PAR_DEBUG(verbose, - fprintf(stderr, "==== Main Thread PE has been forked; doing an execv(%s,...)\n", - pvmExecutable)); - pvmendtask(); // Disconnect from PVM to avoid confusion: - // executable reconnects - - // RFP: assumes that length(arvv[0])>=9 !!! - sprintf(argv[0],"-%08X",sysman_id); /*flag that its the Main Thread PE and include sysman's id*/ - execv(pvmExecutable,argv); /* Parent task becomes Main Thread PE */ - } /* else */ - } /* argc > 1 */ -} /* main */ - -//@node Message handlers, Auxiliary fcts, Main fct, GUM System Manager Program -//@subsection Message handlers - -/* - Received PP_NEWPE: - A new PE has been added to the configuration. -*/ -void -newPE(int nbytes, int opcode, int sender_id) { - IF_PAR_DEBUG(verbose, - fprintf(stderr,"==== [%x] SysMan detected a new host\n", - sysman_id)); - - /* Determine the new machine... assume its the last on the config list? */ - if (nSpawn < MAX_PES) { - int nArch,nHost; - struct pvmhostinfo *hostp; - - /* get conmfiguration of PVM machine */ - pvm_config(&nHost,&nArch,&hostp); - nHost--; - checkComms(pvm_spawn(petask, pargv, spawn_flag+PvmTaskHost, - hostp[nHost].hi_name, 1, gtids+nSpawn), - "SysMan loop"); - nSpawn++; - IF_PAR_DEBUG(verbose, - fprintf(stderr, "==== [%x] Spawned onto %s\n", - sysman_id, hostp[nHost].hi_name)); - } -} - -/* - Received PP_READY: - Let it be known that PE @sender_id@ participates in the computation. -*/ -void -readyPE(int nbytes, int opcode, int sender_id) { - int i = 0, flag = 1; - long isMain; - int nArch, nHost; - struct pvmhostinfo *hostp; - - //ASSERT(opcode==PP_READY); - - IF_PAR_DEBUG(verbose, - fprintf(stderr,"==== [%x] SysMan received PP_READY message from %x\n", - sysman_id, sender_id)); - - pvm_config(&nHost,&nArch,&hostp); - - GetArg1(isMain); - - //if ((isMain && (PEbuffer[0]==0)) || alreadySpawned(sender_id)) { - if (nPEs >= MAX_PES) { - fprintf(stderr,"==== [%x] SysMan doesn't need PE %d (max %d PEs allowed)\n", - sysman_id, sender_id, MAX_PES); - pvm_kill(sender_id); - } else { - if (isMain) { - IF_PAR_DEBUG(verbose, - fprintf(stderr,"==== [%x] SysMan found Main PE %x\n", - sysman_id, sender_id)); - PEbuffer[0]=sender_id; - } else { - /* search for PE in list of PEs */ - for(i=1; i<nPEs; i++) - if (PEbuffer[i]==sender_id) { - flag=0; - break; - } - /* it's a new PE: add it to the list of PEs */ - if (flag) - PEbuffer[nextPE++] = sender_id; - - IF_PAR_DEBUG(verbose, - fprintf(stderr,"==== [%x] SysMan: found PE %d as [%x] on host %s\n", - sysman_id, PEsArrived, sender_id, hostp[PEsArrived].hi_name)); - - PEbuffer[PEsArrived++] = sender_id; - } - - - /* enable better handling of unexpected terminations */ - checkComms( pvm_notify(PvmTaskExit, PP_FINISH, 1, &sender_id), - "SysMan loop"); - - /* finished registration of all PEs => enable notification */ - if ((PEsArrived==nPEs) && PEbuffer[0]) { - checkComms( pvm_notify(PvmHostAdd, PP_NEWPE, -1, 0), - "SysMan startup"); - IF_PAR_DEBUG(verbose, - fprintf(stderr,"==== [%x] SysMan initialising notificaton for new hosts\n", sysman_id)); - } - - /* finished notification => send off the PE ids */ - if ((PEsArrived>=nPEs) && PEbuffer[0]) { - if (PEsArrived>nPEs) { - IF_PAR_DEBUG(verbose, - fprintf(stderr,"==== [%x] Weird: %d PEs registered, but we only asked for %d\n", sysman_id, PEsArrived, nPEs)); - // nPEs=PEsArrived; - } - broadcastPEtids(); - } - } -} - -/* - Received PP_FINISH: - Shut down the corresponding PE. Check whether it is a regular shutdown - or an uncontrolled termination. -*/ -void -finishPE(int nbytes, int opcode, int sender_id, int exitCode) { - int i; - - IF_PAR_DEBUG(verbose, - fprintf(stderr,"==== [%x] SysMan received PP_FINISH message from %x (exit code: %d)\n", - sysman_id, sender_id, exitCode)); - - /* Is it relevant to us? Count the first message */ - for (i=0; i<nPEs; i++) - if (PEbuffer[i] == sender_id) { - PEsTerminated++; - PEbuffer[i]=0; - - /* handle exit code */ - if (exitCode<0) { /* a task exit before a controlled finish? */ - fprintf(stderr,"==== [%x] Termination at %x with exit(%d)\n", - sysman_id, sender_id, exitCode); - } else if (exitCode>0) { /* an abnormal exit code? */ - fprintf(stderr,"==== [%x] Uncontrolled termination at %x with exit(%d)\n", - sysman_id, sender_id, exitCode); - } else if (!Finishing) { /* exitCode==0 which is good news */ - if (i!=0) { /* someone other than main PE terminated first? */ - fprintf(stderr,"==== [%x] Unexpected early termination at %x\n", - sysman_id, sender_id); - } else { - /* start shutdown by broadcasting FINISH to other PEs */ - IF_PAR_DEBUG(verbose, - fprintf(stderr,"==== [%x] Initiating shutdown (requested by [%x] RIP) (exit code: %d)\n", sysman_id, sender_id, exitCode)); - Finishing = rtsTrue; - broadcastFinish(); - } - } else { - /* we are in a shutdown already */ - IF_PAR_DEBUG(verbose, - fprintf(stderr,"==== [%x] Finish from %x during shutdown (%d PEs terminated so far; %d total)\n", - sysman_id, sender_id, PEsTerminated, nPEs)); - } - - if (PEsTerminated >= nPEs) { - IF_PAR_DEBUG(verbose, - fprintf(stderr,"==== [%x] Global Shutdown, Goodbye!! (SysMan has received FINISHes from all PEs)\n", sysman_id)); - //broadcastFinish(); - /* received finish from everybody; now, we can exit, too */ - exit(EXIT_SUCCESS); /* Qapla'! */ - } - } -} - -//@node Auxiliary fcts, Index, Message handlers, GUM System Manager Program -//@subsection Auxiliary fcts - -/* Needed here because its used in loads of places like LLComms etc */ - -//@cindex stg_exit - -/* - * called from STG-land to exit the program - */ - -void -stg_exit(I_ n) -{ - fprintf(stderr, "==// [%x] %s in SysMan code; sending PP_FINISH to all PEs ...\n", - mytid,(n!=0)?"FAILURE":"FINISH"); - broadcastFinish(); - //broadcastFinish(); - pvm_exit(); - exit(n); -} - -//@node Index, , Auxiliary fcts, GUM System Manager Program -//@subsection Index - -//@index -//* main:: @cindex\s-+main -//* message handling loop:: @cindex\s-+message handling loop -//* stgMallocBytes:: @cindex\s-+stgMallocBytes -//* stg_exit:: @cindex\s-+stg_exit -//@end index |