/* --------------------------------------------------------------------------
   Time-stamp: <Fri Mar 19 2010 22:22:06 Stardate: Stardate: [-28]2789.66 hwloidl>

   Variables and functions specific to the parallel RTS (i.e. GUM or GranSim)
   ----------------------------------------------------------------------- */

#if defined(PARALLEL_RTS) /* whole file */

#ifndef PARALLEL_RTS_H
#define PARALLEL_RTS_H

#include "ParTicky.h"

#  define PACK_GA_SIZE	3	/* Size of a packed GA in words */
			        /* Size of a packed fetch-me in words */
#  define PACK_FETCHME_SIZE (PACK_GA_SIZE + HEADERSIZE)

#define PACK_BUFFER_SIZE(buffer) (PACK_BUFFER_HDR_SIZEW+DEBUG_HEADROOM+(buffer->size))
#define PACK_BUFFER_PAYLOAD_SIZE(buffer) (buffer->size)

// needed in various places; should go into a global .h file -- HWL GUM6EDEN

#define MIN_GA_WEIGHT      4      /* smallest legal weight; values lower than this
				  are tags; see Global.c:splitWeight and Pack:isOffset etc -- HWL GUM6 */

#define MAX_GA_STR_LEN  40
#define MAX_GALA_STR_LEN  80

// used as args to sendFish
#define NEW_FISH_AGE           0
#define NEW_FISH_HISTORY       0
#define NEW_FISH_HUNGER        0
#define FISH_LIFE_EXPECTANCY  10

// these used to be in includes/Parallel.h, but they don't have to be

// entry to scheduler for remote PEs, in Schedule.c, called from Main.c
void startWorking(Capability *cap);


// Runtimetable: linked list of processes
// in RTTables.c
void initRTT(void); // init for process list and internal variables

// ports: declared in RtsTypes.h, constants here
#define PORTSIZE sizeof(Port)/sizeof(StgWord)

// fixed system ports: RTS port and NoPort constant 
extern Port RtsPort, NoPort;
/* Port RtsPort = Port {thisPe, 0, 0}; */
/* Port NoPort  = Port {0, 0, 0};      */

/* delay (in us) between dying fish returning and sending out a new fish */
#define FISH_DELAY                   1000
/* max no. of outstanding spark steals */
#define MAX_FISHES                   1  
/* max no. of outstanding spark steals */
#define MAX_THREADS                  1024  

/* spark buffer size, ie. max no. of local sparks */
#define MAX_LOCAL_SPARKS             1024  
/* low- and high-watermarks for spark pool */
#define SPARK_LWM                    1
#define SPARK_HWM                    10
#define SPARK_POOLS                 2
// minimum sizes for mSPARK_POOLessages and buffers: 
// messages must contain tag as a data field, plus a separator
#define MSG_HEADER     2
// All messages contain a header and 2 ports, 
#define MIN_MSG       ( 2*PORTSIZE + MSG_HEADER)
// if we use message buffering, we must add a packet header: (RtsFlags.h to be included!)
#define PACKET_HEADER (RtsFlags.ParFlags.BufferTime?3:0)
// =>  minimum data space for a MessageBuffer (in words!) is max. msg.size:
#define DATASPACEWORDS ( ((int) RtsFlags.ParFlags.packBufferSize/sizeof(StgWord)) \
			+ PACK_BUFFER_HDR_SIZEW	 \
			+ MIN_MSG + PACKET_HEADER)


// extern variables
// PVMComms.c or MPIComms.c
extern rtsBool	IAmMainThread;
extern nat nPEs; 
extern nat thisPE;
// DataComms.c
extern nat targetPE; 
// ParInit.c
extern rtsBool fishing;             /* We have no fish out in the stream */
extern nat advisory_thread_count;         /* number of threads (for par) created */
extern rtsTime next_fish_to_send_at;          /* expected time of next fish */
extern rtsTime last_fish_arrived_at;       /* Time of arrival of most recent fish*/

extern nat     outstandingFishes;          /* Number of active fishes */ 
//@cindex PendingFetches
/* A list of fetch reply messages not yet processed; this list is filled
   by awaken_blocked_queue and processed by processFetches */
extern GALA *blockedFetches;


extern nat totFISH, totSCHEDULE, totACK, totSPARK, totFREE, totFETCH,totSPK;
extern nat totPackets, totUnpacked;
/* global structure for collecting statistics */

// prototypes
// Global.c
/* TODO: move this into one general, parallel-specific .h file */
StgClosure*   UNWIND_IND(StgClosure *closureT);                        // tag-safe
StgInfoTable* get_closure_info(StgClosure* node, nat *size, nat *ptrs, // tag-safe
			       nat *nonptrs, nat *vhs);

