/* -----------------------------------------------------------------------------
 *
 * (c) The GHC Team, 2009
 *
 * Macros for profiling operations in STG code
 *
 * Do not #include this file directly: #include "Rts.h" instead.
 *
 * To understand the structure of the RTS headers, see the wiki:
 *   http://hackage.haskell.org/trac/ghc/wiki/Commentary/SourceTree/Includes
 *
 * ---------------------------------------------------------------------------*/

#ifndef RTS_PROF_CCS_H
#define RTS_PROF_CCS_H

// Returns non-zero if the RTS is a profiling version
int rts_isProfiled(void);

/* -----------------------------------------------------------------------------
 * Data Structures 
 * ---------------------------------------------------------------------------*/  
/*
 * Note [struct alignment]
 * NB. be careful to avoid unwanted padding between fields, by
 * putting the 8-byte fields on an 8-byte boundary.  Padding can
 * vary between C compilers, and we don't take into account any
 * possible padding when generating CCS and CC decls in the code
 * generator (compiler/codeGen/CgProf.hs).
 */

typedef struct CostCentre_ {
    StgInt ccID;              // Unique Id, allocated by the RTS

    char * label;
    char * module;
    char * srcloc;

    // used for accumulating costs at the end of the run...
    StgWord64 mem_alloc;      // align 8 (Note [struct alignment])
    StgWord   time_ticks;

    StgInt is_caf;            // non-zero for a CAF cost centre

    struct CostCentre_ *link;
} CostCentre;

typedef struct CostCentreStack_ {
    StgInt ccsID;               // unique ID, allocated by the RTS

    CostCentre *cc;             // Cost centre at the top of the stack

    struct CostCentreStack_ *prevStack;   // parent
    struct IndexTable_      *indexTable;  // children
    struct CostCentreStack_ *root;        // root of stack
    StgWord    depth;           // number of items in the stack

    StgWord64  scc_count;       // Count of times this CCS is entered
                                // align 8 (Note [struct alignment])

    StgWord    selected;        // is this CCS shown in the heap
                                // profile? (zero if excluded via -hc
                                // -hm etc.)

    StgWord    time_ticks;      // number of time ticks accumulated by
                                // this CCS

    StgWord64  mem_alloc;       // mem allocated by this CCS
                                // align 8 (Note [struct alignment])

    StgWord64  inherited_alloc; // sum of mem_alloc over all children
                                // (calculated at the end)
                                // align 8 (Note [struct alignment])

    StgWord    inherited_ticks; // sum of time_ticks over all children
                                // (calculated at the end)
} CostCentreStack;


/* -----------------------------------------------------------------------------
 * The rest is PROFILING only...
 * ---------------------------------------------------------------------------*/

#if defined(PROFILING)
  
/* -----------------------------------------------------------------------------
 * Constants
 * ---------------------------------------------------------------------------*/

#define EMPTY_STACK NULL
#define EMPTY_TABLE NULL

/* Constants used to set is_caf flag on CostCentres */
#define CC_IS_CAF      'c'            /* 'c'  => *is* a CAF cc           */
#define CC_NOT_CAF     0

/* -----------------------------------------------------------------------------
 * Data Structures
 * ---------------------------------------------------------------------------*/

// IndexTable is the list of children of a CCS. (Alternatively it is a
// cache of the results of pushing onto a CCS, so that the second and
// subsequent times we push a certain CC on a CCS we get the same
// result).

typedef struct IndexTable_ {
    CostCentre *cc;
    CostCentreStack *ccs;
    struct IndexTable_ *next;
    unsigned int back_edge;
} IndexTable;

     
/* -----------------------------------------------------------------------------
   Pre-defined cost centres and cost centre stacks
   -------------------------------------------------------------------------- */

#if IN_STG_CODE

extern StgWord CC_MAIN[];	
extern StgWord CCS_MAIN[];      // Top CCS

extern StgWord CC_SYSTEM[];	
extern StgWord CCS_SYSTEM[];    // RTS costs

extern StgWord CC_GC[];
extern StgWord CCS_GC[];         // Garbage collector costs

extern StgWord CC_OVERHEAD[];
extern StgWord CCS_OVERHEAD[];   // Profiling overhead

