[project @ 2004-08-13 13:04:50 by simonmar]
[ghc-hetmet.git] / ghc / includes / StgProf.h
1 /* -----------------------------------------------------------------------------
2  * $Id: StgProf.h,v 1.18 2004/08/13 13:09:37 simonmar Exp $
3  *
4  * (c) The GHC Team, 1998
5  *
6  * Macros for profiling operations in STG code
7  * ---------------------------------------------------------------------------*/
8
9 #ifndef STGPROF_H
10 #define STGPROF_H
11
12 /* -----------------------------------------------------------------------------
13  * Data Structures 
14  * ---------------------------------------------------------------------------*/  
15 typedef struct _CostCentre {
16   StgInt ccID;
17
18   char * label;
19   char * module;
20  
21   /* used for accumulating costs at the end of the run... */
22   StgWord   time_ticks;
23   StgWord64 mem_alloc;
24
25   StgInt    is_caf;
26
27   struct _CostCentre *link;
28 } CostCentre;
29
30
31 typedef struct _CostCentreStack {
32   StgInt ccsID;
33
34   CostCentre *cc;
35   struct _CostCentreStack *prevStack;
36   struct _IndexTable *indexTable;
37
38   StgWord    selected;
39   StgWord64  scc_count;
40   StgWord    time_ticks;
41   StgWord64  mem_alloc;
42   StgWord    inherited_ticks;
43   StgWord64  inherited_alloc;
44
45   CostCentre *root;
46 } CostCentreStack;
47
48
49 /* -----------------------------------------------------------------------------
50  * The rest is PROFILING only...
51  * ---------------------------------------------------------------------------*/
52
53 #if defined(PROFILING)
54   
55 /* -----------------------------------------------------------------------------
56  * Constants
57  * ---------------------------------------------------------------------------*/
58
59 #define EMPTY_STACK NULL
60 #define EMPTY_TABLE NULL
61
62 /* Constants used to set sumbsumed flag on CostCentres */
63
64 #define CC_IS_CAF      'c'            /* 'c'  => *is* a CAF cc           */
65 #define CC_IS_BORING   'B'            /* 'B'  => *not* a CAF/sub cc      */
66
67
68 /* -----------------------------------------------------------------------------
69  * Data Structures
70  * ---------------------------------------------------------------------------*/
71
72 typedef struct _IndexTable {
73   CostCentre *cc;
74   CostCentreStack *ccs;
75   struct _IndexTable *next;
76   unsigned int back_edge;
77 } IndexTable;
78
79      
80 /* -----------------------------------------------------------------------------
81    Pre-defined cost centres and cost centre stacks
82    -------------------------------------------------------------------------- */
83
84 extern CostCentreStack * RTS_VAR(CCCS);         /* current CCS */
85  
86 #if IN_STG_CODE
87
88 extern StgWord CC_MAIN[];       
89 extern StgWord CCS_MAIN[];      /* Top CCS */
90
91 extern StgWord CC_SYSTEM[];     
92 extern StgWord CCS_SYSTEM[];    /* RTS costs */
93
94 extern StgWord CC_GC[];
95 extern StgWord CCS_GC[];         /* Garbage collector costs */
96
97 extern StgWord CC_SUBSUMED[];   
98 extern StgWord CCS_SUBSUMED[];   /* Costs are subsumed by caller */
99
100 extern StgWord CC_OVERHEAD[];
101 extern StgWord CCS_OVERHEAD[];   /* Profiling overhead */
102
103 extern StgWord CC_DONT_CARE[];
104 extern StgWord CCS_DONT_CARE[];  /* shouldn't ever get set */
105
106 #else
107
108 extern CostCentre      CC_MAIN[];       
109 extern CostCentreStack CCS_MAIN[];      /* Top CCS */
110
111 extern CostCentre      CC_SYSTEM[];     
112 extern CostCentreStack CCS_SYSTEM[];    /* RTS costs */
113
114 extern CostCentre      CC_GC[];
115 extern CostCentreStack CCS_GC[];         /* Garbage collector costs */
116
117 extern CostCentre      CC_SUBSUMED[];   
118 extern CostCentreStack CCS_SUBSUMED[];   /* Costs are subsumed by caller */
119
120 extern CostCentre      CC_OVERHEAD[];
121 extern CostCentreStack CCS_OVERHEAD[];   /* Profiling overhead */
122
123 extern CostCentre      CC_DONT_CARE[];
124 extern CostCentreStack CCS_DONT_CARE[];  /* shouldn't ever get set */
125
126 #endif // IN_STG_CODE
127
128 extern unsigned int RTS_VAR(CC_ID);     /* global ids */
129 extern unsigned int RTS_VAR(CCS_ID);
130 extern unsigned int RTS_VAR(HP_ID);
131
132 extern unsigned int RTS_VAR(era);
133
134 /* -----------------------------------------------------------------------------
135  * Functions 
136  * ---------------------------------------------------------------------------*/
137
138 void EnterFunCCS ( CostCentreStack *ccsfn );
139 CostCentreStack *PushCostCentre ( CostCentreStack *, CostCentre * );
140 CostCentreStack *AppendCCS ( CostCentreStack *ccs1, CostCentreStack *ccs2 );
141
142 extern unsigned int RTS_VAR(entering_PAP);
143
144 /* -----------------------------------------------------------------------------
145  * Registering CCs
146  
147  Cost centres are registered at startup by calling a registering
148  routine in each module. Each module registers its cost centres and
149  calls the registering routine for all imported modules. The RTS calls
150  the registering routine for the module Main. This registering must be
151  done before initialisation since the evaluation required for
152  initialisation may use the cost centres.
153  
154  As the code for each module uses tail calls we use an auxiliary stack
155  (in the heap) to record imported modules still to be registered. At
156  the bottom of the stack is NULL which indicates that
157  @miniInterpretEnd@ should be resumed.
158  
159  @START_REGISTER@ and @END_REGISTER@ are special macros used to
160  delimit the function. @END_REGISTER@ pops the next registering
161  routine off the stack and jumps to it. @REGISTER_CC@ registers a cost
162  centre. @REGISTER_IMPORT@ pushes a modules registering routine onto
163  the register stack.
164
165  -------------------------------------------------------------------------- */
166
167 extern CostCentre * RTS_VAR(CC_LIST);               /* registered CC list */
168 extern CostCentreStack * RTS_VAR(CCS_LIST);         /* registered CCS list */
169
170 #define REGISTER_CC(cc)                                 \
171         do {                                            \
172         extern CostCentre cc[];                         \
173         if ((cc)->link == (CostCentre *)0) {            \
174             (cc)->link = CC_LIST;                       \
175             CC_LIST = (cc);                             \
176             (cc)->ccID = CC_ID++;                       \
177         }} while(0)
178
179 #define REGISTER_CCS(ccs)                               \
180         do {                                            \
181         extern CostCentreStack ccs[];                   \
182         if ((ccs)->prevStack == (CostCentreStack *)0) { \
183           (ccs)->prevStack = CCS_LIST;                  \
184           CCS_LIST = (ccs);                             \
185           (ccs)->ccsID = CCS_ID++;                      \
186         }} while(0)
187
188 /* -----------------------------------------------------------------------------
189  * Declaring Cost Centres & Cost Centre Stacks.
190  * -------------------------------------------------------------------------- */
191
192 # define CC_DECLARE(cc_ident,name,module,caf,is_local)          \
193      is_local CostCentre cc_ident[1]                            \
194         = {{ 0,                                                 \
195              name,                                              \
196              module,                                            \
197              0,                                                 \
198              0,                                                 \
199              caf,                                               \
200              0 }};
201
202 # define CCS_DECLARE(ccs_ident,cc_ident,is_local)               \
203      is_local CostCentreStack ccs_ident[1]                      \
204        = {{ ccsID               : 0,                            \
205             cc                  : cc_ident,                     \
206             prevStack           : NULL,                         \
207             indexTable          : NULL,                         \
208             selected            : 0,                            \
209             scc_count           : 0,                            \
210             time_ticks          : 0,                            \
211             mem_alloc           : 0,                            \
212             inherited_ticks     : 0,                            \
213             inherited_alloc     : 0,                            \
214             root                : 0,                            \
215        }};
216
217 # define CC_EXTERN(cc_ident) \
218     extern CostCentre cc_ident[];
219
220 /* -----------------------------------------------------------------------------
221  * Time / Allocation Macros
222  * ---------------------------------------------------------------------------*/
223
224 /* eliminate profiling overhead from allocation costs */
225 #define CCS_ALLOC(ccs, size) (ccs)->mem_alloc += ((size)-sizeofW(StgProfHeader))
226
227 /* For grabbing the cost centre from a closure */
228 #define CCS_HDR(closure)   ((StgClosure *)(closure))->header.prof.ccs
229
230 /* Restore the CCCS from a stack frame.
231  * (addr should always be Sp->header.prof.ccs) 
232  */
233 #define RESTORE_CCCS(addr)   (*CCCS = (CostCentreStack *)(addr))
234
235 /* -----------------------------------------------------------------------------
236  * Pushing a new cost centre (i.e. for scc annotations)
237  * -------------------------------------------------------------------------- */
238
239 # define SET_CCC_X(cc,do_subcc_count,do_scc_count)              \
240         do {                                                    \
241         CCCS = PushCostCentre(CCCS,cc);                         \
242         if (do_scc_count)     { CCCS->scc_count++; }            \
243         } while(0)
244
245 /* We sometimes don't increment the scc_count field, for example when
246  * this scc has been placed by the compiler on an expression it
247  * floated outside the main scc annotation.
248  */
249
250 # define SET_CCC(cc_ident,do_scc_count) \
251          SET_CCC_X(cc_ident,do_scc_count,do_scc_count)
252
253 # define SET_CCS_TOP(cc_ident) \
254          SET_CCC_X(cc_ident,0,1)
255
256 /* -----------------------------------------------------------------------------
257  * Allocating new cost centres / cost centre stacks.
258  * -------------------------------------------------------------------------- */
259
260 #define ASSIGN_CC_ID(ccID)                \
261         do {                              \
262         ccID = CC_ID;                     \
263         CC_ID++;                          \
264         } while(0)
265
266 #define ASSIGN_CCS_ID(ccsID)              \
267         do {                              \
268         ccsID = CCS_ID;                   \
269         CCS_ID++;                         \
270         } while(0)
271
272 #define ASSIGN_HP_ID(hpID)                \
273         do {                              \
274         hpID = HP_ID;                     \
275         HP_ID++;                          \
276         } while(0)
277
278 #define SET_STATS_TO_ZERO(stack)          \
279         do {                              \
280         (stack)->scc_count = 0;           \
281         (stack)->time_ticks = 0;          \
282         (stack)->mem_alloc = 0;           \
283         } while(0)
284
285 /* -----------------------------------------------------------------------------
286  * Setting the cost centre when we enter a closure
287  * -------------------------------------------------------------------------- */
288
289 #if defined(PROFILING_DETAIL_COUNTS)
290 #define CCCS_DETAIL_COUNT(inc_this) ((inc_this)++)
291 #else
292 #define CCCS_DETAIL_COUNT(inc_this) /*nothing*/
293 #endif
294
295 /* On entry to top level CAFs we count the scc ...*/
296
297 #define ENTER_CCS_CAF_X(ccs)                                \
298         do {                                                \
299         /* set CCCS to ident ccs */                         \
300         CCCS = (CostCentreStack *)(ccs);                    \
301         /* inc scc count of CAF ccs */                      \
302         CCCS->scc_count++;                                  \
303         } while(0)
304  
305 #define ENTER_CCS_CAF(ccs_ident)   ENTER_CCS_CAF_X(ccs_ident)
306 #define ENTER_CCS_CAF_CL(closure)  ENTER_CCS_CAF_X(CCS_HDR(closure))
307
308 /* ----------------------------------------------------------------------------
309  * Entering a Thunk
310  *
311  * On entering a closure we only count the enter to thunks ...
312  * ------------------------------------------------------------------------- */
313
314 #define ENTER_CCS_T(ccs)                                \
315         do {                                            \
316         *CCCS = (CostCentreStack *)(ccs);               \
317         CCCS_DETAIL_COUNT(CCCS->thunk_count);           \
318         } while(0)      
319  
320 #define ENTER_CCS_TCL(closure)  ENTER_CCS_T(CCS_HDR(closure))
321  
322 /* -----------------------------------------------------------------------------
323  * Entering a function
324  *
325  * Here is our special "hybrid" case when we do *not* set the CCCS.
326  *  (a) The closure is a function, not a thunk;
327  *  (b) The CCS is CAF-ish.
328  * -------------------------------------------------------------------------- */
329
330 #define ENTER_CCS_F(stack) EnterFunCCS(stack)
331  
332 #define ENTER_CCS_FCL(closure)  ENTER_CCS_F(CCS_HDR(closure))
333
334 /* Entering a top-level function: costs are subsumed by the caller 
335  */
336 #define ENTER_CCS_FSUB()                                \
337         do {                                            \
338         CCCS_DETAIL_COUNT(CCCS->subsumed_fun_count);    \
339         CCCS_DETAIL_COUNT(CCCS->function_count);        \
340         entering_PAP = 0;                               \
341         } while(0)
342  
343 #define ENTER_CCS_FCAF(stack)                                   \
344         do {                                                    \
345         CostCentreStack *ccs = (CostCentreStack *) (stack);     \
346         CCCS_DETAIL_COUNT(ccs->caffun_subsumed);                \
347         CCCS_DETAIL_COUNT(CCCS->subsumed_caf_count);            \
348         CCCS_DETAIL_COUNT(CCCS->function_count);                \
349         entering_PAP = 0;                                       \
350         } while(0)
351  
352 #define ENTER_CCS_FLOAD(ccs)                                \
353         do {                                                \
354         CCCS = (CostCentreStack *)(ccs);                    \
355         CCCS_DETAIL_COUNT(CCCS->function_count);            \
356         } while(0)
357  
358 /* These ENTER_CC_PAP things are only used in the RTS */
359  
360 #define ENTER_CCS_PAP(stack)                    \
361         do {                                    \
362         ENTER_CCS_F(stack);                     \
363         *entering_PAP = rtsTrue;                \
364         } while(0)
365
366 #define ENTER_CCS_PAP_CL(closure)  \
367         ENTER_CCS_PAP((closure)->header.prof.ccs)
368
369 /* -----------------------------------------------------------------------------
370    When not profiling, these macros do nothing...
371    -------------------------------------------------------------------------- */
372 #else /* !PROFILING */
373
374 #define CCS_ALLOC(ccs, amount) doNothing()
375 #define ENTER_CC_PAP_CL(r)     doNothing()
376 #define ENTER_CCS_PAP_CL(r)    doNothing()
377  
378 #endif /* PROFILING */
379
380 #endif /* STGPROF_H */