StgClosure *GALAlookup(globalAddr *ga);
globalAddr *LAGAlookup(StgClosure *addr);
globalAddr *makeGlobal(StgClosure *closureT, rtsBool preferred);
globalAddr *setRemoteGA(StgClosure *local_closureT, globalAddr *remote_ga, rtsBool preferred);
void        setFetchedLA (StgTSO *t);
StgWord     PackGA (StgWord pe, int slot); 
rtsBool     isGhostrTSO(StgTSO *tso);
void        deallocGALA(GALA *bf_gc);
void        checkBFQ(Capability *cap);
nat         GALA_list_len (GALA *gala);


// Pack.c
void        convertToFetchMe(StgRBH *rbh, globalAddr *ga);
StgClosure *convertToRBH(StgClosure *closure);

// HLComms
void        packAndSendResume(StgClosure *closure, GALA *bf);

/* HWL HACK: compile time sanity checks; shouldn't be necessary at all */
#if defined(PAR) && defined(GRAN)
# error "Both PAR and GRAN defined"
#endif

#if defined(DEBUG)
/* Paranoia debugging: we add an end-of-buffer marker to every pack buffer 
                       (only when sanity checking RTS is enabled, of course) */
#define  DEBUG_HEADROOM        1
#define  END_OF_BUFFER_MARKER  0x1111bbbb
#define  GARBAGE_MARKER        0x1111eeee
#else
#define  DEBUG_HEADROOM        0
#endif /* DEBUG */

/* Statistics info */

/* global structure for collecting statistics */
typedef struct GlobalParStats_ {
  /* GALA and LAGA table info */
  nat tot_mark_GA, tot_rebuild_GA, tot_free_GA,
      res_mark_GA, res_rebuild_GA, res_free_GA,
      cnt_mark_GA, cnt_rebuild_GA, cnt_free_GA,
      res_size_GA, tot_size_GA, local_alloc_GA, tot_global, tot_local;

  /* time spent managing the GAs */
  double time_mark_GA, time_rebuild_GA,time_active;

  /* spark queue stats */
  nat res_sp, tot_sp, cnt_sp, emp_sp;
  // nat tot_sq_len, tot_sq_probes, tot_sparks;
  /* thread queue stats */
  nat res_tp, tot_tp, cnt_tp, emp_tp;
  //nat tot_add_threads, tot_tq_len, non_end_add_threads;

  /* packet statistics */
  nat tot_packets, tot_packet_size, tot_thunks,
      res_packet_size, res_thunks,
      rec_packets, rec_packet_size, rec_thunks,
      rec_res_packet_size, rec_res_thunks;
  /* time spent packing stuff */
  double time_pack, time_unpack;

  /* thread stats */
  nat tot_threads_created;

  /* spark stats */
  //nat pruned_sparks, withered_sparks;
  nat tot_sparks_created, tot_sparks_ignored, tot_sparks_marked,
      res_sparks_created, res_sparks_ignored, res_sparks_marked; // , sparks_created_on_PE[MAX_PROC];
  double time_sparks;

  /* scheduling stats */
  nat tot_yields, tot_stackover, tot_heapover;

  /* message statistics */
  nat tot_fish_mess, tot_fetch_mess, tot_resume_mess, tot_schedule_mess;
  nat rec_fish_mess, rec_fetch_mess, rec_resume_mess, rec_schedule_mess;
  nat rec_ack_mess , max_packed_buffer;
#if defined(DIST)
  nat tot_reval_mess;
  nat rec_reval_mess;
#endif

  /* blocking queue statistics
  rtsTime tot_bq_processing_time;
  nat tot_bq_len, tot_bq_len_local, tot_awbq, tot_FMBQs;
  */

  /* specialised info on arrays (for GPH/Maple mainly) */
  nat tot_arrs, tot_arr_size;
} GlobalParStats;

extern GlobalParStats globalParStats;

void  globalParStat_exit(void);

// from Parallel.c
StgClosure *followFwdInfoPtr(StgInfoTable *info);

// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
// VERY OLD STUFF; sort out and nuke

#if defined(GRAN) || defined(PAR)

#if defined(GRAN)

/* Statistics info */
extern nat tot_packets, tot_packet_size, tot_cuts, tot_thunks;

/* Pack.c */
rtsPackBuffer *PackNearbyGraph(StgClosure* closure, StgTSO* tso, 
			       nat *packBufferSize, GlobalTaskId dest); 
rtsPackBuffer *PackOneNode(StgClosure* closure, StgTSO* tso, 
			   nat *packBufferSize);
rtsPackBuffer *PackTSO(StgTSO *tso, nat *packBufferSize);
rtsPackBuffer *PackStkO(StgPtr stko, nat *packBufferSize);
void           PackFetchMe(StgClosure *closure);

/* Unpack.c */
StgClosure*    UnpackGraph(rtsPackBuffer* buffer);
void           InitPendingGABuffer(nat size); 

/* RBH.c */
StgClosure    *convertToRBH(StgClosure *closure);
void           convertFromRBH(StgClosure *closure);

/* HLComms.c */
rtsFetchReturnCode blockFetch(StgTSO* tso, PEs proc, StgClosure* bh);
void               blockThread(StgTSO *tso);