extern StgWord CC_DONT_CARE[];
extern StgWord CCS_DONT_CARE[];  // CCS attached to static constructors

#else

extern CostCentre      CC_MAIN[];	
extern CostCentreStack CCS_MAIN[];      // Top CCS

extern CostCentre      CC_SYSTEM[];	
extern CostCentreStack CCS_SYSTEM[];    // RTS costs

extern CostCentre      CC_GC[];
extern CostCentreStack CCS_GC[];         // Garbage collector costs

extern CostCentre      CC_OVERHEAD[];
extern CostCentreStack CCS_OVERHEAD[];   // Profiling overhead

extern CostCentre      CC_DONT_CARE[];
extern CostCentreStack CCS_DONT_CARE[];  // shouldn't ever get set

extern CostCentre      CC_PINNED[];
extern CostCentreStack CCS_PINNED[];     // pinned memory

extern CostCentre      CC_IDLE[];
extern CostCentreStack CCS_IDLE[];       // capability is idle

#endif /* IN_STG_CODE */

extern unsigned int RTS_VAR(CC_ID);     // global ids
extern unsigned int RTS_VAR(CCS_ID);

extern unsigned int RTS_VAR(era);

/* -----------------------------------------------------------------------------
 * Functions 
 * ---------------------------------------------------------------------------*/

CostCentreStack * pushCostCentre (CostCentreStack *, CostCentre *);
void              enterFunCCS    (StgRegTable *reg, CostCentreStack *);

/* -----------------------------------------------------------------------------
   Registering CCs and CCSs
 
   Registering a CC or CCS consists of
     - assigning it a unique ID
     - linking it onto the list of registered CCs/CCSs

   Cost centres are registered at startup by a C constructor function
   generated by the compiler in the _stub.c file for each module.  The
   macros below are invoked by that C code to register CCs and CCSs.
 -------------------------------------------------------------------------- */

extern CostCentre * RTS_VAR(CC_LIST);               // registered CC list
extern CostCentreStack * RTS_VAR(CCS_LIST);         // registered CCS list

#define REGISTER_CC(cc)					\
	do {						\
	if ((cc)->link == (CostCentre *)0) {		\
	    (cc)->link = CC_LIST;			\
	    CC_LIST = (cc);				\
	    (cc)->ccID = CC_ID++; 			\
	}} while(0)

#define REGISTER_CCS(ccs)				\
	do {						\
        if ((ccs)->prevStack == (CostCentreStack *)0) {	\
	  (ccs)->prevStack = CCS_LIST;			\
	  CCS_LIST = (ccs);				\
	  (ccs)->ccsID = CCS_ID++;			\
	}} while(0)

/* -----------------------------------------------------------------------------
 * Declaring Cost Centres & Cost Centre Stacks.
 * -------------------------------------------------------------------------- */

# define CC_DECLARE(cc_ident,name,mod,loc,caf,is_local) \
     is_local CostCentre cc_ident[1]                    \
       = {{ ccID       : 0,                             \
            label      : name,                          \
            module     : mod,                           \
            srcloc     : loc,                           \
            time_ticks : 0,                             \
            mem_alloc  : 0,                             \
            link       : 0,                             \
            is_caf     : caf                            \
         }};

# define CCS_DECLARE(ccs_ident,cc_ident,is_local)       \
     is_local CostCentreStack ccs_ident[1]              \
       = {{ ccsID 		: 0,                    \
	    cc 			: cc_ident,             \
	    prevStack 		: NULL,                 \
	    indexTable 		: NULL,                 \
            root                : NULL,                 \
            depth               : 0,                    \
            selected            : 0,                    \
	    scc_count 		: 0,                    \
	    time_ticks 		: 0,                    \
	    mem_alloc 		: 0,                    \
	    inherited_ticks 	: 0,                    \
            inherited_alloc     : 0                     \
       }};

/* -----------------------------------------------------------------------------
 * Time / Allocation Macros
 * ---------------------------------------------------------------------------*/

/* eliminate profiling overhead from allocation costs */
#define CCS_ALLOC(ccs, size) (ccs)->mem_alloc += ((size)-sizeofW(StgProfHeader))

#else /* !PROFILING */

#define CCS_ALLOC(ccs, amount) doNothing()
 
#endif /* PROFILING */

#endif /* RTS_PROF_CCS_H */

