+++ /dev/null
-%
-% (c) The GRASP/AQUA Project, Glasgow University, 1992-1995
-%
-%************************************************************************
-%* *
-\section[Threads.lc]{Thread Control Routines}
-%* *
-%************************************************************************
-
-%************************************************************************
-%
-\subsection[thread-overview]{Overview of the Thread Management System}
-%
-%************************************************************************
-
-%************************************************************************
-%
-\subsection[thread-decls]{Thread Declarations}
-%
-%************************************************************************
-
-% I haven't checked if GRAN can work with QP profiling. But as we use our
-% own profiling (GR profiling) that should be irrelevant. -- HWL
-
-NOTE: There's currently a couple of x86 only pieces in here. The reason
-for this is the need for an expedient hack to make Concurrent Haskell
-and stable pointers work sufficiently for Win32 applications.
-(the changes in here are not x86 specific, but other parts of this patch are
-(see PerformIO.lhc))
-
-ToDo: generalise to all platforms
-
-\begin{code}
-
-#if defined(CONCURRENT) /* the whole module! */
-
-#if !defined(_AIX)
-# define NON_POSIX_SOURCE /* so says Solaris */
-#endif
-
-# include "rtsdefs.h"
-# include <setjmp.h>
-
-#include "LLC.h"
-#include "HLC.h"
-
-static void init_qp_profiling(STG_NO_ARGS); /* forward decl */
-\end{code}
-
-@AvailableStack@ is used to determine whether an existing stack can be
-reused without new allocation, so reducing garbage collection, and
-stack setup time. At present, it is only used for the first stack
-chunk of a thread, the one that's got
-@RTSflags.ConcFlags.stkChunkSize@ words.
-
-\begin{code}
-P_ AvailableStack = PrelBase_Z91Z93_closure;
-P_ AvailableTSO = PrelBase_Z91Z93_closure;
-\end{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,
-on which 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
-
-{{GranSim.lc}Daq ngoq' roQlu'ta'}
-(Code has been moved to GranSim.lc).
-
-%****************************************************************
-%* *
-\subsection[thread-getthread]{The Thread Scheduler}
-%* *
-%****************************************************************
-
-This is the heart of the thread scheduling code.
-
-Most of the changes for GranSim are in this part of the RTS.
-Especially the @ReSchedule@ routine has been blown up quite a lot
-It now contains the top-level event-handling loop.
-
-Parts of the code that are not necessary for GranSim, but convenient to
-have when developing it are marked with a @GRAN_CHECK@ variable.
-
-\begin{code}
-STGRegisterTable *CurrentRegTable = NULL;
-P_ CurrentTSO = NULL;
-
-#if defined(GRAN)
-
-/* Only needed for GranSim Light; costs of operations during rescheduling
- are associated to the virtual processor on which ActiveTSO is living */
-P_ ActiveTSO = NULL;
-rtsBool resched = rtsFalse; /* debugging only !!*/
-
-/* Pointers to the head and tail of the runnable queues for each PE */
-/* In GranSim Light only the thread/spark-queues of proc 0 are used */
-P_ RunnableThreadsHd[MAX_PROC];
-P_ RunnableThreadsTl[MAX_PROC];
-
-P_ WaitThreadsHd[MAX_PROC];
-P_ WaitThreadsTl[MAX_PROC];
-
-sparkq PendingSparksHd[MAX_PROC][SPARK_POOLS];
-sparkq PendingSparksTl[MAX_PROC][SPARK_POOLS];
-
-/* One clock for each PE */
-W_ CurrentTime[MAX_PROC];
-
-/* Useful to restrict communication; cf fishing model in GUM */
-I_ OutstandingFetches[MAX_PROC], OutstandingFishes[MAX_PROC];
-
-/* Status of each PE (new since but independent of GranSim Light) */
-enum proc_status 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 */
-P_ BlockedOnFetch[MAX_PROC];
-#endif
-
-W_ SparksAvail = 0; /* How many sparks are available */
-W_ SurplusThreads = 0; /* How many excess threads are there */
-
-TIME SparkStealTime();
-
-# else /* !GRAN */
-
-P_ RunnableThreadsHd = PrelBase_Z91Z93_closure;
-P_ RunnableThreadsTl = PrelBase_Z91Z93_closure;
-
-P_ WaitingThreadsHd = PrelBase_Z91Z93_closure;
-P_ WaitingThreadsTl = PrelBase_Z91Z93_closure;
-
-TYPE_OF_SPARK PendingSparksBase[SPARK_POOLS];
-TYPE_OF_SPARK PendingSparksLim[SPARK_POOLS];
-
-TYPE_OF_SPARK PendingSparksHd[SPARK_POOLS];
-TYPE_OF_SPARK PendingSparksTl[SPARK_POOLS];
-
-#endif /* GRAN ; HWL */
-
-static jmp_buf scheduler_loop;
-#if defined(i386_TARGET_ARCH)
-void SchedLoop(int ret);
-extern StgInt entersFromC;
-static jmp_buf finish_sched;
-#endif
-
-I_ required_thread_count = 0;
-I_ advisory_thread_count = 0;
-
-EXTFUN(resumeThread);
-
-/* Misc prototypes */
-#if defined(GRAN)
-P_ NewThread PROTO((P_, W_, I_));
-I_ blockFetch PROTO((P_, PROC, P_));
-I_ HandleFetchRequest PROTO((P_, PROC, P_));
-rtsBool InsertThread PROTO((P_ tso));
-sparkq delete_from_spark_queue PROTO((sparkq, sparkq));
-sparkq prev, spark;
-#else
-P_ NewThread PROTO((P_, W_));
-#endif
-
-I_ context_switch = 0;
-I_ contextSwitchTime = 10000;
-
-I_ threadId = 0;
-
-/* NB: GRAN and GUM use different representations of spark pools.
- GRAN sparks are more flexible (containing e.g. granularity info)
- but slower than GUM sparks. There is no fixed upper bound on the
- number of GRAN sparks either. -- HWL
-*/
-#if defined(PAR)
-
-I_ sparksIgnored =0, sparksCreated = 0;
-
-#endif
-
-#if defined(CONCURRENT) && !defined(GRAN)
-I_ SparkLimit[SPARK_POOLS];
-
-rtsBool
-initThreadPools(STG_NO_ARGS)
-{
- I_ i, size = RTSflags.ConcFlags.maxLocalSparks;
-
- SparkLimit[ADVISORY_POOL] = SparkLimit[REQUIRED_POOL] = size;
-
- if ((PendingSparksBase[ADVISORY_POOL] = (TYPE_OF_SPARK) malloc(size * SIZE_OF_SPARK)) == NULL)
- return rtsFalse;
-
- if ((PendingSparksBase[REQUIRED_POOL] = (TYPE_OF_SPARK) malloc(size * SIZE_OF_SPARK)) == NULL)
- return rtsFalse;
- PendingSparksLim[ADVISORY_POOL] = PendingSparksBase[ADVISORY_POOL] + size;
- PendingSparksLim[REQUIRED_POOL] = PendingSparksBase[REQUIRED_POOL] + size;
- return rtsTrue;
-
-}
-#endif
-
-#ifdef PAR
-rtsBool sameThread;
-#endif
-
-void
-ScheduleThreads(topClosure)
-P_ topClosure;
-{
-#ifdef GRAN
- I_ i;
-#endif
- P_ tso;
-
-#if defined(PROFILING) || defined(PAR)
- if (time_profiling || RTSflags.ConcFlags.ctxtSwitchTime > 0) {
- if (initialize_virtual_timer(RTSflags.CcFlags.msecsPerTick)) {
-#else
- if (RTSflags.ConcFlags.ctxtSwitchTime > 0) {
- if (initialize_virtual_timer(RTSflags.ConcFlags.ctxtSwitchTime)) {
-#endif
- fflush(stdout);
- fprintf(stderr, "Can't initialize virtual timer.\n");
- EXIT(EXIT_FAILURE);
- }
- } else
- context_switch = 0 /* 1 HWL */;
-
-# if defined(GRAN_CHECK) && defined(GRAN) /* HWL */
- if ( RTSflags.GranFlags.Light && RTSflags.GranFlags.proc!=1 ) {
- fprintf(stderr,"Qagh: In GrAnSim Light setup .proc must be 1\n");
- EXIT(EXIT_FAILURE);
- }
-
- if ( RTSflags.GranFlags.debug & 0x40 ) {
- fprintf(stderr,"Doing init in ScheduleThreads now ...\n");
- }
-# endif
-
-#if defined(GRAN) /* KH */
- /* Init thread and spark queues on all processors */
- for (i=0; i<RTSflags.GranFlags.proc; i++)
- {
- /* Init of RunnableThreads{Hd,Tl} etc now in main */
- OutstandingFetches[i] = OutstandingFishes[i] = 0;
- procStatus[i] = Idle;
-# if defined(GRAN_CHECK) && defined(GRAN) /* HWL */
- BlockedOnFetch[i] = NULL;
-# endif
- }
-
- CurrentProc = MainProc;
-#endif /* GRAN */
-
- if (DO_QP_PROF)
- init_qp_profiling();
- /*
- * We perform GC so that a signal handler can install a new
- * TopClosure and start a new main thread.
- */
-#ifdef PAR
- if (IAmMainThread) {
-#endif
-#if defined(GRAN)
- if ((tso = NewThread(topClosure, T_MAIN, MAIN_PRI)) == NULL) {
-#else
- if ((tso = NewThread(topClosure, T_MAIN)) == NULL) {
-#endif
- /* kludge to save the top closure as a root */
- CurrentTSO = topClosure;
- ReallyPerformThreadGC(0, rtsTrue);
- topClosure = CurrentTSO;
-#if defined(GRAN)
- if ((tso = NewThread(topClosure, T_MAIN, MAIN_PRI)) == NULL) {
-#else
- if ((tso = NewThread(topClosure, T_MAIN)) == NULL) {
-#endif
- fflush(stdout);
- fprintf(stderr, "Not enough heap for main thread\n");
- EXIT(EXIT_FAILURE);
- }
- }
-#if !defined(GRAN)
- RunnableThreadsHd = RunnableThreadsTl = tso;
-#else
- /* NB: CurrentProc must have been set to MainProc before that! -- HWL */
- ThreadQueueHd = ThreadQueueTl = tso;
-
-# if defined(GRAN_CHECK)
- if ( RTSflags.GranFlags.debug & 0x40 ) {
- fprintf(stderr,"MainTSO has been initialized (0x%x)\n", tso);
- }
-# endif
-#endif /* GRAN */
-
-#ifdef PAR
- if (RTSflags.ParFlags.granSimStats) {
- DumpGranEvent(GR_START, tso);
- sameThread = rtsTrue;
- }
-#elif defined(GRAN)
- if (RTSflags.GranFlags.granSimStats && !RTSflags.GranFlags.labelling)
- DumpRawGranEvent(CurrentProc,(PROC)0,GR_START,
- tso,topClosure,0);
-#endif
-
-#if defined(GRAN)
- MAKE_BUSY(MainProc); /* Everything except the main PE is idle */
- if (RTSflags.GranFlags.Light)
- ActiveTSO = tso;
-#endif
-
- required_thread_count = 1;
- advisory_thread_count = 0;
-#ifdef PAR
- } /*if IAmMainThread ...*/
-#endif
-#if defined(i386_TARGET_ARCH)
- if (setjmp(finish_sched) < 0) {
- return;
- }
- SchedLoop(0);
-}
- /* ----------------------------------------------------------------- */
- /* This part is the MAIN SCHEDULER LOOP; jumped at from ReSchedule */
- /* ----------------------------------------------------------------- */
-
-void
-SchedLoop(ret)
-int ret;
-{
- P_ tso;
-
- if ( (ret <0) || ( (setjmp(scheduler_loop) < 0) )) {
- longjmp(finish_sched,-1);
- }
-#else
- if( (setjmp(scheduler_loop) < 0) ) {
- return;
- }
-#endif
-
-#if defined(GRAN) && defined(GRAN_CHECK)
- if ( RTSflags.GranFlags.debug & 0x80 ) {
- fprintf(stderr,"MAIN Schedule Loop; ThreadQueueHd is ");
- G_TSO(ThreadQueueHd,1);
- /* if (ThreadQueueHd == MainTSO) {
- fprintf(stderr,"D> Event Queue is now:\n");
- GEQ();
- } */
- }
-#endif
-
-#ifdef PAR
- if (PendingFetches != PrelBase_Z91Z93_closure) {
- processFetches();
- }
-
-#elif defined(GRAN)
- if (ThreadQueueHd == PrelBase_Z91Z93_closure) {
- fprintf(stderr, "Qu'vatlh! No runnable threads!\n");
- EXIT(EXIT_FAILURE);
- }
- if (DO_QP_PROF > 1 && CurrentTSO != ThreadQueueHd) {
- QP_Event1("AG", ThreadQueueHd);
- }
-#else
- while (RunnableThreadsHd == PrelBase_Z91Z93_closure) {
- /* If we've no work */
- if (WaitingThreadsHd == PrelBase_Z91Z93_closure) {
- int exitc;
-
- exitc = NoRunnableThreadsHook();
- shutdownHaskell();
- EXIT(exitc);
- }
- /* Block indef. waiting for I/O and timer expire */
- AwaitEvent(0);
- }
-#endif
-
-#ifdef PAR
- if (RunnableThreadsHd == PrelBase_Z91Z93_closure) {
- if (advisory_thread_count < RTSflags.ConcFlags.maxThreads &&
- (PendingSparksHd[REQUIRED_POOL] < PendingSparksTl[REQUIRED_POOL] ||
- PendingSparksHd[ADVISORY_POOL] < PendingSparksTl[ADVISORY_POOL])) {
- /*
- * If we're here (no runnable threads) and we have pending
- * sparks, we must have a space problem. Get enough space
- * to turn one of those pending sparks into a
- * thread... ReallyPerformGC doesn't return until the
- * space is available, so it may force global GC. ToDo:
- * Is this unnecessary here? Duplicated in ReSchedule()?
- * --JSM
- */
- ReallyPerformThreadGC(THREAD_SPACE_REQUIRED, rtsTrue);
- SAVE_Hp -= THREAD_SPACE_REQUIRED;
- } else {
- /*
- * We really have absolutely no work. Send out a fish
- * (there may be some out there already), and wait for
- * something to arrive. We clearly can't run any threads
- * until a SCHEDULE or RESUME arrives, and so that's what
- * we're hoping to see. (Of course, we still have to
- * respond to other types of messages.)
- */
- if (!fishing)
- sendFish(choosePE(), mytid, NEW_FISH_AGE, NEW_FISH_HISTORY,
- NEW_FISH_HUNGER);
-
- processMessages();
- }
- ReSchedule(0);
- } else if (PacketsWaiting()) { /* Look for incoming messages */
- processMessages();
- }
-#endif /* PAR */
-
-#if !defined(GRAN)
- if (DO_QP_PROF > 1 && CurrentTSO != RunnableThreadsHd) {
- QP_Event1("AG", RunnableThreadsHd);
-}
-#endif
-
-#ifdef PAR
- if (RTSflags.ParFlags.granSimStats && !sameThread)
- DumpGranEvent(GR_SCHEDULE, RunnableThreadsHd);
-#endif
-
-#if defined(GRAN)
- TimeOfNextEvent = get_time_of_next_event();
- CurrentTSO = ThreadQueueHd;
- if (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 &&
- RTSflags.GranFlags.debug & 0x20000)
- DumpGranEvent(GR_SYSTEM_END,ActiveTSO);
- }
- TSO_CLOCK(ActiveTSO) = CurrentTime[CurrentProc];
- ActiveTSO = NULL;
- CurrentTime[CurrentProc] = TSO_CLOCK(CurrentTSO);
- if(RTSflags.GranFlags.DoFairSchedule && resched )
- {
- resched = rtsFalse;
- if (RTSflags.GranFlags.granSimStats &&
- RTSflags.GranFlags.debug & 0x20000)
- DumpGranEvent(GR_SCHEDULE,ThreadQueueHd);
- }
- /*
- 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();
- }
- */
- }
- EndOfTimeSlice = CurrentTime[CurrentProc]+RTSflags.GranFlags.time_slice;
-#else /* !GRAN */
- CurrentTSO = RunnableThreadsHd;
- RunnableThreadsHd = TSO_LINK(RunnableThreadsHd);
- TSO_LINK(CurrentTSO) = PrelBase_Z91Z93_closure;
-
- if (RunnableThreadsHd == PrelBase_Z91Z93_closure)
- RunnableThreadsTl = PrelBase_Z91Z93_closure;
-#endif
-
- /* If we're not running a timer, just leave the flag on */
- if (RTSflags.ConcFlags.ctxtSwitchTime > 0)
- context_switch = 0;
-
-#if defined(GRAN_CHECK) && defined(GRAN) /* Just for testing */
- if (CurrentTSO == PrelBase_Z91Z93_closure) {
- fprintf(stderr,"Qagh: Trying to execute PrelBase_Z91Z93_closure on proc %d (@ %d)\n",
- CurrentProc,CurrentTime[CurrentProc]);
- EXIT(EXIT_FAILURE);
- }
-
- if (RTSflags.GranFlags.debug & 0x04) {
- if (BlockedOnFetch[CurrentProc]) {
- fprintf(stderr,"Qagh: Trying to execute TSO 0x%x on proc %d (@ %d) which is blocked-on-fetch by TSO 0x%x\n",
- CurrentTSO,CurrentProc,CurrentTime[CurrentProc],BlockedOnFetch[CurrentProc]);
- EXIT(EXIT_FAILURE);
- }
- }
-
- if ( (RTSflags.GranFlags.debug & 0x10) &&
- (TSO_TYPE(CurrentTSO) & FETCH_MASK_TSO) ) {
- fprintf(stderr,"Qagh: Trying to execute TSO 0x%x on proc %d (@ %d) which should be asleep!\n",
- CurrentTSO,CurrentProc,CurrentTime[CurrentProc]);
- EXIT(EXIT_FAILURE);
- }
-#endif
-
-#if 0 && defined(i386_TARGET_ARCH)
- fprintf(stderr, "ScheduleThreads: About to resume thread:%#x %d\n",
- CurrentTSO, entersFromC);
-#endif
- miniInterpret((StgFunPtr)resumeThread);
-}
-\end{code}
-
-% Some remarks on GrAnSim -- HWL
-
-The ReSchedule fct is the heart of GrAnSim. Based on its parameter it issues
-a CONTINUETRHEAD to carry on executing the current thread in due course or it watches out for new work (e.g. called from EndThread).
-
-Then it picks the next event (get_next_event) and handles it appropriately
-(see switch construct). Note that a continue in the switch causes the next
-event to be handled and a break causes a jmp to the scheduler_loop where
-the TSO at the head of the current processor's runnable queue is executed.
-
-ReSchedule is mostly entered from HpOverflow.lc:PerformReSchedule which is
-itself called via the GRAN_RESCHEDULE macro in the compiler generated code.
-
-\begin{code}
-/*
- GrAnSim rules here! Others stay out or you will be crashed.
- Concurrent and parallel guys: please use the next door (a few pages down;
- turn left at the !GRAN sign).
-*/
-
-#if defined(GRAN)
-
-/* Prototypes of event handling functions. Only needed in ReSchedule */
-void do_the_globalblock PROTO((eventq event));
-void do_the_unblock PROTO((eventq event));
-void do_the_fetchnode PROTO((eventq event));
-void do_the_fetchreply PROTO((eventq event));
-void do_the_movethread PROTO((eventq event));
-void do_the_movespark PROTO((eventq event));
-void gimme_spark PROTO((rtsBool *found_res, sparkq *prev_res, sparkq *spark_res));
-void munch_spark PROTO((rtsBool found, sparkq prev, sparkq spark));
-
-void
-ReSchedule(what_next)
-int what_next; /* Run the current thread again? */
-{
- sparkq spark, nextspark;
- P_ tso;
- P_ node, closure;
- eventq event;
- int rc;
-
-# if defined(GRAN_CHECK) && defined(GRAN)
- if ( RTSflags.GranFlags.debug & 0x80 ) {
- fprintf(stderr,"Entering ReSchedule with mode %u; tso is\n",what_next);
- G_TSO(ThreadQueueHd,1);
- }
-# endif
-
-# if defined(GRAN_CHECK) && defined(GRAN)
- if ( (RTSflags.GranFlags.debug & 0x80) || (RTSflags.GranFlags.debug & 0x40 ) )
- if (what_next<FIND_THREAD || what_next>END_OF_WORLD)
- fprintf(stderr,"Qagh {ReSchedule}Daq: illegal parameter %u for what_next\n",
- what_next);
-# endif
-
- if (RTSflags.GranFlags.Light) {
- /* Save current time; GranSim Light only */
- TSO_CLOCK(CurrentTSO) = CurrentTime[CurrentProc];
- }
-
- /* Run the current thread again (if there is one) */
- if(what_next==SAME_THREAD && ThreadQueueHd != PrelBase_Z91Z93_closure)
- {
- /* A bit of a hassle if the event queue is empty, but ... */
- CurrentTSO = ThreadQueueHd;
-
- resched = rtsFalse;
- if (RTSflags.GranFlags.Light &&
- TSO_LINK(ThreadQueueHd)!=PrelBase_Z91Z93_closure &&
- TSO_CLOCK(ThreadQueueHd)>TSO_CLOCK(TSO_LINK(ThreadQueueHd))) {
- if(RTSflags.GranFlags.granSimStats &&
- RTSflags.GranFlags.debug & 0x20000 )
- DumpGranEvent(GR_DESCHEDULE,ThreadQueueHd);
- resched = rtsTrue;
- ThreadQueueHd = TSO_LINK(CurrentTSO);
- if (ThreadQueueHd==PrelBase_Z91Z93_closure)
- ThreadQueueTl=PrelBase_Z91Z93_closure;
- TSO_LINK(CurrentTSO) = PrelBase_Z91Z93_closure;
- InsertThread(CurrentTSO);
- }
-
- /* This code does round-Robin, if preferred. */
- if(!RTSflags.GranFlags.Light &&
- RTSflags.GranFlags.DoFairSchedule &&
- TSO_LINK(CurrentTSO) != PrelBase_Z91Z93_closure &&
- CurrentTime[CurrentProc]>=EndOfTimeSlice)
- {
- ThreadQueueHd = TSO_LINK(CurrentTSO);
- TSO_LINK(ThreadQueueTl) = CurrentTSO;
- ThreadQueueTl = CurrentTSO;
- TSO_LINK(CurrentTSO) = PrelBase_Z91Z93_closure;
- CurrentTime[CurrentProc] += RTSflags.GranFlags.gran_threadcontextswitchtime;
- if ( RTSflags.GranFlags.granSimStats )
- DumpGranEvent(GR_SCHEDULE,ThreadQueueHd);
- CurrentTSO = ThreadQueueHd;
- }
-
- new_event(CurrentProc,CurrentProc,CurrentTime[CurrentProc],
- CONTINUETHREAD,CurrentTSO,PrelBase_Z91Z93_closure,NULL);
- }
- /* Schedule `next thread' which is at ThreadQueueHd now i.e. thread queue */
- /* has been updated before that already. */
- else if(what_next==NEW_THREAD && ThreadQueueHd != PrelBase_Z91Z93_closure)
- {
-# if defined(GRAN_CHECK) && defined(GRAN)
- fprintf(stderr,"Qagh: ReSchedule(NEW_THREAD) shouldn't be used with DoReScheduleOnFetch!!\n");
- EXIT(EXIT_FAILURE);
-
-# endif
-
- if(RTSflags.GranFlags.granSimStats &&
- (!RTSflags.GranFlags.Light || RTSflags.GranFlags.debug & 0x20000) )
- DumpGranEvent(GR_SCHEDULE,ThreadQueueHd);
-
- CurrentTSO = ThreadQueueHd;
- new_event(CurrentProc,CurrentProc,CurrentTime[CurrentProc],
- CONTINUETHREAD,CurrentTSO,PrelBase_Z91Z93_closure,NULL);
-
- CurrentTime[CurrentProc] += RTSflags.GranFlags.gran_threadcontextswitchtime;
- }
-
- /* We go in here if the current thread is blocked on fetch => don'd CONT */
- else if(what_next==CHANGE_THREAD)
- {
- /* just fall into event handling loop for next event */
- }
-
- /* We go in here if we have no runnable threads or what_next==0 */
- else
- {
- procStatus[CurrentProc] = Idle;
- /* That's now done in HandleIdlePEs!
- new_event(CurrentProc,CurrentProc,CurrentTime[CurrentProc],
- FINDWORK,PrelBase_Z91Z93_closure,PrelBase_Z91Z93_closure,NULL);
- */
- CurrentTSO = PrelBase_Z91Z93_closure;
- }
-
- /* ----------------------------------------------------------------- */
- /* This part is the EVENT HANDLING LOOP */
- /* ----------------------------------------------------------------- */
-
- do {
- /* Choose the processor with the next event */
- event = get_next_event();
- CurrentProc = EVENT_PROC(event);
- CurrentTSO = EVENT_TSO(event);
- if (RTSflags.GranFlags.Light) {
- P_ tso;
- W_ tmp;
- /* 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 */
- TSO_CLOCK(ActiveTSO) = CurrentTime[CurrentProc];
- if (RTSflags.GranFlags.DoFairSchedule)
- {
- if (RTSflags.GranFlags.granSimStats &&
- RTSflags.GranFlags.debug & 0x20000)
- DumpGranEvent(GR_SYSTEM_END,ActiveTSO);
- }
- }
- switch (EVENT_TYPE(event))
- {
- case CONTINUETHREAD:
- case FINDWORK: /* inaccurate this way */
- ActiveTSO = ThreadQueueHd;
- break;
- case RESUMETHREAD:
- case STARTTHREAD:
- case MOVESPARK: /* has tso of virt proc in tso field of event */
- ActiveTSO = EVENT_TSO(event);
- break;
- default: fprintf(stderr,"Illegal event type %s (%d) in GrAnSim Light setup\n",
- event_names[EVENT_TYPE(event)],EVENT_TYPE(event));
- EXIT(EXIT_FAILURE);
- }
- CurrentTime[CurrentProc] = TSO_CLOCK(ActiveTSO);
- if(RTSflags.GranFlags.DoFairSchedule)
- {
- if (RTSflags.GranFlags.granSimStats &&
- RTSflags.GranFlags.debug & 0x20000)
- DumpGranEvent(GR_SYSTEM_START,ActiveTSO);
- }
- }
-
- if(EVENT_TIME(event) > CurrentTime[CurrentProc] &&
- EVENT_TYPE(event)!=CONTINUETHREAD)
- CurrentTime[CurrentProc] = EVENT_TIME(event);
-
-# if defined(GRAN_CHECK) && defined(GRAN) /* HWL */
- if ( RTSflags.GranFlags.Light && CurrentProc!=0 ) {
- fprintf(stderr,"Qagh {ReSchedule}Daq: CurrentProc must be 0 in GrAnSim Light setup\n");
- EXIT(EXIT_FAILURE);
- }
-# endif
- /* MAKE_BUSY(CurrentProc); don't think that's right in all cases now */
- /* -- HWL */
-
-# if defined(GRAN_CHECK) && defined(GRAN)
- if (RTSflags.GranFlags.debug & 0x80)
- fprintf(stderr,"After get_next_event, before HandleIdlePEs\n");
-# endif
-
- /* Deal with the idlers */
- if ( !RTSflags.GranFlags.Light )
- HandleIdlePEs();
-
-# if defined(GRAN_CHECK) && defined(GRAN)
- if ( RTSflags.GranFlags.event_trace_all ||
- ( RTSflags.GranFlags.event_trace && EVENT_TYPE(event) != CONTINUETHREAD) ||
- (RTSflags.GranFlags.debug & 0x80) )
- print_event(event);
-# endif
-
- switch (EVENT_TYPE(event))
- {
- /* Should just be continuing execution */
- case CONTINUETHREAD:
-# if defined(GRAN_CHECK) && defined(GRAN) /* Just for testing */
- if ( (RTSflags.GranFlags.debug & 0x100) &&
- (EVENT_TSO(event)!=RunnableThreadsHd[EVENT_PROC(event)]) ) {
- fprintf(stderr,"Warning: Wrong TSO in CONTINUETHREAD: %#lx (%x) (PE: %d Hd: 0x%lx)\n",
- EVENT_TSO(event), TSO_ID(EVENT_TSO(event)),
- EVENT_PROC(event),
- RunnableThreadsHd[EVENT_PROC(event)]);
- }
- if ( (RTSflags.GranFlags.debug & 0x04) &&
- BlockedOnFetch[CurrentProc]) {
- fprintf(stderr,"Warning: Discarding CONTINUETHREAD on blocked proc %u @ %u\n",
- CurrentProc,CurrentTime[CurrentProc]);
- print_event(event);
- continue;
- }
-# endif
- if(ThreadQueueHd==PrelBase_Z91Z93_closure)
- {
- new_event(CurrentProc,CurrentProc,CurrentTime[CurrentProc],
- FINDWORK,PrelBase_Z91Z93_closure,PrelBase_Z91Z93_closure,NULL);
- continue; /* Catches superfluous CONTINUEs -- should be unnecessary */
- }
- else
- break; /* fall into scheduler loop */
-
- case FETCHNODE:
- do_the_fetchnode(event);
- continue; /* handle next event in event queue */
-
- case GLOBALBLOCK:
- do_the_globalblock(event);
- continue; /* handle next event in event queue */
-
- case FETCHREPLY:
- do_the_fetchreply(event);
- continue; /* handle next event in event queue */
-
- case UNBLOCKTHREAD: /* Move from the blocked queue to the tail of */
- do_the_unblock(event);
- continue; /* handle next event in event queue */
-
- case RESUMETHREAD: /* Move from the blocked queue to the tail of */
- /* the runnable queue ( i.e. Qu' SImqa'lu') */
- TSO_BLOCKTIME(EVENT_TSO(event)) += CurrentTime[CurrentProc] -
- TSO_BLOCKEDAT(EVENT_TSO(event));
- StartThread(event,GR_RESUME);
- continue;
-
- case STARTTHREAD:
- StartThread(event,GR_START);
- continue;
-
- case MOVETHREAD:
- do_the_movethread(event);
- continue; /* handle next event in event queue */
-
- case MOVESPARK:
- do_the_movespark(event);
- continue; /* handle next event in event queue */
-
- case FINDWORK:
- { /* 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
- munch_spark. */
-
- I_ req_heap = TSO_HS + TSO_CTS_SIZE + STKO_HS +
- RTSflags.ConcFlags.stkChunkSize;
-
- if (SAVE_Hp + req_heap >= SAVE_HpLim ) {
- ReallyPerformThreadGC(req_heap, rtsFalse);
- SAVE_Hp -= req_heap;
- if (IS_SPARKING(CurrentProc))
- MAKE_IDLE(CurrentProc);
- continue;
- }
- }
-
- if( RTSflags.GranFlags.DoAlwaysCreateThreads ||
- (ThreadQueueHd == PrelBase_Z91Z93_closure &&
- (RTSflags.GranFlags.FetchStrategy >= 2 ||
- OutstandingFetches[CurrentProc] == 0)) )
- {
- rtsBool found;
- sparkq prev, spark;
-
- /* ToDo: check */
- ASSERT(procStatus[CurrentProc]==Sparking ||
- RTSflags.GranFlags.DoAlwaysCreateThreads);
-
- /* SImmoHwI' yInej! Search spark queue! */
- gimme_spark (&found, &prev, &spark);
-
- /* DaH chu' Qu' yIchen! Now create new work! */
- munch_spark (found, prev, spark);
-
- /* ToDo: check ; not valid if GC occurs in munch_spark
- ASSERT(procStatus[CurrentProc]==Starting ||
- procStatus[CurrentProc]==Idle ||
- RTSflags.GranFlags.DoAlwaysCreateThreads); */
- }
- continue; /* to the next event */
-
- default:
- fprintf(stderr,"Illegal event type %u\n",EVENT_TYPE(event));
- continue;
- } /* switch */
-#if defined(i386_TARGET_ARCH)
-
- if (entersFromC) {
- /* more than one thread has entered the Haskell world
- via C (and stable pointers) - don't squeeze the C stack. */
- SchedLoop(1);
- } else {
- /* Squeeze C stack */
- longjmp(scheduler_loop, 1);
- }
-#else
- longjmp(scheduler_loop, 1);
-#endif
- } while(1);
-}
-
-/* ----------------------------------------------------------------- */
-/* The main event handling functions; called from ReSchedule (switch) */
-/* ----------------------------------------------------------------- */
-
-void
-do_the_globalblock(eventq event)
-{
- PROC proc = EVENT_PROC(event); /* proc that requested node */
- P_ tso = EVENT_TSO(event), /* tso that requested node */
- node = EVENT_NODE(event); /* requested, remote node */
-
-# if defined(GRAN_CHECK) && defined(GRAN)
- if ( RTSflags.GranFlags.Light ) {
- fprintf(stderr,"Qagh: There should be no GLOBALBLOCKs in GrAnSim Light setup\n");
- EXIT(EXIT_FAILURE);
- }
-
- if (!RTSflags.GranFlags.DoGUMMFetching) {
- fprintf(stderr,"Qagh: GLOBALBLOCK events only valid with GUMM fetching\n");
- EXIT(EXIT_FAILURE);
- }
-
- if ( (RTSflags.GranFlags.debug & 0x100) &&
- IS_LOCAL_TO(PROCS(node),proc) ) {
- fprintf(stderr,"Qagh: GLOBALBLOCK: Blocking on LOCAL node 0x %x (PE %d).\n",
- node,proc);
- }
-# endif
- /* CurrentTime[CurrentProc] += RTSflags.GranFlags.gran_munpacktime; */
- if ( blockFetch(tso,proc,node) != 0 )
- return; /* node has become local by now */
-
- if (!RTSflags.GranFlags.DoReScheduleOnFetch) { /* head of queue is next thread */
- P_ tso = RunnableThreadsHd[proc]; /* awaken next thread */
- if(tso != PrelBase_Z91Z93_closure) {
- new_event(proc,proc,CurrentTime[proc],
- CONTINUETHREAD,tso,PrelBase_Z91Z93_closure,NULL);
- CurrentTime[proc] += RTSflags.GranFlags.gran_threadcontextswitchtime;
- if(RTSflags.GranFlags.granSimStats)
- DumpRawGranEvent(proc,CurrentProc,GR_SCHEDULE,tso,
- PrelBase_Z91Z93_closure,0);
- MAKE_BUSY(proc); /* might have been fetching */
- } else {
- MAKE_IDLE(proc); /* no work on proc now */
- }
- } else { /* RTSflags.GranFlags.DoReScheduleOnFetch 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.DoGUMMFetching ? closure :
- EVENT_NODE(event)),NULL);
- */
- }
-}
-
-void
-do_the_unblock(eventq event)
-{
- PROC proc = EVENT_PROC(event), /* proc that requested node */
- creator = EVENT_CREATOR(event); /* proc that requested node */
- P_ tso = EVENT_TSO(event), /* tso that requested node */
- node = EVENT_NODE(event); /* requested, remote node */
-
-# if defined(GRAN) && defined(GRAN_CHECK)
- if ( RTSflags.GranFlags.Light ) {
- fprintf(stderr,"Qagh: There should be no UNBLOCKs in GrAnSim Light setup\n");
- EXIT(EXIT_FAILURE);
- }
-# endif
-
- if (!RTSflags.GranFlags.DoReScheduleOnFetch) { /* block-on-fetch */
- /* We count block-on-fetch as normal block time */
- TSO_BLOCKTIME(tso) += CurrentTime[proc] - TSO_BLOCKEDAT(tso);
- /* No costs for contextswitch or thread queueing in this case */
- if(RTSflags.GranFlags.granSimStats)
- DumpRawGranEvent(proc,CurrentProc,GR_RESUME,tso, PrelBase_Z91Z93_closure,0);
- new_event(proc,proc,CurrentTime[proc],CONTINUETHREAD,tso,node,NULL);
- } else {
- /* Reschedule on fetch causes additional costs here: */
- /* Bring the TSO from the blocked queue into the threadq */
- new_event(proc,proc,CurrentTime[proc]+RTSflags.GranFlags.gran_threadqueuetime,
- RESUMETHREAD,tso,node,NULL);
- }
-}
-
-void
-do_the_fetchnode(eventq event)
-{
- I_ rc;
-
-# if defined(GRAN_CHECK) && defined(GRAN)
- if ( RTSflags.GranFlags.Light ) {
- fprintf(stderr,"Qagh: There should be no FETCHNODEs in GrAnSim Light setup\n");
- EXIT(EXIT_FAILURE);
- }
-
- if (RTSflags.GranFlags.SimplifiedFetch) {
- fprintf(stderr,"Qagh: FETCHNODE events not valid with simplified fetch\n");
- EXIT(EXIT_FAILURE);
- }
-# endif
- CurrentTime[CurrentProc] += RTSflags.GranFlags.gran_munpacktime;
- do {
- rc = HandleFetchRequest(EVENT_NODE(event),
- EVENT_CREATOR(event),
- EVENT_TSO(event));
- if (rc == 4) { /* trigger GC */
-# if defined(GRAN_CHECK) && defined(GRAN)
- if (RTSflags.GcFlags.giveStats)
- fprintf(RTSflags.GcFlags.statsFile,"***** veQ boSwI' PackNearbyGraph(node %#lx, tso %#lx (%x))\n",
- EVENT_NODE(event), EVENT_TSO(event), TSO_ID(EVENT_TSO(event)));
-# endif
- prepend_event(event);
- ReallyPerformThreadGC(PACK_HEAP_REQUIRED, rtsFalse);
-# if defined(GRAN_CHECK) && defined(GRAN)
- if (RTSflags.GcFlags.giveStats) {
- fprintf(RTSflags.GcFlags.statsFile,"***** SAVE_Hp=%#lx, SAVE_HpLim=%#lx, PACK_HEAP_REQUIRED=%#lx\n",
- SAVE_Hp, SAVE_HpLim, PACK_HEAP_REQUIRED);
- fprintf(stderr,"***** No. of packets so far: %d (total size: %d)\n",
- tot_packets,tot_packet_size);
- }
-# endif
- event = grab_event();
- SAVE_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 == 4);
-}
-
-void
-do_the_fetchreply(eventq event)
-{
- P_ tso, closure;
-
-# if defined(GRAN_CHECK) && defined(GRAN) /* Just for testing */
- if ( RTSflags.GranFlags.Light ) {
- fprintf(stderr,"Qagh: There should be no FETCHREPLYs in GrAnSim Light setup\n");
- EXIT(EXIT_FAILURE);
- }
-
- if (RTSflags.GranFlags.SimplifiedFetch) {
- fprintf(stderr,"Qagh: FETCHREPLY events not valid with simplified fetch\n");
- EXIT(EXIT_FAILURE);
- }
-
- if (RTSflags.GranFlags.debug & 0x10) {
- if (TSO_TYPE(EVENT_TSO(event)) & FETCH_MASK_TSO) {
- TSO_TYPE(EVENT_TSO(event)) &= ~FETCH_MASK_TSO;
- } else {
- fprintf(stderr,"Qagh: FETCHREPLY: TSO %#x (%x) has fetch mask not set @ %d\n",
- CurrentTSO,TSO_ID(CurrentTSO),CurrentTime[CurrentProc]);
- EXIT(EXIT_FAILURE);
- }
- }
-
- if (RTSflags.GranFlags.debug & 0x04) {
- if (BlockedOnFetch[CurrentProc]!=ThreadQueueHd) {
- fprintf(stderr,"Qagh: FETCHREPLY: Proc %d (with TSO %#x (%x)) not blocked-on-fetch by TSO %#lx (%x)\n",
- CurrentProc,CurrentTSO,TSO_ID(CurrentTSO),
- BlockedOnFetch[CurrentProc], TSO_ID(BlockedOnFetch[CurrentProc]));
- EXIT(EXIT_FAILURE);
- } else {
- BlockedOnFetch[CurrentProc] = 0; /*- rtsFalse; -*/
- }
- }
-# endif
-
- CurrentTime[CurrentProc] += RTSflags.GranFlags.gran_munpacktime;
-
- if (RTSflags.GranFlags.DoGUMMFetching) { /* bulk (packet) fetching */
- P_ buffer = EVENT_NODE(event);
- PROC p = EVENT_PROC(event);
- I_ size = buffer[PACK_SIZE_LOCN];
-
- tso = EVENT_TSO(event);
-
- /* NB: Fetch misses can't occur with GUMM fetching, as */
- /* updatable closure are turned into RBHs and therefore locked */
- /* for other processors that try to grab them. */
-
- closure = UnpackGraph(buffer);
- CurrentTime[CurrentProc] += size * RTSflags.GranFlags.gran_munpacktime;
- } else
- /* Copy or move node to CurrentProc */
- if (FetchNode(EVENT_NODE(event),
- EVENT_CREATOR(event),
- EVENT_PROC(event)) ) {
- /* Fetch has failed i.e. node has been grabbed by another PE */
- P_ node = EVENT_NODE(event), tso = EVENT_TSO(event);
- PROC p = where_is(node);
- TIME fetchtime;
-
-# if defined(GRAN_CHECK) && defined(GRAN)
- if (RTSflags.GranFlags.PrintFetchMisses) {
- fprintf(stderr,"Fetch miss @ %lu: node %#lx is at proc %u (rather than proc %u)\n",
- CurrentTime[CurrentProc],node,p,EVENT_CREATOR(event));
- fetch_misses++;
- }
-# endif /* GRAN_CHECK */
-
- CurrentTime[CurrentProc] += RTSflags.GranFlags.gran_mpacktime;
-
- /* Count fetch again !? */
- ++TSO_FETCHCOUNT(tso);
- TSO_FETCHTIME(tso) += RTSflags.GranFlags.gran_fetchtime;
-
- fetchtime = STG_MAX(CurrentTime[CurrentProc],CurrentTime[p]) +
- RTSflags.GranFlags.gran_latency;
-
- /* Chase the grabbed node */
- new_event(p,CurrentProc,fetchtime,FETCHNODE,tso,node,NULL);
-
-# if defined(GRAN_CHECK) && defined(GRAN) /* Just for testing */
- if (RTSflags.GranFlags.debug & 0x04)
- BlockedOnFetch[CurrentProc] = tso; /*-rtsTrue;-*/
-
- if (RTSflags.GranFlags.debug & 0x10)
- TSO_TYPE(tso) |= FETCH_MASK_TSO;
-# endif
-
- CurrentTime[CurrentProc] += RTSflags.GranFlags.gran_mtidytime;
-
- return; /* NB: no REPLy has been processed; tso still sleeping */
- }
-
- /* -- Qapla'! Fetch has been successful; node is here, now */
- ++TSO_FETCHCOUNT(EVENT_TSO(event));
- TSO_FETCHTIME(EVENT_TSO(event)) += RTSflags.GranFlags.gran_fetchtime;
-
- if (RTSflags.GranFlags.granSimStats)
- DumpRawGranEvent(CurrentProc,EVENT_CREATOR(event),GR_REPLY,
- EVENT_TSO(event),
- (RTSflags.GranFlags.DoGUMMFetching ?
- closure :
- EVENT_NODE(event)),
- 0);
-
- --OutstandingFetches[CurrentProc];
- ASSERT(OutstandingFetches[CurrentProc] >= 0);
-# if 0 && defined(GRAN_CHECK) && defined(GRAN) /* Just for testing */
- if (OutstandingFetches[CurrentProc] < 0) {
- fprintf(stderr,"Qagh: OutstandingFetches of proc %u has become negative\n",CurrentProc);
- EXIT(EXIT_FAILURE);
- }
-# endif
- new_event(CurrentProc,CurrentProc,CurrentTime[CurrentProc],
- UNBLOCKTHREAD,EVENT_TSO(event),
- (RTSflags.GranFlags.DoGUMMFetching ?
- closure :
- EVENT_NODE(event)),
- NULL);
-}
-
-void
-do_the_movethread(eventq event) {
- P_ tso = EVENT_TSO(event);
-# if defined(GRAN_CHECK) && defined(GRAN) /* Just for testing */
- if ( RTSflags.GranFlags.Light && CurrentProc!=1 ) {
- fprintf(stderr,"Qagh: There should be no MOVETHREADs in GrAnSim Light setup\n");
- EXIT(EXIT_FAILURE);
- }
- if (!RTSflags.GranFlags.DoThreadMigration) {
- fprintf(stderr,"Qagh: MOVETHREAD events should never occur without -bM\n");
- EXIT(EXIT_FAILURE);
- }
- if (PROCS(tso)!=0) {
- fprintf(stderr,"Qagh: Moved thread has a bitmask of 0%o (proc %d); should be 0\n",
- PROCS(tso), where_is(tso));
- EXIT(EXIT_FAILURE);
- }
-# endif
- --OutstandingFishes[CurrentProc];
- ASSERT(OutstandingFishes[CurrentProc]>=0);
- SET_PROCS(tso,ThisPE);
- CurrentTime[CurrentProc] += RTSflags.GranFlags.gran_munpacktime;
- StartThread(event,GR_STOLEN);
-}
-
-void
-do_the_movespark(eventq event){
- sparkq spark = EVENT_SPARK(event);
-
- CurrentTime[CurrentProc] += RTSflags.GranFlags.gran_munpacktime;
-
- if (RTSflags.GranFlags.granSimStats_Sparks)
- DumpRawGranEvent(CurrentProc,(PROC)0,SP_ACQUIRED,PrelBase_Z91Z93_closure,
- SPARK_NODE(spark),
- spark_queue_len(CurrentProc,ADVISORY_POOL));
-
-#if defined(GRAN) && defined(GRAN_CHECK)
- if (!SHOULD_SPARK(SPARK_NODE(spark)))
- 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 */
-#endif
- --OutstandingFishes[CurrentProc];
- ASSERT(OutstandingFishes[CurrentProc]>=0);
-
- add_to_spark_queue(spark);
-
- if (procStatus[CurrentProc]==Fishing)
- procStatus[CurrentProc] = Idle;
-
- /* add_to_spark_queue will increase the time of the current proc. */
- /* Just falling into FINDWORK is wrong as we might have other */
- /* events that are happening before that. Therefore, just create */
- /* a FINDWORK event and go back to main event handling loop. */
-
- /* Should we treat stolen sparks specially? Currently, we don't. */
-#if 0
- /* Now FINDWORK is created in HandleIdlePEs */
- new_event(CurrentProc,CurrentProc,CurrentTime[CurrentProc],
- FINDWORK,PrelBase_Z91Z93_closure,PrelBase_Z91Z93_closure,NULL);
- sparking[CurrentProc]=rtsTrue;
-#endif
-}
-
-/* Search the spark queue of the CurrentProc for a spark that's worth
- turning into a thread */
-void
-gimme_spark (rtsBool *found_res, sparkq *prev_res, sparkq *spark_res)
-{
- P_ node;
- rtsBool found;
- sparkq spark_of_non_local_node = NULL, spark_of_non_local_node_prev = NULL,
- low_priority_spark = NULL, low_priority_spark_prev = NULL,
- spark = NULL, prev = NULL, tmp = NULL;
-
- /* Choose a spark from the local spark queue */
- spark = SparkQueueHd;
- found = rtsFalse;
-
- while (spark != NULL && !found)
- {
- node = SPARK_NODE(spark);
- if (!SHOULD_SPARK(node))
- {
- if(RTSflags.GranFlags.granSimStats_Sparks)
- DumpRawGranEvent(CurrentProc,(PROC)0,SP_PRUNED,PrelBase_Z91Z93_closure,
- SPARK_NODE(spark),
- spark_queue_len(CurrentProc,ADVISORY_POOL));
-
- ASSERT(spark != NULL);
-
- --SparksAvail;
- spark = delete_from_spark_queue (prev,spark);
- }
- /* -- node should eventually be sparked */
- else if (RTSflags.GranFlags.PreferSparksOfLocalNodes &&
- !IS_LOCAL_TO(PROCS(node),CurrentProc))
- {
- /* Remember first low priority spark */
- if (spark_of_non_local_node==NULL) {
- spark_of_non_local_node_prev = prev;
- spark_of_non_local_node = spark;
- }
-
- if (SPARK_NEXT(spark)==NULL) {
- ASSERT(spark==SparkQueueTl); /* just for testing */
- prev = spark_of_non_local_node_prev;
- spark = spark_of_non_local_node;
- found = rtsTrue;
- break;
- }
-
-# if defined(GRAN) && defined(GRAN_CHECK)
- /* Should never happen; just for testing */
- if (spark==SparkQueueTl) {
- fprintf(stderr,"ReSchedule: Last spark != SparkQueueTl\n");
- EXIT(EXIT_FAILURE);
- }
-# endif
- prev = spark;
- spark = SPARK_NEXT(spark);
- --SparksAvail;
- }
- else if ( RTSflags.GranFlags.DoPrioritySparking ||
- (SPARK_GRAN_INFO(spark)>=RTSflags.GranFlags.SparkPriority2) )
- {
- found = rtsTrue;
- }
- else /* only used if SparkPriority2 is defined */
- {
- /* Remember first low priority spark */
- if (low_priority_spark==NULL) {
- low_priority_spark_prev = prev;
- low_priority_spark = spark;
- }
-
- if (SPARK_NEXT(spark)==NULL) {
- ASSERT(spark==SparkQueueTl); /* just for testing */
- prev = low_priority_spark_prev;
- spark = low_priority_spark;
- found = rtsTrue; /* take low pri spark => rc is 2 */
- break;
- }
-
- /* Should never happen; just for testing */
- if (spark==SparkQueueTl) {
- fprintf(stderr,"ReSchedule: Last spark != SparkQueueTl\n");
- EXIT(EXIT_FAILURE);
- break;
- }
- prev = spark;
- spark = SPARK_NEXT(spark);
-# if defined(GRAN_CHECK) && defined(GRAN)
- if ( RTSflags.GranFlags.debug & 0x40 ) {
- fprintf(stderr,"Ignoring spark of priority %u (SparkPriority=%u); node=0x%lx; name=%u\n",
- SPARK_GRAN_INFO(spark), RTSflags.GranFlags.SparkPriority,
- SPARK_NODE(spark), SPARK_NAME(spark));
- }
-# endif /* GRAN_CHECK */
- }
- } /* while (spark!=NULL && !found) */
-
- *spark_res = spark;
- *prev_res = prev;
- *found_res = found;
-}
-
-void
-munch_spark (rtsBool found, sparkq prev, sparkq spark)
-{
- P_ tso, node;
-
- /* We've found a node; now, create thread (DaH Qu' yIchen) */
- if (found)
- {
-# if defined(GRAN_CHECK) && defined(GRAN)
- if ( SPARK_GRAN_INFO(spark) < RTSflags.GranFlags.SparkPriority2 ) {
- tot_low_pri_sparks++;
- if ( RTSflags.GranFlags.debug & 0x40 ) {
- fprintf(stderr,"GRAN_TNG: No high priority spark available; low priority (%u) spark chosen: node=0x%lx; name=%u\n",
- SPARK_GRAN_INFO(spark),
- SPARK_NODE(spark), SPARK_NAME(spark));
- }
- }
-# endif
- CurrentTime[CurrentProc] += RTSflags.GranFlags.gran_threadcreatetime;
-
- node = SPARK_NODE(spark);
- if((tso = NewThread(node, T_REQUIRED, SPARK_GRAN_INFO(spark)))==NULL)
- {
- /* Some kind of backoff needed here in case there's too little heap */
-# if defined(GRAN_CHECK) && defined(GRAN)
- if (RTSflags.GcFlags.giveStats)
- fprintf(RTSflags.GcFlags.statsFile,"***** vIS Qu' chen veQ boSwI'; spark=%#x, node=%#x; name=%u\n",
- /* (found==2 ? "no hi pri spark" : "hi pri spark"), */
- spark, node,SPARK_NAME(spark));
-# endif
- new_event(CurrentProc,CurrentProc,CurrentTime[CurrentProc]+1,
- FINDWORK,PrelBase_Z91Z93_closure,PrelBase_Z91Z93_closure,NULL);
- ReallyPerformThreadGC(TSO_HS+TSO_CTS_SIZE,rtsFalse);
- SAVE_Hp -= TSO_HS+TSO_CTS_SIZE;
- spark = NULL;
- return; /* was: continue; */ /* to the next event, eventually */
- }
-
- if(RTSflags.GranFlags.granSimStats_Sparks)
- DumpRawGranEvent(CurrentProc,(PROC)0,SP_USED,PrelBase_Z91Z93_closure,
- SPARK_NODE(spark),
- spark_queue_len(CurrentProc,ADVISORY_POOL));
-
- TSO_EXPORTED(tso) = SPARK_EXPORTED(spark);
- TSO_LOCKED(tso) = !SPARK_GLOBAL(spark);
- TSO_SPARKNAME(tso) = SPARK_NAME(spark);
-
- new_event(CurrentProc,CurrentProc,CurrentTime[CurrentProc],
- STARTTHREAD,tso,node,NULL);
-
- procStatus[CurrentProc] = Starting;
-
- ASSERT(spark != NULL);
-
- spark = delete_from_spark_queue (prev, spark);
- }
- else /* !found */
- /* Make the PE idle if nothing sparked and we have no threads. */
- {
- if(ThreadQueueHd == PrelBase_Z91Z93_closure)
- {
- MAKE_IDLE(CurrentProc);
-# if defined(GRAN_CHECK) && defined(GRAN)
- if ( (RTSflags.GranFlags.debug & 0x80) )
- fprintf(stderr,"Warning in FINDWORK handling: No work found for PROC %u\n",CurrentProc);
-# endif /* GRAN_CHECK */
- }
-#if 0
- else
- /* ut'lu'Qo' ; Don't think that's necessary any more -- HWL
- new_event(CurrentProc,CurrentProc,CurrentTime[CurrentProc],
- CONTINUETHREAD,ThreadQueueHd,PrelBase_Z91Z93_closure,NULL);
- */
-#endif
- }
-
-}
-\end{code}
-
-Here follows the non-GRAN @ReSchedule@.
-
-\begin{code}
-#else /* !GRAN */
-
-/* If you are concurrent and maybe even parallel please use this door. */
-
-void
-ReSchedule(again)
-int again; /* Run the current thread again? */
-{
- P_ spark;
- PP_ sparkp;
- P_ tso;
-
-#ifdef PAR
- /*
- * In the parallel world, we do unfair scheduling for the moment.
- * Ultimately, this should all be merged with the more
- * sophisticated GrAnSim scheduling options. (Of course, some
- * provision should be made for *required* threads to make sure
- * that they don't starve, but for now we assume that no one is
- * running concurrent Haskell on a multi-processor platform.)
- */
-
- sameThread = again;
-
- if (again) {
- if (RunnableThreadsHd == PrelBase_Z91Z93_closure)
- RunnableThreadsTl = CurrentTSO;
- TSO_LINK(CurrentTSO) = RunnableThreadsHd;
- RunnableThreadsHd = CurrentTSO;
- }
-
-#else
-
- /*
- * In the sequential world, we assume that the whole point of running
- * the threaded build is for concurrent Haskell, so we provide round-robin
- * scheduling.
- */
-
- if (again) {
- if(RunnableThreadsHd == PrelBase_Z91Z93_closure) {
- RunnableThreadsHd = CurrentTSO;
- } else {
- TSO_LINK(RunnableThreadsTl) = CurrentTSO;
- if (DO_QP_PROF > 1) {
- QP_Event1("GA", CurrentTSO);
- }
- }
- RunnableThreadsTl = CurrentTSO;
- }
-#endif
-
-#if 1
- /*
- * Debugging code, which is useful enough (and cheap enough) to compile
- * in all the time. This makes sure that we don't access saved registers,
- * etc. in threads which are supposed to be sleeping.
- */
- CurrentTSO = PrelBase_Z91Z93_closure;
- CurrentRegTable = NULL;
-#endif
-
- /* First the required sparks */
-
- for (sparkp = PendingSparksHd[REQUIRED_POOL];
- sparkp < PendingSparksTl[REQUIRED_POOL]; sparkp++) {
- spark = *sparkp;
- if (SHOULD_SPARK(spark)) {
- if ((tso = NewThread(spark, T_REQUIRED)) == NULL)
- break;
- if (RunnableThreadsHd == PrelBase_Z91Z93_closure) {
- RunnableThreadsHd = tso;
-#ifdef PAR
- if (RTSflags.ParFlags.granSimStats) {
- DumpGranEvent(GR_START, tso);
- sameThread = rtsTrue;
- }
-#endif
- } else {
- TSO_LINK(RunnableThreadsTl) = tso;
-#ifdef PAR
- if (RTSflags.ParFlags.granSimStats)
- DumpGranEvent(GR_STARTQ, tso);
-#endif
- }
- RunnableThreadsTl = tso;
- } else {
- if (DO_QP_PROF)
- QP_Event0(threadId++, spark);
-#if 0
- /* ToDo: Fix log entries for pruned sparks in GUM -- HWL */
- if(RTSflags.GranFlags.granSimStats_Sparks)
- DumpGranEvent(SP_PRUNED,threadId++);
- ^^^^^^^^ should be a TSO
-#endif
- }
- }
- PendingSparksHd[REQUIRED_POOL] = sparkp;
-
- /* Now, almost the same thing for advisory sparks */
-
- for (sparkp = PendingSparksHd[ADVISORY_POOL];
- sparkp < PendingSparksTl[ADVISORY_POOL]; sparkp++) {
- spark = *sparkp;
- if (SHOULD_SPARK(spark)) {
- if (
-#ifdef PAR
- /* In the parallel world, don't create advisory threads if we are
- * about to rerun the same thread, or already have runnable threads,
- * or the main thread has terminated */
- (RunnableThreadsHd != PrelBase_Z91Z93_closure ||
- (required_thread_count == 0 && IAmMainThread)) ||
-#endif
- advisory_thread_count == RTSflags.ConcFlags.maxThreads ||
- (tso = NewThread(spark, T_ADVISORY)) == NULL)
- break;
- advisory_thread_count++;
- if (RunnableThreadsHd == PrelBase_Z91Z93_closure) {
- RunnableThreadsHd = tso;
-#ifdef PAR
- if (RTSflags.ParFlags.granSimStats) {
- DumpGranEvent(GR_START, tso);
- sameThread = rtsTrue;
- }
-#endif
- } else {
- TSO_LINK(RunnableThreadsTl) = tso;
-#ifdef PAR
- if (RTSflags.ParFlags.granSimStats)
- DumpGranEvent(GR_STARTQ, tso);
-#endif
- }
- RunnableThreadsTl = tso;
- } else {
- if (DO_QP_PROF)
- QP_Event0(threadId++, spark);
-#if 0
- /* ToDo: Fix log entries for pruned sparks in GUM -- HWL */
- if(RTSflags.GranFlags.granSimStats_Sparks)
- DumpGranEvent(SP_PRUNED,threadId++);
- ^^^^^^^^ should be a TSO
-#endif
- }
- }
- PendingSparksHd[ADVISORY_POOL] = sparkp;
-
-#ifndef PAR
-# if defined(i386_TARGET_ARCH)
- if (entersFromC) { /* more than one thread has entered the Haskell world
- via C (and stable pointers) */
- /* Don't squeeze C stack */
- if (required_thread_count <= 0) {
- longjmp(scheduler_loop, -1);
- } else {
- SchedLoop(required_thread_count <= 0 ? -1 : 1);
- longjmp(scheduler_loop, -1);
- }
- } else {
- longjmp(scheduler_loop, required_thread_count == 0 ? -1 : 1);
- }
-# else
- longjmp(scheduler_loop, required_thread_count == 0 ? -1 : 1);
-# endif
-#else
- longjmp(scheduler_loop, required_thread_count == 0 && IAmMainThread ? -1 : 1);
-#endif
-}
-
-#endif /* !GRAN */
-
-\end{code}
-
-%****************************************************************************
-%
-\subsection[thread-gransim-execution]{Starting, Idling and Migrating
- Threads (GrAnSim only)}
-%
-%****************************************************************************
-
-Thread start, idle and migration code for GrAnSim (i.e. simulating multiple
-processors).
-
-\begin{code}
-#if defined(GRAN)
-
-/* ngoqvam che' {GrAnSim}! */
-
-# if defined(GRAN_CHECK)
-/* 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'
-*/
-I_
-thread_queue_len(PROC proc)
-{
- P_ prev, next;
- I_ len;
-
- for (len = 0, prev = PrelBase_Z91Z93_closure, next = RunnableThreadsHd[proc];
- next != PrelBase_Z91Z93_closure;
- len++, prev = next, next = TSO_LINK(prev))
- {}
-
- return (len);
-}
-# endif /* GRAN_CHECK */
-\end{code}
-
-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.
-
-\begin{code}
-StartThread(event,event_type)
-eventq event;
-enum gran_event_types event_type;
-{
- P_ tso = EVENT_TSO(event),
- node = EVENT_NODE(event);
- PROC proc = EVENT_PROC(event),
- creator = EVENT_CREATOR(event);
- P_ prev, next;
- I_ count = 0;
- rtsBool found = rtsFalse;
-
- ASSERT(CurrentProc==proc);
-
-# if defined(GRAN_CHECK)
- if ( RTSflags.GranFlags.Light && CurrentProc!=0 ) {
- fprintf(stderr,"Qagh {StartThread}Daq: CurrentProc must be 0 in GrAnSim Light setup\n");
- EXIT(EXIT_FAILURE);
- }
-
- /* A wee bit of statistics gathering */
- ++tot_add_threads;
- tot_tq_len += thread_queue_len(CurrentProc);
-# endif
-
- ASSERT(TSO_LINK(CurrentTSO)==PrelBase_Z91Z93_closure);
-
- /* Idle proc; same for pri spark and basic version */
- if(ThreadQueueHd==PrelBase_Z91Z93_closure)
- {
- CurrentTSO = ThreadQueueHd = ThreadQueueTl = tso;
-
- CurrentTime[CurrentProc] += RTSflags.GranFlags.gran_threadqueuetime;
- new_event(CurrentProc,CurrentProc,CurrentTime[CurrentProc],
- CONTINUETHREAD,tso,PrelBase_Z91Z93_closure,NULL);
-
- if(RTSflags.GranFlags.granSimStats &&
- !( (event_type == GR_START || event_type == GR_STARTQ) && RTSflags.GranFlags.labelling) )
- DumpRawGranEvent(CurrentProc,creator,event_type,
- tso,node,
- TSO_SPARKNAME(tso));
- /* ^^^ SN (spark name) as optional info */
- /* spark_queue_len(CurrentProc,ADVISORY_POOL)); */
- /* ^^^ spark length as optional info */
-
- ASSERT(IS_IDLE(CurrentProc) || event_type==GR_RESUME ||
- (procStatus[CurrentProc]==Fishing && event_type==GR_STOLEN) ||
- procStatus[CurrentProc]==Starting);
- MAKE_BUSY(CurrentProc);
- return;
- }
-
- /* 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.
- */
- if(RTSflags.GranFlags.Light)
- {
- ASSERT(ThreadQueueHd!=PrelBase_Z91Z93_closure);
- ASSERT(TSO_LINK(tso)==PrelBase_Z91Z93_closure);
-
- /* If only one thread in queue so far we emit DESCHEDULE in debug mode */
- if(RTSflags.GranFlags.granSimStats &&
- (RTSflags.GranFlags.debug & 0x20000) &&
- TSO_LINK(ThreadQueueHd)==PrelBase_Z91Z93_closure) {
- DumpRawGranEvent(CurrentProc,CurrentProc,GR_DESCHEDULE,
- ThreadQueueHd,PrelBase_Z91Z93_closure,0);
- resched = rtsTrue;
- }
-
- if ( InsertThread(tso) ) { /* new head of queue */
- new_event(CurrentProc,CurrentProc,CurrentTime[CurrentProc],
- CONTINUETHREAD,tso,PrelBase_Z91Z93_closure,NULL);
-
- }
- if(RTSflags.GranFlags.granSimStats &&
- !(( event_type == GR_START || event_type == GR_STARTQ) && RTSflags.GranFlags.labelling) )
- DumpRawGranEvent(CurrentProc,creator,event_type,
- tso,node,
- TSO_SPARKNAME(tso));
- /* ^^^ SN (spark name) as optional info */
- /* spark_queue_len(CurrentProc,ADVISORY_POOL)); */
- /* ^^^ spark length as optional info */
-
- /* MAKE_BUSY(CurrentProc); */
- return;
- }
-
- /* Only for Pri Sparking */
- if (RTSflags.GranFlags.DoPriorityScheduling && TSO_PRI(tso)!=0)
- /* {add_to_spark_queue}vo' jInIHta'; Qu' wa'DIch yIleghQo' */
- for (prev = ThreadQueueHd, next = TSO_LINK(ThreadQueueHd), count=0;
- (next != PrelBase_Z91Z93_closure) &&
- !(found = (TSO_PRI(tso) >= TSO_PRI(next)));
- prev = next, next = TSO_LINK(next), count++)
- {}
-
-
- ASSERT(!IS_IDLE(CurrentProc));
-
- /* found can only be rtsTrue if pri sparking enabled */
- if (found) {
-# if defined(GRAN_CHECK)
- ++non_end_add_threads;
-# endif
- /* Add tso to ThreadQueue between prev and next */
- TSO_LINK(tso) = next;
- if ( next == PrelBase_Z91Z93_closure ) {
- ThreadQueueTl = tso;
- } else {
- /* no back link for TSO chain */
- }
-
- if ( prev == PrelBase_Z91Z93_closure ) {
- /* Never add TSO as first elem of thread queue; the first */
- /* element should be the one that is currently running -- HWL */
-# if defined(GRAN_CHECK)
- fprintf(stderr,"Qagh: NewThread (w/ PriorityScheduling): Trying to add TSO %#lx (PRI=%d) as first elem of threadQ (%#lx) on proc %u (@ %u)\n",
- tso, TSO_PRI(tso), ThreadQueueHd, CurrentProc,
- CurrentTime[CurrentProc]);
-# endif
- } else {
- TSO_LINK(prev) = tso;
- }
- } else { /* !found */ /* or not pri sparking! */
- /* Add TSO to the end of the thread queue on that processor */
- TSO_LINK(ThreadQueueTl) = EVENT_TSO(event);
- ThreadQueueTl = EVENT_TSO(event);
- }
- CurrentTime[CurrentProc] += count *
- RTSflags.GranFlags.gran_pri_sched_overhead +
- RTSflags.GranFlags.gran_threadqueuetime;
-
- if(RTSflags.GranFlags.DoThreadMigration)
- ++SurplusThreads;
-
- if(RTSflags.GranFlags.granSimStats &&
- !(( event_type == GR_START || event_type == GR_STARTQ) && RTSflags.GranFlags.labelling) )
- DumpRawGranEvent(CurrentProc,creator,event_type+1,
- tso,node,
- TSO_SPARKNAME(tso));
- /* ^^^ SN (spark name) as optional info */
- /* spark_queue_len(CurrentProc,ADVISORY_POOL)); */
- /* ^^^ spark length as optional info */
-
-# if defined(GRAN_CHECK)
- /* Check if thread queue is sorted. Only for testing, really! HWL */
- if ( RTSflags.GranFlags.DoPriorityScheduling && (RTSflags.GranFlags.debug & 0x400) ) {
- rtsBool sorted = rtsTrue;
- P_ prev, next;
-
- if (ThreadQueueHd==PrelBase_Z91Z93_closure || TSO_LINK(ThreadQueueHd)==PrelBase_Z91Z93_closure) {
- /* just 1 elem => ok */
- } else {
- /* Qu' wa'DIch yIleghQo' (ignore first elem)! */
- for (prev = TSO_LINK(ThreadQueueHd), next = TSO_LINK(prev);
- (next != PrelBase_Z91Z93_closure) ;
- prev = next, next = TSO_LINK(prev)) {
- sorted = sorted &&
- (TSO_PRI(prev) >= TSO_PRI(next));
- }
- }
- if (!sorted) {
- fprintf(stderr,"Qagh: THREADQ on PE %d is not sorted:\n",
- CurrentProc);
- G_THREADQ(ThreadQueueHd,0x1);
- }
- }
-# endif
-
- CurrentTime[CurrentProc] += RTSflags.GranFlags.gran_threadqueuetime;
-}
-\end{code}
-
-@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.
-
-\begin{code}
-rtsBool
-InsertThread(tso)
-P_ tso;
-{
- P_ prev, next;
- I_ count = 0;
- rtsBool found = rtsFalse;
-
-# if defined(GRAN_CHECK)
- if ( !RTSflags.GranFlags.Light ) {
- fprintf(stderr,"Qagh {InsertThread}Daq: InsertThread should only be used in a GrAnSim Light setup\n");
- EXIT(EXIT_FAILURE);
- }
-
- if ( RTSflags.GranFlags.Light && CurrentProc!=0 ) {
- fprintf(stderr,"Qagh {StartThread}Daq: CurrentProc must be 0 in GrAnSim Light setup\n");
- EXIT(EXIT_FAILURE);
- }
-# endif
-
- /* Idle proc; same for pri spark and basic version */
- if(ThreadQueueHd==PrelBase_Z91Z93_closure)
- {
- ThreadQueueHd = ThreadQueueTl = tso;
- /* MAKE_BUSY(CurrentProc); */
- return (rtsTrue);
- }
-
- for (prev = ThreadQueueHd, next = TSO_LINK(ThreadQueueHd), count=0;
- (next != PrelBase_Z91Z93_closure) &&
- !(found = (TSO_CLOCK(tso) < TSO_CLOCK(next)));
- prev = next, next = TSO_LINK(next), count++)
- {}
-
- /* found can only be rtsTrue if pri sparking enabled */
- if (found) {
- /* Add tso to ThreadQueue between prev and next */
- TSO_LINK(tso) = next;
- if ( next == PrelBase_Z91Z93_closure ) {
- ThreadQueueTl = tso;
- } else {
- /* no back link for TSO chain */
- }
-
- if ( prev == PrelBase_Z91Z93_closure ) {
- ThreadQueueHd = tso;
- } else {
- TSO_LINK(prev) = tso;
- }
- } else { /* !found */ /* or not pri sparking! */
- /* Add TSO to the end of the thread queue on that processor */
- TSO_LINK(ThreadQueueTl) = tso;
- ThreadQueueTl = tso;
- }
- return (prev == PrelBase_Z91Z93_closure);
-}
-
-\end{code}
-
-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.
-
-\begin{code}
-HandleIdlePEs()
-{
- PROC proc;
-
-# if defined(GRAN) && defined(GRAN_CHECK)
- if ( RTSflags.GranFlags.Light ) {
- fprintf(stderr,"Qagh {HandleIdlePEs}Daq: Should never be entered in GrAnSim Light setup\n");
- EXIT(EXIT_FAILURE);
- }
-# endif
-
- if(ANY_IDLE)
- for(proc = 0; proc < RTSflags.GranFlags.proc; proc++)
- if(IS_IDLE(proc)) /* && IS_SPARKING(proc) && IS_STARTING(proc) */
- /* First look for local work! */
- if (PendingSparksHd[proc][ADVISORY_POOL]!=NULL)
- {
- new_event(proc,proc,CurrentTime[proc],
- FINDWORK,PrelBase_Z91Z93_closure,PrelBase_Z91Z93_closure,NULL);
- MAKE_SPARKING(proc);
- }
- /* Then try to get remote work! */
- else if ((RTSflags.GranFlags.max_fishes==0 ||
- OutstandingFishes[proc]<RTSflags.GranFlags.max_fishes) )
-
- {
- if(RTSflags.GranFlags.DoStealThreadsFirst &&
- (RTSflags.GranFlags.FetchStrategy >= 4 || OutstandingFetches[proc] == 0))
- {
- if (SurplusThreads > 0l) /* Steal a thread */
- StealThread(proc);
-
- if(!IS_IDLE(proc))
- break;
- }
-
- if(SparksAvail > 0l &&
- (RTSflags.GranFlags.FetchStrategy >= 3 || OutstandingFetches[proc] == 0)) /* Steal a spark */
- StealSpark(proc);
-
- if (SurplusThreads > 0l &&
- (RTSflags.GranFlags.FetchStrategy >= 4 || OutstandingFetches[proc] == 0)) /* Steal a thread */
- StealThread(proc);
- }
-}
-\end{code}
-
-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.
-
-\begin{code}
-StealSpark(proc)
-PROC proc;
-{
- PROC p;
- sparkq spark, prev, next;
- rtsBool stolen = rtsFalse;
- TIME times[MAX_PROC], stealtime;
- unsigned ntimes=0, i, j;
- int first_later, upb, r;
-
-# if defined(GRAN) && defined(GRAN_CHECK)
- if ( RTSflags.GranFlags.Light ) {
- fprintf(stderr,"Qagh {StealSpark}Daq: Should never be entered in GrAnSim Light setup\n");
- EXIT(EXIT_FAILURE);
- }
-# endif
-
- /* times shall contain processors from which we may steal sparks */
- for(p=0; p < RTSflags.GranFlags.proc; ++p)
- if(proc != p &&
- PendingSparksHd[p][ADVISORY_POOL] != NULL &&
- CurrentTime[p] <= CurrentTime[CurrentProc])
- times[ntimes++] = p;
-
- /* sort times */
- for(i=0; i < ntimes; ++i)
- for(j=i+1; j < ntimes; ++j)
- if(CurrentTime[times[i]] > CurrentTime[times[j]])
- {
- unsigned temp = times[i];
- times[i] = times[j];
- times[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_later=0;
- (first_later < ntimes) && (CurrentTime[times[first_later]] < CurrentTime[proc]);
- ++first_later)
- /* nothing */ ;
-
- while (!stolen && (ntimes>0)) {
- long unsigned int r, q=0;
-
- upb = (first_later==0) ? ntimes : first_later;
-
- if (RTSflags.GranFlags.RandomSteal) {
- r = lrand48(); /* [0, RAND_MAX] */
- } else {
- r = 0;
- }
- /* -- ASSERT(r<=RAND_MAX); */
- i = (unsigned int) (r % upb); /* [0, upb) */
- /* -- ASSERT((i>=0) && (i<=upb)); */
- p = times[i];
- /* -- ASSERT((p>=0) && (p<MAX_PROC)); */
-
-# if defined(GRAN_CHECK)
- if ( RTSflags.GranFlags.debug & 0x2000 )
- fprintf(stderr,"RANDOM_STEAL: [index %u of %u] from %u (@ %lu) to %u (@ %lu) (q=%d) [rand value: %lu]\n",
- i, ntimes, p, CurrentTime[p], proc, CurrentTime[proc], q, r);
-# endif
-
- /* Now go through sparkq and steal the first one that should be sparked*/
- for(prev=NULL, spark = PendingSparksHd[p][ADVISORY_POOL];
- spark != NULL && !stolen;
- spark=next)
- {
- next = SPARK_NEXT(spark);
-
- if ((IS_IDLE(p) || procStatus[p]==Sparking || procStatus[p]==Fishing) &&
- SPARK_NEXT(spark)==NULL)
- {
- /* Be social! Don't steal the only spark of an idle processor */
- break;
- }
- else if(SHOULD_SPARK(SPARK_NODE(spark)))
- {
- /* Don't Steal local sparks */
- if(!SPARK_GLOBAL(spark))
- {
- prev=spark;
- continue;
- }
-
- /* Prepare message for sending spark */
- CurrentTime[p] += RTSflags.GranFlags.gran_mpacktime;
-
- if(RTSflags.GranFlags.granSimStats_Sparks)
- DumpRawGranEvent(p,(PROC)0,SP_EXPORTED,PrelBase_Z91Z93_closure,
- SPARK_NODE(spark),
- spark_queue_len(p,ADVISORY_POOL));
-
- SPARK_NEXT(spark) = NULL;
-
- stealtime = (CurrentTime[p] > CurrentTime[proc] ?
- CurrentTime[p] :
- CurrentTime[proc])
- + SparkStealTime();
-
-
- new_event(proc,p /* CurrentProc */,stealtime,
- MOVESPARK,PrelBase_Z91Z93_closure,PrelBase_Z91Z93_closure,spark);
-
- /* MAKE_BUSY(proc); not yet; busy when TSO in threadq */
- stolen = rtsTrue;
- ++OutstandingFishes[proc];
- if (IS_IDLE(proc))
- MAKE_FISHING(proc);
- ++SPARK_GLOBAL(spark);
- --SparksAvail;
-
- CurrentTime[p] += RTSflags.GranFlags.gran_mtidytime;
- }
- else /* !(SHOULD_SPARK(SPARK_NODE(spark))) */
- {
- if(RTSflags.GranFlags.granSimStats_Sparks)
- DumpRawGranEvent(p,(PROC)0,SP_PRUNED,PrelBase_Z91Z93_closure,
- SPARK_NODE(spark),
- spark_queue_len(p,ADVISORY_POOL));
- --SparksAvail;
- DisposeSpark(spark);
- }
-
- if(spark == PendingSparksHd[p][ADVISORY_POOL])
- PendingSparksHd[p][ADVISORY_POOL] = next;
-
- if(prev!=NULL)
- SPARK_NEXT(prev) = next;
- } /* for (spark=... iterating over sparkq */
-
- if(PendingSparksHd[p][ADVISORY_POOL] == NULL)
- PendingSparksTl[p][ADVISORY_POOL] = NULL;
-
- if (!stolen && (ntimes>0)) { /* nothing stealable from proc p :( */
- ASSERT(times[i]==p);
-
- /* remove p from the list (at pos i) */
- for (j=i; j+1<ntimes; j++)
- times[j] = times[j+1];
- ntimes--;
-
- /* update index to first proc which is later (or equal) than proc */
- for ( ;
- (first_later>0) &&
- (CurrentTime[times[first_later-1]]>CurrentTime[proc]);
- first_later--)
- /* nothing */ ;
- }
- } /* while */
-# if defined(GRAN_CHECK)
- if (stolen && (i!=0)) { /* only for statistics */
- rs_sp_count++;
- ntimes_total += ntimes;
- fl_total += first_later;
- no_of_steals++;
- }
-# endif
-}
-\end{code}
-
-Steal a spark and schedule moving it to proc.
-
-\begin{code}
-StealThread(proc)
-PROC proc;
-{
- PROC p;
- rtsBool found;
- P_ thread, prev;
- TIME times[MAX_PROC], stealtime;
- unsigned ntimes=0, i, j;
- int first_later, upb, r;
-
- /* Hunt for a thread */
-
-# if defined(GRAN) && defined(GRAN_CHECK)
- if ( RTSflags.GranFlags.Light ) {
- fprintf(stderr,"Qagh {StealThread}: Should never be entered in GrAnSim Light setup\n");
- EXIT(EXIT_FAILURE);
- }
-# endif
-
- /* times shall contain processors from which we may steal threads */
- for(p=0; p < RTSflags.GranFlags.proc; ++p)
- if(proc != p && RunnableThreadsHd[p] != PrelBase_Z91Z93_closure &&
- CurrentTime[p] <= CurrentTime[CurrentProc])
- times[ntimes++] = p;
-
- /* sort times */
- for(i=0; i < ntimes; ++i)
- for(j=i+1; j < ntimes; ++j)
- if(CurrentTime[times[i]] > CurrentTime[times[j]])
- {
- unsigned temp = times[i];
- times[i] = times[j];
- times[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_later=0;
- (first_later < ntimes) && (CurrentTime[times[first_later]] < CurrentTime[proc]);
- ++first_later)
- /* nothing */ ;
-
- while (!found && (ntimes>0)) {
- long unsigned int r, q=0;
-
- upb = (first_later==0) ? ntimes : first_later;
-
- if (RTSflags.GranFlags.RandomSteal) {
- r = lrand48(); /* [0, RAND_MAX] */
- } else {
- r = 0;
- }
- /* -- ASSERT(r<=RAND_MAX); */
- if ( RTSflags.GranFlags.debug & 0x2000 )
- fprintf(stderr,"rand value: %d " , r);
- i = (unsigned int) (r % upb); /* [0, upb] */
- /* -- ASSERT((i>=0) && (i<=upb)); */
- p = times[i];
- /* -- ASSERT((p>=0) && (p<MAX_PROC)); */
-
-# if defined(GRAN_CHECK)
- if ( RTSflags.GranFlags.debug & 0x2000 )
- fprintf(stderr,"RANDOM_STEAL; [index %u] from %u (@ %lu) to %u (@ %lu) (q=%d)\n",
- i, p, CurrentTime[p], proc, CurrentTime[proc], q);
-# endif
-
- /* Steal the first exportable thread in the runnable queue after the */
- /* first one */
-
- if(RunnableThreadsHd[p] != PrelBase_Z91Z93_closure)
- {
- for(prev = RunnableThreadsHd[p], thread = TSO_LINK(RunnableThreadsHd[p]);
- thread != PrelBase_Z91Z93_closure && TSO_LOCKED(thread);
- prev = thread, thread = TSO_LINK(thread))
- /* SKIP */;
-
- if(thread != PrelBase_Z91Z93_closure) /* Take thread out of runnable queue */
- {
- TSO_LINK(prev) = TSO_LINK(thread);
-
- TSO_LINK(thread) = PrelBase_Z91Z93_closure;
-
- if(RunnableThreadsTl[p] == thread)
- RunnableThreadsTl[p] = prev;
-
- /* Turn magic constants into params !? -- HWL */
-
- CurrentTime[p] += 5l * RTSflags.GranFlags.gran_mpacktime;
-
- stealtime = (CurrentTime[p] > CurrentTime[proc] ?
- CurrentTime[p] :
- CurrentTime[proc])
- + SparkStealTime()
- + 4l * RTSflags.GranFlags.gran_additional_latency
- + 5l * RTSflags.GranFlags.gran_munpacktime;
-
- /* Move the thread; set bitmask to 0 while TSO is `on-the-fly' */
- SET_PROCS(thread,Nowhere /* PE_NUMBER(proc) */);
-
- /* Move from one queue to another */
- new_event(proc,p,stealtime,MOVETHREAD,thread,PrelBase_Z91Z93_closure,NULL);
- /* MAKE_BUSY(proc); not yet; only when thread is in threadq */
- ++OutstandingFishes[proc];
- if (IS_IDLE(proc))
- MAKE_FISHING(proc);
- --SurplusThreads;
-
- if(RTSflags.GranFlags.granSimStats)
- DumpRawGranEvent(p,proc,GR_STEALING,thread,
- PrelBase_Z91Z93_closure,0);
-
- CurrentTime[p] += 5l * RTSflags.GranFlags.gran_mtidytime;
-
- /* Found one */
- found = rtsTrue;
- /* break; */
- }
- }
-
- if (!found && (ntimes>0)) { /* nothing stealable from proc p */
- ASSERT(times[i]==p);
-
- /* remove p from the list (at pos i) */
- for (j=i; j+1<ntimes; j++)
- times[j] = times[j+1];
- ntimes--;
- }
- } /* while */
-# if defined(GRAN_CHECK) && defined(GRAN)
- if (found && (i!=0)) { /* only for statistics */
- rs_t_count++;
- }
-# endif
-}
-
-TIME
-SparkStealTime(void)
-{
- double fishdelay, sparkdelay, latencydelay;
- fishdelay = (double)RTSflags.GranFlags.proc/2;
- sparkdelay = fishdelay -
- ((fishdelay-1)/(double)(RTSflags.GranFlags.proc-1))*(double)idlers();
- latencydelay = sparkdelay*((double)RTSflags.GranFlags.gran_latency);
-
- return((TIME)latencydelay);
-}
-#endif /* GRAN ; HWL */
-
-\end{code}
-
-
-%****************************************************************************
-%
-\subsection[thread-execution]{Executing Threads}
-%
-%****************************************************************************
-
-First a set of functions for handling sparks and spark-queues that are
-attached to the processors. Currently, there are two spark-queues per
-processor:
-
-\begin{itemize}
-\item A queue of @REQUIRED@ sparks i.e. these sparks will be definitely
- turned into threads ({\em non-discardable\/}). They are mainly used in concurrent
- Haskell. We don't use them in GrAnSim.
-\item A queue of @ADVISORY@ sparks i.e. they may be turned into threads if
- the RTS thinks that it is a good idea. However, these sparks are {\em
- discardable}. They will be discarded if the associated closure is
- generally not worth creating a new thread (indicated by a tag in the
- closure) or they may be pruned during GC if there are too many sparks
- around already.
-\end{itemize}
-
-\begin{code}
-EXTDATA_RO(StkO_info);
-EXTDATA_RO(TSO_info);
-EXTDATA_RO(realWorldZh_closure);
-
-EXTFUN(EnterNodeCode);
-UNVEC(EXTFUN(stopThreadDirectReturn);,EXTDATA(vtbl_stopStgWorld);)
-
-#if defined(GRAN)
-/* ngoqvam che' {GrAnSim} */
-
-/* Slow but relatively reliable method uses stgMallocBytes */
-/* Eventually change that to heap allocated sparks. */
-
-/* -------------------------------------------------------------------------
- This is the main point where handling granularity information comes into
- play.
- ------------------------------------------------------------------------- */
-
-#define MAX_RAND_PRI 100
-
-/*
- Granularity info transformers.
- Applied to the GRAN_INFO field of a spark.
-*/
-static I_ ID(I_ x) { return(x); };
-static I_ INV(I_ x) { return(-x); };
-static I_ IGNORE(I_ x) { return (0); };
-static I_ RAND(I_ x) { return ((lrand48() % MAX_RAND_PRI) + 1); }
-
-/* NB: size_info and par_info are currently unused (what a shame!) -- HWL */
-
-sparkq
-NewSpark(node,name,gran_info,size_info,par_info,local)
-P_ node;
-I_ name, gran_info, size_info, par_info, local;
-{
- I_ pri;
- sparkq newspark;
-
- pri = RTSflags.GranFlags.RandomPriorities ? RAND(gran_info) :
- RTSflags.GranFlags.InversePriorities ? INV(gran_info) :
- RTSflags.GranFlags.IgnorePriorities ? IGNORE(gran_info) :
- gran_info;
-
- if ( RTSflags.GranFlags.SparkPriority!=0 && pri<RTSflags.GranFlags.SparkPriority ) {
- if ( RTSflags.GranFlags.debug & 0x40 ) {
- fprintf(stderr,"NewSpark: Ignoring spark of priority %u (SparkPriority=%u); node=0x%lx; name=%u\n",
- pri, RTSflags.GranFlags.SparkPriority, node, name);
- }
- return ((sparkq)NULL);
- }
-
- newspark = (sparkq) stgMallocBytes(sizeof(struct spark), "NewSpark");
- SPARK_PREV(newspark) = SPARK_NEXT(newspark) = NULL;
- SPARK_NODE(newspark) = node;
- SPARK_NAME(newspark) = (name==1) ? TSO_SPARKNAME(CurrentTSO) : name;
- SPARK_GRAN_INFO(newspark) = pri;
- SPARK_GLOBAL(newspark) = !local; /* Check that with parAt, parAtAbs !!*/
- return(newspark);
-}
-
-/* To make casm more convenient use this function to label strategies */
-int
-set_sparkname(P_ tso, int name) {
- TSO_SPARKNAME(tso) = name ;
-
- if(0 && RTSflags.GranFlags.granSimStats)
- DumpRawGranEvent(CurrentProc,99,GR_START,
- tso,PrelBase_Z91Z93_closure,
- TSO_SPARKNAME(tso));
- /* ^^^ SN (spark name) as optional info */
- /* spark_queue_len(CurrentProc,ADVISORY_POOL)); */
- /* ^^^ spark length as optional info */
-
- return(0); }
-
-int
-reset_sparkname(P_ tso) {
- TSO_SPARKNAME(tso) = 0;
- return (0);
-}
-
-/*
- With PrioritySparking add_to_spark_queue performs an insert sort to keep
- the spark queue sorted. Otherwise the spark is just added to the end of
- the queue.
-*/
-
-void
-add_to_spark_queue(spark)
-sparkq spark;
-{
- sparkq prev, next;
- I_ count = 0;
- rtsBool found = rtsFalse;
-
- if ( spark == (sparkq)NULL ) {
- return;
- }
-
- if (RTSflags.GranFlags.DoPrioritySparking && (SPARK_GRAN_INFO(spark)!=0) ) {
-
- for (prev = NULL, next = PendingSparksHd[CurrentProc][ADVISORY_POOL], count=0;
- (next != NULL) &&
- !(found = (SPARK_GRAN_INFO(spark) >= SPARK_GRAN_INFO(next)));
- prev = next, next = SPARK_NEXT(next), count++)
- {}
-
- } else { /* 'utQo' */
-
- found = rtsFalse; /* to add it at the end */
-
- }
-
- if (found) {
- SPARK_NEXT(spark) = next;
- if ( next == NULL ) {
- PendingSparksTl[CurrentProc][ADVISORY_POOL] = spark;
- } else {
- SPARK_PREV(next) = spark;
- }
- SPARK_PREV(spark) = prev;
- if ( prev == NULL ) {
- PendingSparksHd[CurrentProc][ADVISORY_POOL] = spark;
- } else {
- SPARK_NEXT(prev) = spark;
- }
- } else { /* (RTSflags.GranFlags.DoPrioritySparking && !found) || !DoPrioritySparking */
- SPARK_NEXT(spark) = NULL;
- SPARK_PREV(spark) = PendingSparksTl[CurrentProc][ADVISORY_POOL];
- if (PendingSparksHd[CurrentProc][ADVISORY_POOL] == NULL)
- PendingSparksHd[CurrentProc][ADVISORY_POOL] = spark;
- else
- SPARK_NEXT(PendingSparksTl[CurrentProc][ADVISORY_POOL]) = spark;
- PendingSparksTl[CurrentProc][ADVISORY_POOL] = spark;
- }
- ++SparksAvail;
-
- if (RTSflags.GranFlags.DoPrioritySparking) {
- CurrentTime[CurrentProc] += count * RTSflags.GranFlags.gran_pri_spark_overhead;
- }
-
-# if defined(GRAN_CHECK)
- if ( RTSflags.GranFlags.debug & 0x1000 ) {
- for (prev = NULL, next = PendingSparksHd[CurrentProc][ADVISORY_POOL];
- (next != NULL);
- prev = next, next = SPARK_NEXT(next))
- {}
- if ( (prev!=NULL) && (prev!=PendingSparksTl[CurrentProc][ADVISORY_POOL]) )
- fprintf(stderr,"SparkQ inconsistency after adding spark %#lx: (PE %u, pool %u) PendingSparksTl (%#lx) not end of queue (%#lx)\n",
- spark,CurrentProc,ADVISORY_POOL,
- PendingSparksTl[CurrentProc][ADVISORY_POOL], prev);
- }
-# endif
-
-# if defined(GRAN_CHECK)
- /* Check if the sparkq is still sorted. Just for testing, really! */
- if ( RTSflags.GranFlags.debug & 0x400 ) {
- rtsBool sorted = rtsTrue;
- sparkq prev, next;
-
- if (PendingSparksHd[CurrentProc][ADVISORY_POOL] == NULL ||
- SPARK_NEXT(PendingSparksHd[CurrentProc][ADVISORY_POOL]) == NULL ) {
- /* just 1 elem => ok */
- } else {
- for (prev = PendingSparksHd[CurrentProc][ADVISORY_POOL],
- next = SPARK_NEXT(PendingSparksHd[CurrentProc][ADVISORY_POOL]);
- (next != NULL) ;
- prev = next, next = SPARK_NEXT(next)) {
- sorted = sorted &&
- (SPARK_GRAN_INFO(prev) >= SPARK_GRAN_INFO(next));
- }
- }
- if (!sorted) {
- fprintf(stderr,"Warning: SPARKQ on PE %d is not sorted:\n",
- CurrentProc);
- G_SPARKQ(PendingSparksHd[CurrentProc][ADVISORY_POOL],1);
- }
- }
-# endif
-}
-
-void
-DisposeSpark(spark)
-sparkq spark;
-{
- /* A SP_PRUNED line should be dumped when this is called from pruning or */
- /* discarding a spark! */
-
- if(spark!=NULL)
- free(spark);
-
- --SparksAvail;
-}
-
-void
-DisposeSparkQ(spark)
-sparkq spark;
-{
- if (spark==NULL)
- return;
-
- DisposeSparkQ(SPARK_NEXT(spark));
-
-# ifdef GRAN_CHECK
- if (SparksAvail < 0)
- fprintf(stderr,"DisposeSparkQ: SparksAvail<0 after disposing sparkq @ 0x%lx\n", spark);
-# endif
-
- free(spark);
-}
-
-#endif /* GRAN */
-\end{code}
-
-% {GrAnSim}vaD (Notes on GrAnSim) -- HWL:
-% Qu'vaD ngoq
-% NB: mayQo' wIvwI'
-
-\paragraph{Notes on GrAnSim:}
-The following routines are for handling threads. Currently, we use an
-unfair scheduling policy in GrAnSim. Thus there are no explicit functions for
-scheduling here. If other scheduling policies are added to the system that
-code should go in here.
-
-\begin{code}
-/* Create a new TSO, with the specified closure to enter and thread type */
-
-#if defined(GRAN)
-P_
-NewThread(topClosure, type, pri)
-P_ topClosure;
-W_ type;
-I_ pri;
-#else
-P_
-NewThread(topClosure, type)
-P_ topClosure;
-W_ type;
-#endif /* GRAN */
-{
- P_ stko, tso;
-
-# if defined(GRAN) && defined(GRAN_CHECK)
- if ( RTSflags.GranFlags.Light && CurrentProc!=0) {
- fprintf(stderr,"Qagh {NewThread}Daq: CurrentProc must be 0 in GrAnSim Light setup\n");
- EXIT(EXIT_FAILURE);
- }
-# endif
- if (AvailableTSO != PrelBase_Z91Z93_closure) {
- tso = AvailableTSO;
-#if defined(GRAN)
- SET_PROCS(tso,ThisPE); /* Allocate it locally! */
-#endif
- AvailableTSO = TSO_LINK(tso);
- } else if (SAVE_Hp + TSO_HS + TSO_CTS_SIZE > SAVE_HpLim) {
- return(NULL);
- } else {
- ALLOC_TSO(TSO_HS,BYTES_TO_STGWORDS(sizeof(STGRegisterTable)),
- BYTES_TO_STGWORDS(sizeof(StgDouble)));
- tso = SAVE_Hp + 1;
- SAVE_Hp += TSO_HS + TSO_CTS_SIZE;
- SET_TSO_HDR(tso, TSO_info, CCC);
- }
-
- TSO_LINK(tso) = PrelBase_Z91Z93_closure;
-#if defined(GRAN)
- TSO_PRI(tso) = pri; /* Priority of that TSO -- HWL */
-#endif
-#if defined(PROFILING) || defined(PAR)
- TSO_CCC(tso) = (CostCentre)STATIC_CC_REF(CC_MAIN);
-#endif
- TSO_NAME(tso) = (P_) INFO_PTR(topClosure); /* A string would be nicer -- JSM */
- TSO_ID(tso) = threadId++;
- TSO_TYPE(tso) = type;
- TSO_PC1(tso) = TSO_PC2(tso) = EnterNodeCode;
- TSO_ARG1(tso) = /* TSO_ARG2(tso) = */ 0;
- TSO_SWITCH(tso) = NULL;
-
-#ifdef TICKY_TICKY
- TSO_AHWM(tso) = 0;
- TSO_BHWM(tso) = 0;
-#endif
-
-#if defined(GRAN) || defined(PAR)
- TSO_SPARKNAME(tso) = 0;
-# if defined(GRAN)
- TSO_STARTEDAT(tso) = CurrentTime[CurrentProc];
-# else
- TSO_STARTEDAT(tso) = CURRENT_TIME;
-# endif
- TSO_EXPORTED(tso) = 0;
- TSO_BASICBLOCKS(tso) = 0;
- TSO_ALLOCS(tso) = 0;
- TSO_EXECTIME(tso) = 0;
- TSO_FETCHTIME(tso) = 0;
- TSO_FETCHCOUNT(tso) = 0;
- TSO_BLOCKTIME(tso) = 0;
- TSO_BLOCKCOUNT(tso) = 0;
- TSO_BLOCKEDAT(tso) = 0;
- TSO_GLOBALSPARKS(tso) = 0;
- TSO_LOCALSPARKS(tso) = 0;
-# if defined(GRAN)
- if (RTSflags.GranFlags.Light)
- TSO_CLOCK(tso) = TSO_STARTEDAT(tso); /* local clock */
- else
-# endif
- TSO_CLOCK(tso) = 0;
-#endif
- /*
- * set pc, Node (R1), liveness
- */
- CurrentRegTable = TSO_INTERNAL_PTR(tso);
- SAVE_Liveness = LIVENESS_R1;
- SAVE_R1.p = topClosure;
-
-# ifndef PAR
- if (type == T_MAIN) {
- stko = MainStkO;
- } else {
-# endif
- if (AvailableStack != PrelBase_Z91Z93_closure) {
- stko = AvailableStack;
-#if defined(GRAN)
- SET_PROCS(stko,ThisPE);
-#endif
- AvailableStack = STKO_LINK(AvailableStack);
- } else if (SAVE_Hp + STKO_HS + RTSflags.ConcFlags.stkChunkSize > SAVE_HpLim) {
- return(NULL);
- } else {
- /* ALLOC_STK(STKO_HS,STKO_CHUNK_SIZE,0); use RTSflag now*/
- ALLOC_STK(STKO_HS,RTSflags.ConcFlags.stkChunkSize,0);
- stko = SAVE_Hp + 1;
- SAVE_Hp += STKO_HS + RTSflags.ConcFlags.stkChunkSize;
- SET_STKO_HDR(stko, StkO_info, CCC);
- }
- STKO_SIZE(stko) = RTSflags.ConcFlags.stkChunkSize + STKO_VHS;
- STKO_SpB(stko) = STKO_SuB(stko) = STKO_BSTK_BOT(stko) + BREL(1);
- STKO_SpA(stko) = STKO_SuA(stko) = STKO_ASTK_BOT(stko) + AREL(1);
- STKO_LINK(stko) = PrelBase_Z91Z93_closure;
- STKO_RETURN(stko) = NULL;
-# ifndef PAR
- }
-# endif
-
-#ifdef TICKY_TICKY
- STKO_ADEP(stko) = STKO_BDEP(stko) = 0;
-#endif
-
- if (type == T_MAIN) {
- STKO_SpB(stko) -= BREL(1);
- *STKO_SpB(stko) = (P_) realWorldZh_closure;
- }
-
- SAVE_Ret = (StgRetAddr) UNVEC(stopThreadDirectReturn,vtbl_stopStgWorld);
- SAVE_StkO = stko;
-
- if (DO_QP_PROF) {
- QP_Event1(do_qp_prof > 1 ? "*A" : "*G", tso);
- }
-#if defined(GRAN_CHECK)
- tot_sq_len += spark_queue_len(CurrentProc,ADVISORY_POOL);
- tot_sq_probes++;
-#endif
- return tso;
-}
-
-\end{code}
-
-In GrAnSim the @EndThread@ function is the place where statistics about the
-simulation are printed. I guess, that could be moved into @main.lc@.
-
-\begin{code}
-
-void
-EndThread(STG_NO_ARGS)
-{
- P_ stko;
-#if defined(PAR)
- TIME now = CURRENT_TIME;
-#endif
-
-#ifdef TICKY_TICKY
- if (RTSflags.TickyFlags.showTickyStats) {
- fprintf(RTSflags.TickyFlags.tickyFile,
- "Thread %d (%lx)\n\tA stack max. depth: %ld words\n",
- TSO_ID(CurrentTSO), TSO_NAME(CurrentTSO), TSO_AHWM(CurrentTSO));
- fprintf(RTSflags.TickyFlags.tickyFile,
- "\tB stack max. depth: %ld words\n",
- TSO_BHWM(CurrentTSO));
- }
-#endif
-
- if (DO_QP_PROF) {
- QP_Event1("G*", CurrentTSO);
- }
-
-#if defined(GRAN)
- ASSERT(CurrentTSO == ThreadQueueHd);
-
- if (RTSflags.GranFlags.DoThreadMigration)
- --SurplusThreads;
-
- if(TSO_TYPE(CurrentTSO)==T_MAIN)
- {
- int i;
- rtsBool is_first;
- for(i=0; i < RTSflags.GranFlags.proc; ++i) {
- is_first = rtsTrue;
- while(RunnableThreadsHd[i] != PrelBase_Z91Z93_closure)
- {
- /* We schedule runnable threads before killing them to */
- /* make the job of bookkeeping the running, runnable, */
- /* blocked threads easier for scripts like gr2ps -- HWL */
-
- if (RTSflags.GranFlags.granSimStats && !is_first &&
- (!RTSflags.GranFlags.Light || RTSflags.GranFlags.debug & 0x20000) )
- DumpRawGranEvent(i,(PROC)0,GR_SCHEDULE,
- RunnableThreadsHd[i],
- PrelBase_Z91Z93_closure,0);
- if (!RTSflags.GranFlags.granSimStats_suppressed &&
- TSO_TYPE(RunnableThreadsHd[i])!=T_MAIN)
- DumpGranInfo(i,RunnableThreadsHd[i],rtsTrue);
- RunnableThreadsHd[i] = TSO_LINK(RunnableThreadsHd[i]);
- is_first = rtsFalse;
- }
- }
-
- ThreadQueueHd = PrelBase_Z91Z93_closure;
- /* Printing of statistics has been moved into end_gr_simulation */
- } /* ... T_MAIN */
-
- if (RTSflags.GranFlags.labelling && RTSflags.GranFlags.granSimStats &&
- !RTSflags.GranFlags.granSimStats_suppressed)
- DumpStartEventAt(TSO_STARTEDAT(CurrentTSO),where_is(CurrentTSO),0,GR_START,
- CurrentTSO,PrelBase_Z91Z93_closure,
- TSO_SPARKNAME(CurrentTSO));
- /* ^^^ SN (spark name) as optional info */
- /* spark_queue_len(CurrentProc,ADVISORY_POOL)); */
- /* ^^^ spark length as optional info */
-
- if (RTSflags.GranFlags.granSimStats &&
- !RTSflags.GranFlags.granSimStats_suppressed)
- DumpGranInfo(CurrentProc,CurrentTSO,
- TSO_TYPE(CurrentTSO) != T_ADVISORY);
-
- if (RTSflags.GranFlags.granSimStats_Binary &&
- TSO_TYPE(CurrentTSO)==T_MAIN &&
- !RTSflags.GranFlags.granSimStats_suppressed)
- grterminate(CurrentTime[CurrentProc]);
-
- if (TSO_TYPE(CurrentTSO)!=T_MAIN)
- ActivateNextThread(CurrentProc);
-
- /* Note ThreadQueueHd is Nil when the main thread terminates
- if(ThreadQueueHd != PrelBase_Z91Z93_closure)
- {
- if (RTSflags.GranFlags.granSimStats && !RTSflags.GranFlags.granSimStats_suppressed &&
- (!RTSflags.GranFlags.Light || RTSflags.GranFlags.debug & 0x20000) )
- DumpGranEvent(GR_SCHEDULE,ThreadQueueHd);
- CurrentTime[CurrentProc] += RTSflags.GranFlags.gran_threadscheduletime;
- }
- */
-
-#endif /* GRAN */
-
-#ifdef PAR
- if (RTSflags.ParFlags.granSimStats) {
- TSO_EXECTIME(CurrentTSO) += now - TSO_BLOCKEDAT(CurrentTSO);
- DumpGranInfo(thisPE, CurrentTSO, TSO_TYPE(CurrentTSO) != T_ADVISORY);
- }
-#endif
-
- switch (TSO_TYPE(CurrentTSO)) {
- case T_MAIN:
- required_thread_count--;
-
-#ifdef PAR
- if (GRANSIMSTATS_BINARY)
- grterminate(now);
-#endif
-#ifdef GRAN
- longjmp(scheduler_loop, -1); /* i.e. the world comes to an end NOW */
-#else
- ReSchedule(0); /* i.e. the world will eventually come to an end */
-#endif
-
- case T_REQUIRED:
- required_thread_count--;
- break;
-
- case T_ADVISORY:
- advisory_thread_count--;
- break;
-
- case T_FAIL:
- EXIT(EXIT_FAILURE);
-
- default:
- fflush(stdout);
- fprintf(stderr, "EndThread: %x unknown\n", TSO_TYPE(CurrentTSO));
- EXIT(EXIT_FAILURE);
- }
-
- /* Reuse stack object space */
- ASSERT(STKO_LINK(SAVE_StkO) == PrelBase_Z91Z93_closure);
- STKO_LINK(SAVE_StkO) = AvailableStack;
- AvailableStack = SAVE_StkO;
- /* Reuse TSO */
- TSO_LINK(CurrentTSO) = AvailableTSO;
- AvailableTSO = CurrentTSO;
- CurrentTSO = PrelBase_Z91Z93_closure;
- CurrentRegTable = NULL;
-
-#if defined(GRAN)
- /* NB: Now ThreadQueueHd is either the next runnable thread on this */
- /* proc or it's PrelBase_Z91Z93_closure. In the latter case, a FINDWORK will be */
- /* issued by ReSchedule. */
- ReSchedule(SAME_THREAD); /* back for more! */
-#else
- ReSchedule(0); /* back for more! */
-#endif
-}
-
-\end{code}
-
-%****************************************************************************
-%
-\subsection[thread-blocking]{Local Blocking}
-%
-%****************************************************************************
-
-\begin{code}
-
-#if defined(GRAN_COUNT)
-/* Some non-essential maybe-useful statistics-gathering */
-void CountnUPDs() { ++nUPDs; }
-void CountnUPDs_old() { ++nUPDs_old; }
-void CountnUPDs_new() { ++nUPDs_new; }
-
-void CountnPAPs() { ++nPAPs; }
-#endif
-
-EXTDATA_RO(BQ_info);
-
-#ifndef GRAN
-/* NB: non-GRAN version ToDo
- *
- * AwakenBlockingQueue awakens a list of TSOs and FBQs.
- */
-
-P_ PendingFetches = PrelBase_Z91Z93_closure;
-
-void
-AwakenBlockingQueue(bqe)
- P_ bqe;
-{
- P_ last_tso = NULL;
-
-# ifdef PAR
- P_ next;
- TIME now = CURRENT_TIME;
-
-# endif
-
-# ifndef PAR
- while (bqe != PrelBase_Z91Z93_closure) {
-# else
- while (IS_MUTABLE(INFO_PTR(bqe))) {
- switch (INFO_TYPE(INFO_PTR(bqe))) {
- case INFO_TSO_TYPE:
-# endif
- if (DO_QP_PROF) {
- QP_Event2(do_qp_prof > 1 ? "RA" : "RG", bqe, CurrentTSO);
- }
-# ifdef PAR
- if (RTSflags.ParFlags.granSimStats) {
- DumpGranEvent(GR_RESUMEQ, bqe);
- switch (TSO_QUEUE(bqe)) {
- case Q_BLOCKED:
- TSO_BLOCKTIME(bqe) += now - TSO_BLOCKEDAT(bqe);
- break;
- case Q_FETCHING:
- TSO_FETCHTIME(bqe) += now - TSO_BLOCKEDAT(bqe);
- break;
- default:
- fflush(stdout);
- fprintf(stderr, "ABQ: TSO_QUEUE invalid.\n");
- EXIT(EXIT_FAILURE);
- }
- }
-# endif
- if (last_tso == NULL) {
- if (RunnableThreadsHd == PrelBase_Z91Z93_closure) {
- RunnableThreadsHd = bqe;
- } else {
- TSO_LINK(RunnableThreadsTl) = bqe;
- }
- }
- last_tso = bqe;
- bqe = TSO_LINK(bqe);
-# ifdef PAR
- break;
- case INFO_BF_TYPE:
- next = BF_LINK(bqe);
- BF_LINK(bqe) = PendingFetches;
- PendingFetches = bqe;
- bqe = next;
- if (last_tso != NULL)
- TSO_LINK(last_tso) = next;
- break;
- default:
- fprintf(stderr, "Unexpected IP (%#lx) in blocking queue at %#lx\n",
- INFO_PTR(bqe), (W_) bqe);
- EXIT(EXIT_FAILURE);
- }
- }
-# else
- }
-# endif
- if (last_tso != NULL) {
- RunnableThreadsTl = last_tso;
-# ifdef PAR
- TSO_LINK(last_tso) = PrelBase_Z91Z93_closure;
-# endif
- }
-}
-#endif /* !GRAN */
-
-#ifdef GRAN
-
-# if defined(GRAN_CHECK)
-
-/* First some useful test functions */
-
-EXTFUN(RBH_Save_0_info);
-EXTFUN(RBH_Save_1_info);
-EXTFUN(RBH_Save_2_info);
-
-void
-PRINT_BQ(bqe)
-P_ bqe;
-{
- W_ it;
- P_ last = NULL;
- char str[80], str0[80];
-
- fprintf(stderr,"\n[PE %d] @ %lu BQ: ",
- CurrentProc,CurrentTime[CurrentProc]);
- if ( bqe == PrelBase_Z91Z93_closure ) {
- fprintf(stderr," NIL.\n");
- return;
- }
- if ( bqe == NULL ) {
- fprintf(stderr," NULL\n");
- return;
- }
- while (IS_MUTABLE(INFO_PTR(bqe))) { /* This distinguishes TSOs from */
- W_ proc; /* RBH_Save_? closures! */
-
- /* Find where the tso lives */
- proc = where_is(bqe);
- it = INFO_TYPE(INFO_PTR(bqe));
-
- switch (it) {
- case INFO_TSO_TYPE:
- strcpy(str0,"TSO");
- break;
- case INFO_BQ_TYPE:
- strcpy(str0,"BQ");
- break;
- default:
- strcpy(str0,"???");
- break;
- }
-
- if(proc == CurrentProc)
- fprintf(stderr," %#lx (%x) L %s,", bqe, TSO_ID(bqe), str0);
- else
- fprintf(stderr," %#lx (%x) G (PE %d) %s,", bqe, TSO_ID(bqe), proc, str0);
-
- last = bqe;
- switch (it) {
- case INFO_TSO_TYPE:
- bqe = TSO_LINK(bqe);
- break;
- case INFO_BQ_TYPE:
- bqe = TSO_LINK(bqe);
- break;
- default:
- bqe = PrelBase_Z91Z93_closure;
- break;
- }
- /* TSO_LINK(last_tso) = PrelBase_Z91Z93_closure; */
- }
- if ( bqe == PrelBase_Z91Z93_closure )
- fprintf(stderr," NIL.\n");
- else if (
- (INFO_PTR(bqe) == (P_) RBH_Save_0_info) ||
- (INFO_PTR(bqe) == (P_) RBH_Save_1_info) ||
- (INFO_PTR(bqe) == (P_) RBH_Save_2_info) )
- fprintf(stderr," RBH.\n");
- /* fprintf(stderr,"\n%s\n",str); */
- }
-
-rtsBool
-CHECK_BQ(node, tso, proc)
-P_ node, tso;
-PROC proc;
-{
- P_ bqe;
- W_ it;
- P_ last = NULL;
- PROC p = where_is(tso);
- rtsBool ok = rtsTrue;
-
- if ( p != proc) {
- fprintf(stderr,"ERROR in CHECK_BQ: CurrentTSO %#lx (%x) on proc %d but CurrentProc = %d\n",
- tso, TSO_ID(tso), proc);
- ok = rtsFalse;
- }
-
- switch (INFO_TYPE(INFO_PTR(node))) {
- case INFO_BH_TYPE:
- case INFO_BH_U_TYPE:
- bqe = (P_) BQ_ENTRIES(node);
- return (rtsTrue); /* BHs don't have BQs */
- break;
- case INFO_BQ_TYPE:
- bqe = (P_) BQ_ENTRIES(node);
- break;
- case INFO_FMBQ_TYPE:
- fprintf(stderr,"CHECK_BQ: ERROR: FMBQ closure (%#lx) found in GrAnSim (TSO=%#lx (%x))\n",
- node, tso, TSO_ID(tso));
- EXIT(EXIT_FAILURE);
- break;
- case INFO_SPEC_RBH_TYPE:
- bqe = (P_) SPEC_RBH_BQ(node);
- break;
- case INFO_GEN_RBH_TYPE:
- bqe = (P_) GEN_RBH_BQ(node);
- break;
- default:
- {
- P_ info_ptr;
- I_ size, ptrs, nonptrs, vhs;
- char info_hdr_ty[80];
-
- fprintf(stderr, "CHECK_BQ: thought %#lx was a black hole (IP %#lx)",
- node, INFO_PTR(node));
- info_ptr = get_closure_info(node,
- &size, &ptrs, &nonptrs, &vhs,
- info_hdr_ty);
- fprintf(stderr, " %s\n",info_hdr_ty);
- /* G_PRINT_NODE(node); */
- return (rtsFalse);
- /* EXIT(EXIT_FAILURE); */
- }
- }
-
- while (IS_MUTABLE(INFO_PTR(bqe))) { /* This distinguishes TSOs from */
- W_ proc; /* RBH_Save_? closures! */
-
- /* Find where the tso lives */
- proc = where_is(bqe);
- it = INFO_TYPE(INFO_PTR(bqe));
-
- if ( bqe == tso ) {
- fprintf(stderr,"ERROR in CHECK_BQ [Node = 0x%lx, PE %d]: TSO %#lx (%x) already in BQ: ",
- node, proc, tso, TSO_ID(tso));
- PRINT_BQ(BQ_ENTRIES(node));
- ok = rtsFalse;
- }
-
- bqe = TSO_LINK(bqe);
- }
- return (ok);
-}
-/* End of test functions */
-# endif /* GRAN_CHECK */
-
-/* This version of AwakenBlockingQueue has been originally taken from the
- GUM code. It is now assimilated into GrAnSim */
-
-/* Note: This version assumes a pointer to a blocking queue rather than a
- node with an attached blocking queue as input */
-
-P_
-AwakenBlockingQueue(bqe)
-P_ bqe;
-{
- /* P_ tso = (P_) BQ_ENTRIES(node); */
- P_ last = NULL;
- /* P_ prev; */
- W_ notifytime;
-
-# if 0
- if(do_gr_sim)
-# endif
-
- /* Compatibility mode with old libaries! 'oH jIvoQmoH */
- if (IS_BQ_CLOSURE(bqe))
- bqe = (P_)BQ_ENTRIES(bqe);
- else if ( INFO_TYPE(INFO_PTR(bqe)) == INFO_SPEC_RBH_TYPE )
- bqe = (P_)SPEC_RBH_BQ(bqe);
- else if ( INFO_TYPE(INFO_PTR(bqe)) == INFO_GEN_RBH_TYPE )
- bqe = (P_)GEN_RBH_BQ(bqe);
-
-# if defined(GRAN_CHECK)
- if ( RTSflags.GranFlags.debug & 0x100 ) {
- PRINT_BQ(bqe);
- }
-# endif
-
-# if defined(GRAN_COUNT)
- ++nUPDs;
- if (tso != PrelBase_Z91Z93_closure)
- ++nUPDs_BQ;
-# endif
-
-# if defined(GRAN_CHECK)
- if (RTSflags.GranFlags.debug & 0x100)
- fprintf(stderr,"----- AwBQ: ");
-# endif
-
- while (IS_MUTABLE(INFO_PTR(bqe))) { /* This distinguishes TSOs from */
- W_ proc; /* RBH_Save_? closures! */
- ASSERT(INFO_TYPE(INFO_PTR(bqe)) == INFO_TSO_TYPE);
-
- if (DO_QP_PROF) {
- QP_Event2(do_qp_prof > 1 ? "RA" : "RG", bqe, CurrentTSO);
- }
-# if defined(GRAN_COUNT)
- ++BQ_lens;
-# endif
-
- /* Find where the tso lives */
- proc = where_is(bqe);
-
- if(proc == CurrentProc) {
- notifytime = CurrentTime[CurrentProc] + RTSflags.GranFlags.gran_lunblocktime;
- } else {
- /* A better way of handling this would be to introduce a
- GLOBALUNBLOCK event which is created here. -- HWL */
- CurrentTime[CurrentProc] += RTSflags.GranFlags.gran_mpacktime;
- notifytime = STG_MAX(CurrentTime[CurrentProc],CurrentTime[proc]) +
- RTSflags.GranFlags.gran_gunblocktime;
- CurrentTime[CurrentProc] += RTSflags.GranFlags.gran_mtidytime;
- /* new_event(proc, CurrentProc, notifytime,
- GLOBALUNBLOCK,bqe,PrelBase_Z91Z93_closure,NULL); */
- }
- /* cost the walk over the queue */
- CurrentTime[CurrentProc] += RTSflags.GranFlags.gran_lunblocktime;
- /* GrAnSim Light: make blocked TSO aware of the time that passed */
- if (RTSflags.GranFlags.Light)
- TSO_CLOCK(bqe) = notifytime;
- /* and create a resume message */
- new_event(proc, CurrentProc, notifytime,
- RESUMETHREAD,bqe,PrelBase_Z91Z93_closure,NULL);
-
- if (notifytime<TimeOfNextEvent)
- TimeOfNextEvent = notifytime;
-
-# if defined(GRAN_CHECK)
- if (RTSflags.GranFlags.debug & 0x100) {
- fprintf(stderr," TSO %x (PE %d) %s,",
- TSO_ID(bqe), proc, ( (proc==CurrentProc) ? "L" : "G") );
- }
-# endif
-
- last = bqe;
- bqe = TSO_LINK(bqe);
- TSO_LINK(last) = PrelBase_Z91Z93_closure;
- } /* while */
-
-# if 0
- /* This was once used in a !do_gr_sim setup. Now only GrAnSim setup is */
- /* supported. */
- else /* Check if this is still valid for non-GrAnSim code -- HWL */
- {
- if (ThreadQueueHd == PrelBase_Z91Z93_closure)
- ThreadQueueHd = bqe;
- else
- TSO_LINK(ThreadQueueTl) = bqe;
-
- if (RunnableThreadsHd == PrelBase_Z91Z93_closure)
- RunnableThreadsHd = tso;
- else
- TSO_LINK(RunnableThreadsTl) = tso;
-
-
- while(TSO_LINK(bqe) != PrelBase_Z91Z93_closure) {
- assert(TSO_INTERNAL_PTR(bqe)->rR[0].p == node);
-# if 0
- if (DO_QP_PROF) {
- QP_Event2(do_qp_prof > 1 ? "RA" : "RG", bqe, CurrentTSO);
- }
-# endif
- bqe = TSO_LINK(bqe);
- }
-
- assert(TSO_INTERNAL_PTR(bqe)->rR[0].p == node);
-# if 0
- if (DO_QP_PROF) {
- QP_Event2(do_qp_prof > 1 ? "RA" : "RG", bqe, CurrentTSO);
- }
-# endif
- }
-# endif /* 0 */
-
- if (RTSflags.GranFlags.debug & 0x100)
- fprintf(stderr,".\n");
-
- return (bqe);
- /* ngo' {GrAnSim}Qo' ngoq: RunnableThreadsTl = tso; */
-}
-#endif /* GRAN */
-
-EXTFUN(Continue);
-
-
-#if defined(GRAN)
-
-/* Different interface for GRAN */
-void
-Yield(liveness)
-W_ liveness;
-{
- SAVE_Liveness = liveness;
- TSO_PC1(CurrentTSO) = Continue;
- if (DO_QP_PROF) {
- QP_Event1("GR", CurrentTSO);
- }
- ReSchedule(SAME_THREAD);
-}
-
-#else /* !GRAN */
-
-void
-Yield(args)
-W_ args;
-{
- SAVE_Liveness = args >> 1;
- TSO_PC1(CurrentTSO) = Continue;
- if (DO_QP_PROF) {
- QP_Event1("GR", CurrentTSO);
- }
-#ifdef PAR
- if (RTSflags.ParFlags.granSimStats) {
- /* Note that CURRENT_TIME may perform an unsafe call */
- TSO_EXECTIME(CurrentTSO) += CURRENT_TIME - TSO_BLOCKEDAT(CurrentTSO);
- }
-#endif
- ReSchedule(args & 1);
-}
-
-#endif /* GRAN */
-\end{code}
-
-
-%****************************************************************************
-%
-\subsection[gr-fetch]{Fetching Nodes (GrAnSim only)}
-%
-%****************************************************************************
-
-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.
-
-
-\begin{code}
-#if defined(GRAN)
-/* ngoqvam che' {GrAnSim}! */
-
-/* Fetch node "node" to processor "p" */
-
-int
-FetchNode(node,from,to)
-P_ node;
-PROC from, to;
-{
- /* In case of RTSflags.GranFlags.DoGUMMFetching this fct should never be
- entered! Instead, UnpackGraph is used in ReSchedule */
- P_ closure;
-
- ASSERT(to==CurrentProc);
-
-# if defined(GRAN) && defined(GRAN_CHECK)
- if ( RTSflags.GranFlags.Light ) {
- fprintf(stderr,"Qagh {FetchNode}Daq: Should never be entered in GrAnSim Light setup\n");
- EXIT(EXIT_FAILURE);
- }
-# endif
-
- if ( RTSflags.GranFlags.DoGUMMFetching ) {
- fprintf(stderr,"Qagh: FetchNode should never be entered with DoGUMMFetching\n");
- EXIT(EXIT_FAILURE);
- }
-
- /* Now fetch the children */
- if (!IS_LOCAL_TO(PROCS(node),from) &&
- !IS_LOCAL_TO(PROCS(node),to) )
- return 1;
-
- if(IS_NF(INFO_PTR(node))) /* Old: || IS_BQ(node) */
- PROCS(node) |= PE_NUMBER(to); /* Copy node */
- else
- PROCS(node) = PE_NUMBER(to); /* Move node */
-
- return 0;
-}
-
-/* --------------------------------------------------
- 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].
- -------------------------------------------------- */
-
-/* Return codes:
- 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).
-
- ToDo: Symbolic return codes; clean up code (separate GUMMFetching from
- single node fetching.
-*/
-
-I_
-HandleFetchRequest(node,p,tso)
-P_ node, tso;
-PROC p;
-{
- ASSERT(!RTSflags.GranFlags.Light);
-
- if (IS_LOCAL_TO(PROCS(node),p) ) /* Somebody else moved node already => */
- { /* start tso */
-# if defined(GRAN_CHECK)
- if (RTSflags.GranFlags.debug & 0x100 ) {
- P_ info_ptr;
- I_ size, ptrs, nonptrs, vhs;
- char info_hdr_ty[80];
-
- info_ptr = get_closure_info(node,
- &size, &ptrs, &nonptrs, &vhs,
- info_hdr_ty);
- fprintf(stderr,"Warning: HandleFetchRequest entered with local node %#lx (%s) (PE %d)\n",
- node,info_hdr_ty,p);
- }
-# endif
- if (RTSflags.GranFlags.DoGUMMFetching) {
- W_ size;
- P_ graph;
-
- /* Create a 1-node-buffer and schedule a FETCHREPLY now */
- graph = PackOneNode(node, tso, &size);
- new_event(p,CurrentProc,CurrentTime[CurrentProc],
- FETCHREPLY,tso,graph,NULL);
- } else {
- new_event(p,CurrentProc,CurrentTime[CurrentProc],
- FETCHREPLY,tso,node,NULL);
- }
- return (1);
- }
- else if (IS_LOCAL_TO(PROCS(node),CurrentProc) ) /* Is node still here? */
- {
- if(RTSflags.GranFlags.DoGUMMFetching) { /* {GUM}vo' ngoqvam vInIHta' (code from GUM) */
- W_ size;
- P_ graph;
-
- if (IS_BLACK_HOLE(INFO_PTR(node))) { /* block on BH or RBH */
- new_event(p,CurrentProc,CurrentTime[p],
- GLOBALBLOCK,tso,node,NULL);
- /* Note: blockFetch is done when handling GLOBALBLOCK event */
- /* 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[p];
- return (3);
- }
-
-# if defined(GRAN_CHECK)
- if (!RTSflags.GranFlags.DoReScheduleOnFetch && (tso != RunnableThreadsHd[p])) {
- fprintf(stderr,"Qagh {HandleFetchRequest}Daq: tso 0x%lx (%x) not at head of proc %d (0x%lx)\n",
- tso, TSO_ID(tso), p, RunnableThreadsHd[p]);
- EXIT(EXIT_FAILURE);
- }
-# endif
-
- if ((graph = PackNearbyGraph(node, tso, &size)) == NULL)
- return (4); /* 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[CurrentProc] += size * RTSflags.GranFlags.gran_mpacktime;
-
- new_event(p,CurrentProc,CurrentTime[CurrentProc]+RTSflags.GranFlags.gran_latency,
- FETCHREPLY,tso,graph,NULL);
-
- CurrentTime[CurrentProc] += RTSflags.GranFlags.gran_mtidytime;
- return (0);
- } else { /* incremental (single closure) fetching */
- /* Actual moving/copying of node is done on arrival; see FETCHREPLY */
- /* Send a reply to the originator */
- CurrentTime[CurrentProc] += RTSflags.GranFlags.gran_mpacktime;
-
- new_event(p,CurrentProc,CurrentTime[CurrentProc]+RTSflags.GranFlags.gran_latency,
- FETCHREPLY,tso,node,NULL);
-
- CurrentTime[CurrentProc] += RTSflags.GranFlags.gran_mtidytime;
- return (0);
- }
- }
- else /* Qu'vatlh! node has been grabbed by another proc => forward */
- {
- PROC p_new = where_is(node);
- TIME fetchtime;
-
-# if defined(GRAN_CHECK)
- if (RTSflags.GranFlags.debug & 0x2)
- fprintf(stderr,"Qu'vatlh! node %#lx has been grabbed by PE %d (current=%d; demander=%d) @ %d\n",
- node,p_new,CurrentProc,p,CurrentTime[CurrentProc]);
-# endif
- /* Prepare FORWARD message to proc p_new */
- CurrentTime[CurrentProc] += RTSflags.GranFlags.gran_mpacktime;
-
- fetchtime = STG_MAX(CurrentTime[CurrentProc],CurrentTime[p_new]) +
- RTSflags.GranFlags.gran_latency;
-
- new_event(p_new,p,fetchtime,FETCHNODE,tso,node,NULL);
-
- CurrentTime[CurrentProc] += RTSflags.GranFlags.gran_mtidytime;
-
- return (2);
- }
-}
-#endif
-\end{code}
-
-@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.
-
-\begin{code}
-#if defined(GRAN)
-
-/* Return codes:
- 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
-*/
-
-I_
-blockFetch(tso, proc, bh)
-P_ tso; /* TSO which gets blocked */
-PROC proc; /* PE where that tso was running */
-P_ bh; /* closure to block on (BH, RBH, BQ) */
-{
-# if defined(GRAN_CHECK)
- if ( RTSflags.GranFlags.debug & 0x100 ) {
- P_ info_ptr;
- I_ size, ptrs, nonptrs, vhs;
- char info_hdr_ty[80];
-
- info_ptr = get_closure_info(bh,
- &size, &ptrs, &nonptrs, &vhs,
- info_hdr_ty);
- fprintf(stderr,"Blocking TSO %#lx (%x)(PE %d) on node %#lx (%s) (PE %d). No graph is packed!\n",
- tso, TSO_ID(tso), proc, bh, info_hdr_ty, where_is(bh));
- }
-
- if ( !RTSflags.GranFlags.DoReScheduleOnFetch && (tso != RunnableThreadsHd[proc]) ) {
- fprintf(stderr,"Qagh {blockFetch}Daq: TSO 0x%lx (%x) is not first on runnable list of proc %d (first is 0x%lx)\n",
- tso,TSO_ID(tso),proc,RunnableThreadsHd[proc]);
- EXIT(EXIT_FAILURE);
- }
-# endif
-
- if (!IS_BLACK_HOLE(INFO_PTR(bh))) { /* catches BHs and RBHs */
-# if defined(GRAN_CHECK)
- if ( RTSflags.GranFlags.debug & 0x100 ) {
- P_ info;
- W_ size, ptrs, nonptrs, vhs;
- char str[80], junk_str[80];
-
- info = get_closure_info(bh, &size, &ptrs, &nonptrs, &vhs, str);
- fprintf(stderr,"blockFetch: node %#lx (%s) is not a BH => awakening TSO %#lx (%x) (PE %u)\n",
- bh, str, tso, TSO_ID(tso), proc);
- G_PRINT_NODE(bh);
- }
-# endif
- /* No BH anymore => immediately unblock tso */
- new_event(proc,proc,CurrentTime[proc],
- UNBLOCKTHREAD,tso,bh,NULL);
-
- /* Is this always a REPLY to a FETCH in the profile ? */
- if (RTSflags.GranFlags.granSimStats)
- DumpRawGranEvent(proc,proc,GR_REPLY,tso,bh,0);
- return (1);
- }
-
- /* DaH {BQ}Daq Qu' Suq 'e' wISov!
- Now we know that we have to put the tso into the BQ.
- 2 case: 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
- */
- if (!RTSflags.GranFlags.DoReScheduleOnFetch) { /* block-on-fetch */
- GranSimBlock(tso, proc, bh); /* get tso out of threadq & activate next
- thread (same as in BQ_entry) */
- } else { /* reschedule-on-fetch */
- if(RTSflags.GranFlags.granSimStats)
- DumpRawGranEvent(proc,where_is(bh),GR_BLOCK,tso,bh,0);
-
- ++TSO_BLOCKCOUNT(tso);
- TSO_BLOCKEDAT(tso) = CurrentTime[proc];
- }
-
- ASSERT(TSO_LINK(tso)==PrelBase_Z91Z93_closure);
-
- /* Put tso into BQ */
- switch (INFO_TYPE(INFO_PTR(bh))) {
- case INFO_BH_TYPE:
- case INFO_BH_U_TYPE:
- TSO_LINK(tso) = PrelBase_Z91Z93_closure;
- SET_INFO_PTR(bh, BQ_info);
- BQ_ENTRIES(bh) = (W_) tso;
-
-#ifdef GC_MUT_REQUIRED
- /*
- * 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 INFO_BQ_TYPE:
- /* BF_LINK(bf) = (P_) BQ_ENTRIES(bh); */
- TSO_LINK(tso) = (P_) BQ_ENTRIES(bh);
- BQ_ENTRIES(bh) = (W_) tso;
- break;
- case INFO_FMBQ_TYPE:
- fprintf(stderr,"ERROR: FMBQ closure (%#lx) found in GrAnSim (TSO=%#lx (%x))\n",
- bh, tso, TSO_ID(tso));
- EXIT(EXIT_FAILURE);
- case INFO_SPEC_RBH_TYPE:
- /* BF_LINK(bf) = (P_) BQ_ENTRIES(bh); */
- TSO_LINK(tso) = (P_) SPEC_RBH_BQ(bh);
- SPEC_RBH_BQ(bh) = (W_) tso;
- break;
- case INFO_GEN_RBH_TYPE:
- /* BF_LINK(bf) = (P_) BQ_ENTRIES(bh); */
- TSO_LINK(tso) = (P_) GEN_RBH_BQ(bh);
- GEN_RBH_BQ(bh) = (W_) tso;
- break;
- default:
- {
- P_ info_ptr;
- I_ size, ptrs, nonptrs, vhs;
- char info_hdr_ty[80];
-
- fprintf(stderr, "Panic: thought %#lx was a black hole (IP %#lx)",
- bh, INFO_PTR(bh));
-# if defined(GRAN_CHECK)
- info_ptr = get_closure_info(bh,
- &size, &ptrs, &nonptrs, &vhs,
- info_hdr_ty);
- fprintf(stderr, " %s\n",info_hdr_ty);
- G_PRINT_NODE(bh);
-# endif
- EXIT(EXIT_FAILURE);
- }
- }
- return (0);
-}
-
-#endif /* GRAN */
-\end{code}
-
-%****************************************************************************
-%
-\subsection[qp-profile]{Quasi-Parallel Profiling}
-%
-%****************************************************************************
-
-\begin{code}
-/* ToDo: Check if this is really still used anywhere!? */
-
-I_ do_qp_prof;
-FILE *qp_file;
-
-/* *Virtual* Time in milliseconds */
-#if !defined(GRAN)
-long
-qp_elapsed_time(STG_NO_ARGS)
-{
- extern StgDouble usertime();
-
- return ((long) (usertime() * 1e3));
-}
-#else
-long
-qp_elapsed_time(STG_NO_ARGS)
-{
- return ((long) CurrentTime[CurrentProc] );
-}
-#endif
-
-static void
-init_qp_profiling(STG_NO_ARGS)
-{
- I_ i;
- char qp_filename[STATS_FILENAME_MAXLEN];
-
- sprintf(qp_filename, QP_FILENAME_FMT, prog_argv[0]);
- if ((qp_file = fopen(qp_filename,"w")) == NULL ) {
- fprintf(stderr, "Can't open quasi-parallel profile report file %s\n",
- qp_filename);
- do_qp_prof = 0;
- } else {
- fputs(prog_argv[0], qp_file);
- for(i = 1; prog_argv[i]; i++) {
- fputc(' ', qp_file);
- fputs(prog_argv[i], qp_file);
- }
- fprintf(qp_file, " +RTS -C%d -t%d\n"
- , RTSflags.ConcFlags.ctxtSwitchTime
- , RTSflags.ConcFlags.maxThreads);
-
- fputs(time_str(), qp_file);
- fputc('\n', qp_file);
- }
-}
-
-void
-QP_Event0(tid, node)
-I_ tid;
-P_ node;
-{
- fprintf(qp_file, "%lu ** %lu 0x%lx\n", qp_elapsed_time(), tid, INFO_PTR(node));
-}
-
-void
-QP_Event1(event, tso)
-char *event;
-P_ tso;
-{
- fprintf(qp_file, "%lu %s %lu 0x%lx\n", qp_elapsed_time(), event,
- TSO_ID(tso), TSO_NAME(tso));
-}
-
-void
-QP_Event2(event, tso1, tso2)
-char *event;
-P_ tso1, tso2;
-{
- fprintf(qp_file, "%lu %s %lu 0x%lx %lu 0x%lx\n", qp_elapsed_time(), event,
- TSO_ID(tso1), TSO_NAME(tso1), TSO_ID(tso2), TSO_NAME(tso2));
-}
-
-\end{code}
-
-%****************************************************************************
-%
-\subsection[gc-GrAnSim]{Garbage collection routines for GrAnSim objects}
-%
-%****************************************************************************
-
-Garbage collection code for the event queue. We walk the event queue
-so that if the only reference to a TSO is in some event (e.g. RESUME),
-the TSO is still preserved.
-
-The GC code now uses a breadth-first pruning strategy. This prevents
-the GC from keeping all sparks of the low-numbered PEs while discarding all
-sparks from high-numbered PEs. Such a depth-first pruning may have
-disastrous effects for programs that generate a huge number of sparks!
-
-\begin{code}
-#if defined(GRAN)
-
-extern smInfo StorageMgrInfo;
-
-/* Auxiliary functions needed in Save/RestoreSparkRoots if breadth-first */
-/* pruning is done. */
-
-static W_
-arr_and(W_ arr[], I_ max)
-{
- I_ i;
- W_ res;
-
- /* Doesn't work with max==0; but then, many things don't work in this */
- /* special case. */
- for (i=1, res = arr[0]; i<max; i++)
- res &= arr[i];
-
- return (res);
-}
-
-static W_
-arr_max(W_ arr[], I_ max)
-{
- I_ i;
- W_ res;
-
- /* Doesn't work with max==0; but then, many things don't work in this */
- /* special case. */
- for (i=1, res = arr[0]; i<max; i++)
- res = (arr[i]>res) ? arr[i] : res;
-
- return (res);
-}
-
-/*
- Routines working on spark queues.
- It would be a good idea to make that an ADT!
-*/
-
-I_
-spark_queue_len(PROC proc, I_ pool)
-{
- sparkq prev, spark; /* prev only for testing !! */
- I_ len;
-
- for (len = 0, prev = NULL, spark = PendingSparksHd[proc][pool];
- spark != NULL;
- len++, prev = spark, spark = SPARK_NEXT(spark))
- {}
-
-# if defined(GRAN_CHECK)
- if ( RTSflags.GranFlags.debug & 0x1000 )
- if ( (prev!=NULL) && (prev!=PendingSparksTl[proc][pool]) )
- fprintf(stderr,"ERROR in spark_queue_len: (PE %u, pool %u) PendingSparksTl (%#lx) not end of queue (%#lx)\n",
- proc, pool, PendingSparksTl[proc][pool], prev);
-# endif
-
- return (len);
-}
-
-sparkq
-delete_from_spark_queue (prev,spark) /* unlink and dispose spark */
-sparkq prev, spark;
-{ /* Global Vars: CurrentProc, SparkQueueHd, SparkQueueTl */
- sparkq tmp;
-
-# if defined(GRAN_CHECK)
- if ( RTSflags.GranFlags.debug & 0x10000 ) {
- fprintf(stderr,"** |%#x:%#x| prev=%#x->(%#x), (%#x)<-spark=%#x->(%#x) <-(%#x)\n",
- SparkQueueHd, SparkQueueTl,
- prev, (prev==NULL ? 0 : SPARK_NEXT(prev)),
- SPARK_PREV(spark), spark, SPARK_NEXT(spark),
- (SPARK_NEXT(spark)==NULL ? 0 : SPARK_PREV(SPARK_NEXT(spark))));
- }
-# endif
-
- tmp = SPARK_NEXT(spark);
- if (prev==NULL) {
- SparkQueueHd = SPARK_NEXT(spark);
- } else {
- SPARK_NEXT(prev) = SPARK_NEXT(spark);
- }
- if (SPARK_NEXT(spark)==NULL) {
- SparkQueueTl = prev;
- } else {
- SPARK_PREV(SPARK_NEXT(spark)) = prev;
- }
- if(SparkQueueHd == NULL)
- SparkQueueTl = NULL;
- SPARK_NEXT(spark) = NULL;
-
- DisposeSpark(spark);
-
- spark = tmp;
-# if defined(GRAN_CHECK)
- if ( RTSflags.GranFlags.debug & 0x10000 ) {
- fprintf(stderr,"## prev=%#x->(%#x)\n",
- prev, (prev==NULL ? 0 : SPARK_NEXT(prev)));
- }
-# endif
- return (tmp);
-}
-
-#if 0
-/* NB: These functions have been replaced by functions:
- EvacuateEvents, EvacuateSparks, (in ../storage/SMcopying.lc)
- LinkEvents, LinkSparks (in ../storage/SMcompacting.lc)
- Thus, GrAnSim does not need additional entries in the list of roots
- any more.
-*/
-
-I_
-SaveEventRoots(num_ptr_roots)
-I_ num_ptr_roots;
-{
- eventq event = EventHd;
- while(event != NULL)
- {
- if(EVENT_TYPE(event) == RESUMETHREAD ||
- EVENT_TYPE(event) == MOVETHREAD ||
- EVENT_TYPE(event) == CONTINUETHREAD ||
- /* EVENT_TYPE(event) >= CONTINUETHREAD1 || */
- EVENT_TYPE(event) == STARTTHREAD )
- StorageMgrInfo.roots[num_ptr_roots++] = EVENT_TSO(event);
-
- else if(EVENT_TYPE(event) == MOVESPARK)
- StorageMgrInfo.roots[num_ptr_roots++] = SPARK_NODE(EVENT_SPARK(event));
-
- else if (EVENT_TYPE(event) == FETCHNODE ||
- EVENT_TYPE(event) == FETCHREPLY )
- {
- StorageMgrInfo.roots[num_ptr_roots++] = EVENT_TSO(event);
- /* In the case of packet fetching, EVENT_NODE(event) points to */
- /* the packet (currently, malloced). The packet is just a list of */
- /* closure addresses, with the length of the list at index 1 (the */
- /* structure of the packet is defined in Pack.lc). */
- if ( RTSflags.GranFlags.DoGUMMFetching && (EVENT_TYPE(event)==FETCHREPLY)) {
- P_ buffer = (P_) EVENT_NODE(event);
- int size = (int) buffer[PACK_SIZE_LOCN], i;
-
- for (i = PACK_HDR_SIZE; i <= size-1; i++) {
- StorageMgrInfo.roots[num_ptr_roots++] = (P_) buffer[i];
- }
- } else
- StorageMgrInfo.roots[num_ptr_roots++] = EVENT_NODE(event);
- }
- else if (EVENT_TYPE(event) == GLOBALBLOCK)
- {
- StorageMgrInfo.roots[num_ptr_roots++] = EVENT_TSO(event);
- StorageMgrInfo.roots[num_ptr_roots++] = EVENT_NODE(event);
- }
- else if (EVENT_TYPE(event) == UNBLOCKTHREAD)
- {
- StorageMgrInfo.roots[num_ptr_roots++] = EVENT_TSO(event);
- }
- event = EVENT_NEXT(event);
- }
- return(num_ptr_roots);
-}
-
-#if defined(DEPTH_FIRST_PRUNING)
-/* Is it worthwhile keeping the depth-first pruning code !? -- HWL */
-
-I_
-SaveSparkRoots(num_ptr_roots)
-I_ num_ptr_roots;
-{
- sparkq spark, /* prev, */ disposeQ=NULL;
- PROC proc;
- I_ i, sparkroots=0, prunedSparks=0;
- I_ tot_sparks[MAX_PROC], tot = 0;;
-
- for(proc = 0; proc < RTSflags.GranFlags.proc; ++proc) {
- tot_sparks[proc] = 0;
- for(i = 0; i < SPARK_POOLS; ++i) {
- for(/* prev = &PendingSparksHd[proc][i],*/ spark = PendingSparksHd[proc][i];
- spark != NULL;
- /* prev = &SPARK_NEXT(spark), */ spark = SPARK_NEXT(spark))
- {
- if(++sparkroots <= MAX_SPARKS)
- {
- if ( RTSflags.GcFlags.giveStats )
- if (i==ADVISORY_POOL) {
- tot_sparks[proc]++;
- tot++;
- }
- StorageMgrInfo.roots[num_ptr_roots++] = SPARK_NODE(spark);
- }
- else
- {
- SPARK_NODE(spark) = PrelBase_Z91Z93_closure;
- if (prunedSparks==0) {
- disposeQ = spark;
- /*
- *prev = NULL;
- */
- }
- prunedSparks++;
- }
- } /* forall spark ... */
- if ( (RTSflags.GcFlags.giveStats) && (prunedSparks>0) ) {
- fprintf(RTSflags.GcFlags.statsFile,"Pruning and disposing %lu excess sparks (> %lu) on proc %d for GC purposes\n",
- prunedSparks,MAX_SPARKS,proc);
- if (disposeQ == PendingSparksHd[proc][i])
- PendingSparksHd[proc][i] = NULL;
- else
- SPARK_NEXT(SPARK_PREV(disposeQ)) = NULL;
- DisposeSparkQ(disposeQ);
- prunedSparks = 0;
- disposeQ = NULL;
- }
- } /* forall i ... */
- } /*forall proc .. */
-
- if ( RTSflags.GcFlags.giveStats ) {
- fprintf(RTSflags.GcFlags.statsFile,
- "Spark statistics (after pruning) (total sparks = %d):",tot);
- for (proc=0; proc<RTSflags.GranFlags.proc; proc++) {
- if (proc % 4 == 0)
- fprintf(RTSflags.GcFlags.statsFile,"\n> ");
- fprintf(RTSflags.GcFlags.statsFile,"\tPE %d: %d ",proc,tot_sparks[proc]);
- }
- fprintf(RTSflags.GcFlags.statsFile,".\n");
- }
-
- return(num_ptr_roots);
-}
-
-#else /* !DEPTH_FIRST_PRUNING */
-
-/* In case of an excessive number of sparks, depth first pruning is a Bad */
-/* Idea as we might end up with all remaining sparks on processor 0 and */
-/* none on the other processors. So, this version uses breadth first */
-/* pruning. -- HWL */
-
-I_
-SaveSparkRoots(num_ptr_roots)
-I_ num_ptr_roots;
-{
- sparkq spark,
- curr_spark[MAX_PROC][SPARK_POOLS];
- PROC proc;
- W_ allProcs = 0,
- endQueues[SPARK_POOLS], finishedQueues[SPARK_POOLS];
- I_ i, sparkroots=0,
- prunedSparks[MAX_PROC][SPARK_POOLS];
- I_ tot_sparks[MAX_PROC], tot = 0;;
-
-
-# if defined(GRAN_CHECK) && defined(GRAN)
- if ( RTSflags.GranFlags.debug & 0x40 )
- fprintf(stderr,"D> Saving spark roots for GC ...\n");
-# endif
-
- /* Init */
- for(proc = 0; proc < RTSflags.GranFlags.proc; ++proc) {
- allProcs |= PE_NUMBER(proc);
- tot_sparks[proc] = 0;
- for(i = 0; i < SPARK_POOLS; ++i) {
- curr_spark[proc][i] = PendingSparksHd[proc][i];
- prunedSparks[proc][i] = 0;
- endQueues[i] = 0;
- finishedQueues[i] = 0;
- }
- }
-
- /* Breadth first pruning */
- do {
- for(proc = 0; proc < RTSflags.GranFlags.proc; ++proc) {
- for(i = 0; i < SPARK_POOLS; ++i) {
- spark = curr_spark[proc][i];
- if ( spark != NULL ) {
-
- if(++sparkroots <= MAX_SPARKS)
- {
-# if defined(GRAN_CHECK) && defined(GRAN)
- if ( (RTSflags.GranFlags.debug & 0x1000) &&
- (RTSflags.GcFlags.giveStats) )
- fprintf(RTSflags.GcFlags.statsFile,"Saving Spark Root %d(proc: %d; pool: %d): 0x%lx \t(info ptr=%#lx)\n",
- num_ptr_roots,proc,i,SPARK_NODE(spark),
- INFO_PTR(SPARK_NODE(spark)));
-# endif
- if ( RTSflags.GcFlags.giveStats )
- if (i==ADVISORY_POOL) {
- tot_sparks[proc]++;
- tot++;
- }
- StorageMgrInfo.roots[num_ptr_roots++] = SPARK_NODE(spark);
- curr_spark[proc][i] = spark = SPARK_NEXT(spark);
- }
- else /* sparkroots > MAX_SPARKS */
- {
- if (curr_spark[proc][i] == PendingSparksHd[proc][i])
- PendingSparksHd[proc][i] = NULL;
- else
- SPARK_NEXT(SPARK_PREV(curr_spark[proc][i])) = NULL;
- PendingSparksTl[proc][i] = SPARK_PREV(curr_spark[proc][i]);
- endQueues[i] |= PE_NUMBER(proc);
- }
- } else { /* spark == NULL ; actually, this only has to be done once */
- endQueues[i] |= PE_NUMBER(proc);
- }
- }
- }
- } while (arr_and(endQueues,SPARK_POOLS) != allProcs);
-
- /* The buffer for spark roots in StorageMgrInfo.roots is full */
- /* now. Prune all sparks on all processor starting with */
- /* curr_spark[proc][i]. */
-
- do {
- for(proc = 0; proc < RTSflags.GranFlags.proc; ++proc) {
- for(i = 0; i < SPARK_POOLS; ++i) {
- spark = curr_spark[proc][i];
-
- if ( spark != NULL ) {
- SPARK_NODE(spark) = PrelBase_Z91Z93_closure;
- curr_spark[proc][i] = SPARK_NEXT(spark);
-
- prunedSparks[proc][i]++;
- DisposeSpark(spark);
- } else {
- finishedQueues[i] |= PE_NUMBER(proc);
- }
- }
- }
- } while (arr_and(finishedQueues,SPARK_POOLS) != allProcs);
-
-
-# if defined(GRAN_CHECK) && defined(GRAN)
- if ( RTSflags.GranFlags.debug & 0x1000) {
- for(proc = 0; proc < RTSflags.GranFlags.proc; ++proc) {
- for(i = 0; i < SPARK_POOLS; ++i) {
- if ( (RTSflags.GcFlags.giveStats) && (prunedSparks[proc][i]>0)) {
- fprintf(RTSflags.GcFlags.statsFile,
- "Discarding %lu sparks on proc %d (pool %d) for GC purposes\n",
- prunedSparks[proc][i],proc,i);
- }
- }
- }
-
- if ( RTSflags.GcFlags.giveStats ) {
- fprintf(RTSflags.GcFlags.statsFile,
- "Spark statistics (after discarding) (total sparks = %d):",tot);
- for (proc=0; proc<RTSflags.GranFlags.proc; proc++) {
- if (proc % 4 == 0)
- fprintf(RTSflags.GcFlags.statsFile,"\n> ");
- fprintf(RTSflags.GcFlags.statsFile,
- "\tPE %d: %d ",proc,tot_sparks[proc]);
- }
- fprintf(RTSflags.GcFlags.statsFile,".\n");
- }
- }
-# endif
-
- return(num_ptr_roots);
-}
-
-#endif /* DEPTH_FIRST_PRUNING */
-
-/*
- GC roots must be restored in *reverse order*.
- The recursion is a little ugly, but is better than
- in-place pointer reversal.
-*/
-
-static I_
-RestoreEvtRoots(event,num_ptr_roots)
-eventq event;
-I_ num_ptr_roots;
-{
- if(event != NULL)
- {
- num_ptr_roots = RestoreEvtRoots(EVENT_NEXT(event),num_ptr_roots);
-
- if(EVENT_TYPE(event) == RESUMETHREAD ||
- EVENT_TYPE(event) == MOVETHREAD ||
- EVENT_TYPE(event) == CONTINUETHREAD ||
- /* EVENT_TYPE(event) >= CONTINUETHREAD1 || */
- EVENT_TYPE(event) == STARTTHREAD )
- EVENT_TSO(event) = StorageMgrInfo.roots[--num_ptr_roots];
-
- else if(EVENT_TYPE(event) == MOVESPARK )
- SPARK_NODE(EVENT_SPARK(event)) = StorageMgrInfo.roots[--num_ptr_roots];
-
- else if (EVENT_TYPE(event) == FETCHNODE ||
- EVENT_TYPE(event) == FETCHREPLY )
- {
- if ( RTSflags.GranFlags.DoGUMMFetching && (EVENT_TYPE(event)==FETCHREPLY)) {
- P_ buffer = (P_) EVENT_NODE(event);
- int size = (int) buffer[PACK_SIZE_LOCN], i;
-
- for (i = size-1; i >= PACK_HDR_SIZE; i--) {
- buffer[i] = StorageMgrInfo.roots[--num_ptr_roots];
- }
- } else
- EVENT_NODE(event) = StorageMgrInfo.roots[--num_ptr_roots];
-
- EVENT_TSO(event) = StorageMgrInfo.roots[--num_ptr_roots];
- }
- else if (EVENT_TYPE(event) == GLOBALBLOCK)
- {
- EVENT_NODE(event) = StorageMgrInfo.roots[--num_ptr_roots];
- EVENT_TSO(event) = StorageMgrInfo.roots[--num_ptr_roots];
- }
- else if (EVENT_TYPE(event) == UNBLOCKTHREAD)
- {
- EVENT_TSO(event) = StorageMgrInfo.roots[--num_ptr_roots];
- }
- }
- return(num_ptr_roots);
-}
-
-I_
-RestoreEventRoots(num_ptr_roots)
-I_ num_ptr_roots;
-{
- return(RestoreEvtRoots(EventHd,num_ptr_roots));
-}
-
-#if defined(DEPTH_FIRST_PRUNING)
-
-static I_
-RestoreSpkRoots(spark,num_ptr_roots,sparkroots)
-sparkq spark;
-I_ num_ptr_roots, sparkroots;
-{
- if(spark != NULL)
- {
- num_ptr_roots = RestoreSpkRoots(SPARK_NEXT(spark),num_ptr_roots,++sparkroots);
- if(sparkroots <= MAX_SPARKS)
- {
- P_ n = SPARK_NODE(spark);
- SPARK_NODE(spark) = StorageMgrInfo.roots[--num_ptr_roots];
-# if defined(GRAN_CHECK) && defined(GRAN)
- if ( RTSflags.GranFlags.debug & 0x40 )
- fprintf(RTSflags.GcFlags.statsFile,
- "Restoring Spark Root %d: 0x%lx \t(info ptr=%#lx\n",
- num_ptr_roots,SPARK_NODE(spark),
- INFO_PTR(SPARK_NODE(spark)));
-# endif
- }
-# if defined(GRAN_CHECK) && defined(GRAN)
- else
- if ( RTSflags.GranFlags.debug & 0x40 )
- fprintf(RTSflags.GcFlags.statsFile,
- "Error in RestoreSpkRoots (%d; @ spark %#lx): More than MAX_SPARKS (%d) sparks\n",
- num_ptr_roots,SPARK_NODE(spark),MAX_SPARKS);
-# endif
-
- }
- return(num_ptr_roots);
-}
-
-I_
-RestoreSparkRoots(num_ptr_roots)
-I_ num_ptr_roots;
-{
- PROC proc;
- I_ i;
-
-#if defined(GRAN_JSM_SPARKS)
- fprintf(stderr,"Error: RestoreSparkRoots should be never be entered in a JSM style sparks set-up\n");
- EXIT(EXIT_FAILURE);
-#endif
-
- /* NB: PROC is currently an unsigned datatype i.e. proc>=0 is always */
- /* true ((PROC)-1 == (PROC)255). So we need a second clause in the head */
- /* of the for loop. For i that is currently not necessary. C is really */
- /* impressive in datatype abstraction! -- HWL */
-
- for(proc = RTSflags.GranFlags.proc - 1; (proc >= 0) && (proc < RTSflags.GranFlags.proc); --proc) {
- for(i = SPARK_POOLS - 1; (i >= 0) && (i < SPARK_POOLS) ; --i) {
- num_ptr_roots = RestoreSpkRoots(PendingSparksHd[proc][i],num_ptr_roots,0);
- }
- }
- return(num_ptr_roots);
-}
-
-#else /* !DEPTH_FIRST_PRUNING */
-
-I_
-RestoreSparkRoots(num_ptr_roots)
-I_ num_ptr_roots;
-{
- sparkq spark,
- curr_spark[MAX_PROC][SPARK_POOLS];
- PROC proc;
- I_ i, max_len, len, pool, count,
- queue_len[MAX_PROC][SPARK_POOLS];
-
- /* NB: PROC is currently an unsigned datatype i.e. proc>=0 is always */
- /* true ((PROC)-1 == (PROC)255). So we need a second clause in the head */
- /* of the for loop. For i that is currently not necessary. C is really */
- /* impressive in datatype abstraction! -- HWL */
-
- max_len=0;
- for (proc=0; proc < RTSflags.GranFlags.proc; proc++) {
- for (i=0; i<SPARK_POOLS; i++) {
- curr_spark[proc][i] = PendingSparksTl[proc][i];
- queue_len[proc][i] = spark_queue_len(proc,i);
- max_len = (queue_len[proc][i]>max_len) ? queue_len[proc][i] : max_len;
- }
- }
-
- for (len=max_len; len > 0; len--){
- for(proc = RTSflags.GranFlags.proc - 1; (proc >= 0) && (proc < RTSflags.GranFlags.proc); --proc) {
- for(i = SPARK_POOLS - 1; (i >= 0) && (i < SPARK_POOLS) ; --i) {
- if (queue_len[proc][i]>=len) {
- spark = curr_spark[proc][i];
- SPARK_NODE(spark) = StorageMgrInfo.roots[--num_ptr_roots];
-# if defined(GRAN_CHECK) && defined(GRAN)
- count++;
- if ( (RTSflags.GranFlags.debug & 0x1000) &&
- (RTSflags.GcFlags.giveStats) )
- fprintf(RTSflags.GcFlags.statsFile,
- "Restoring Spark Root %d (PE %u, pool %u): 0x%lx \t(info ptr=%#lx)\n",
- num_ptr_roots,proc,i,SPARK_NODE(spark),
- INFO_PTR(SPARK_NODE(spark)));
-# endif
- curr_spark[proc][i] = SPARK_PREV(spark);
- /*
- num_ptr_roots = RestoreSpkRoots(PendingSparksHd[proc][i],
- num_ptr_roots,0);
- */
- }
- }
- }
- }
-# if defined(GRAN_CHECK) && defined(GRAN)
- if ( (RTSflags.GranFlags.debug & 0x1000) && (RTSflags.GcFlags.giveStats) )
- fprintf(RTSflags.GcFlags.statsFile,"Number of restored spark roots: %d\n",
- count);
-# endif
- return(num_ptr_roots);
-}
-
-#endif /* DEPTH_FIRST_PRUNING */
-
-#endif /* 0 */
-
-#endif /* GRAN */
-
-#endif /* CONCURRENT */ /* the whole module! */
-\end{code}
-
-