#endif
/* Pack.c */
rtsBool        InitPackBuffer(void);
rtsPackBuffer *PackNearbyGraph(StgClosure* closure, StgTSO* tso, 
			       nat *packBufferSize, GlobalTaskId dest); 

/* Unpack.c */
void           CommonUp(StgClosure *src, StgClosure *dst);
StgClosure    *UnpackGraph(rtsPackBuffer *buffer, globalAddr **gamap, 
			   nat *nGAs);

/* RBH.c */
StgClosure    *convertToRBH(StgClosure *closure);
void           convertToFetchMe(StgRBH *rbh, globalAddr *ga);

/* HLComms.c */
void           blockFetch(StgBlockedFetch *bf, StgClosure *bh);
void           blockThread(StgTSO *tso);

/* Global.c */
void           GALAdeprecate(globalAddr *ga);

/* HLComms.c */
nat            pending_fetches_len(void);

/* ParInit.c */
void 	       initParallelSystem(void);
void 	       shutdownParallelSystem(StgInt n);
void 	       synchroniseSystem(void);
void 	       par_exit(I_);

#endif

/* this routine should be moved to a more general module; currently in Pack.c 
StgInfoTable* get_closure_info(StgClosure* node, 
			       nat *size, nat *ptrs, nat *nonptrs, nat *vhs, 
			       char *info_hdr_ty);
*/
void doGlobalGC(void); 

//@node GC routines, Debugging routines, Spark handling routines
//@subsection GC routines

#if defined(PAR)
/* HLComms.c */
void      freeRemoteGA(int pe, globalAddr *ga);
void      sendFreeMessages(void);
void      markPendingFetches(rtsBool major_gc);

/* Global.c */
void      markInPtrs(rtsBool full);
void      markOutPtrs(rtsBool full);
void      RebuildGAtables(rtsBool full);
void      RebuildLAGAtable(void);
#endif

//@node Debugging routines, Generating .gr profiles, GC routines
//@subsection Debugging routines

#if defined(PAR)
void      printGA (globalAddr *ga);
void      printGALA (GALA *gala);
void      printLAGAtable(void);

rtsBool   isOnLiveIndTable(globalAddr *ga);
rtsBool   isOnRemoteGATable(globalAddr *ga);
void      checkFreeGALAList(void);
void      checkFreeIndirectionsList(void);
#endif

//@node Generating .gr profiles, Index, Debugging routines
//@subsection Generating .gr profiles

#define STATS_FILENAME_MAXLEN	128

/* Where to write the log file */
//@cindex gr_file
//@cindex gr_filename
extern FILE *gr_file;
extern char gr_filename[STATS_FILENAME_MAXLEN];

//@cindex init_gr_stats
//@cindex init_gr_simulation
//@cindex end_gr_simulation
void 	  	init_gr_stats (void);
void 	  	init_gr_simulation(int rts_argc, char *rts_argv[], 
 	 			   int prog_argc, char *prog_argv[]);
void 	  	end_gr_simulation(void);

/* TODO: move fcts in here (as static inline)
StgInfoTable*   get_closure_info(StgClosure* node, nat *size, nat *ptrs, nat *nonptrs, nat *vhs, char *info_hdr_ty);
rtsBool         IS_BLACK_HOLE(StgClosure* node);
StgClosure     *IS_INDIRECTION(StgClosure* node)          ;
StgClosure     *UNWIND_IND (StgClosure *closure);
*/

#endif /* defined(PAR) || defined(GRAN) */

//@node Common macros, Index, Generating .gr profiles
//@subsection Common macros

#define LOOKS_LIKE_PTR(r)    \
        (LOOKS_LIKE_STATIC_CLOSURE(r) ||  \
         ((HEAP_ALLOCED(r) && Bdescr((P_)r)->free != (void *)-1)))

/* see Sanity.c for this kind of test; doing this in these basic fcts
   is paranoid (nuke it after debugging!)
*/

/* pathetic version of the check whether p can be a closure */
#define LOOKS_LIKE_COOL_CLOSURE(p)  1

//LOOKS_LIKE_GHC_INFO(get_itbl(p))

    /* Is it a static closure (i.e. in the data segment)? */ \
    /*
#define LOOKS_LIKE_COOL_CLOSURE(p)  \
    ((LOOKS_LIKE_STATIC(p)) ?                                   \
	closure_STATIC(p)                               \
      : !closure_STATIC(p) && LOOKS_LIKE_PTR(p))
    */

#endif /* PARALLEL_RTS_H */

//@node Index,  , Index
//@subsection Index

//@index
//* IS_BLACK_HOLE::  @cindex\s-+IS_BLACK_HOLE
//* IS_INDIRECTION::  @cindex\s-+IS_INDIRECTION
//* end_gr_simulation::  @cindex\s-+end_gr_simulation
//* get_closure_info::  @cindex\s-+get_closure_info
//* gr_file::  @cindex\s-+gr_file
//* gr_filename::  @cindex\s-+gr_filename
//* init_gr_simulation::  @cindex\s-+init_gr_simulation
//* unwindInd::  @cindex\s-+unwindInd
//@end index
