[project @ 1996-07-19 18:36:04 by partain]
[ghc-hetmet.git] / ghc / includes / CostCentre.lh
1 %************************************************************************
2 %*                                                                      *
3 \section[CostCentre.lh]{Definitions for Cost Centre Profiling}
4 %*                                                                      *
5 %************************************************************************
6
7 Multi-slurp protection:
8 \begin{code}
9 #ifndef CostCentre_H
10 #define CostCentre_H
11 \end{code}
12
13 For threaded activity profiling, we need a few bits of the CostCentre
14 environment to be defined, despite the fact that we don't have CostCentre
15 fields in closures.
16
17 \begin{code}
18 #if defined(PROFILING) || defined(CONCURRENT)
19
20 # define CC_EXTERN(cc_ident)                                    \
21      extern struct cc CAT2(cc_ident,_struct);                   \
22      extern CostCentre cc_ident
23
24 extern CostCentre CCC;          /* the current cost centre */
25
26 extern CostCentre Registered_CC;/* registered cost centre list */
27
28 CC_EXTERN(CC_MAIN);             /* initial MAIN cost centre */
29 CC_EXTERN(CC_GC);               /* Garbage Collection cost center */
30
31 # ifdef PAR
32 CC_EXTERN(CC_MSG);              /* Communications cost center */
33 CC_EXTERN(CC_IDLE);             /* Idle-time cost centre */
34 # endif
35
36 # define REGISTERED_END (CostCentre)4   /* end of list */
37                                         /* That 4 look likes a HACK, Patrick.
38                                            (WDP 94/06) */
39 # define NOT_REGISTERED (CostCentre)0   /* not yet registered */
40
41 \end{code}
42
43 The compiler declares a static block for each @_scc_@ annotation in the
44 source using the @CC_DECLARE@ macro where @label@, @module@ and
45 @group@ are strings and @ident@ the cost centre identifier.
46
47 \begin{code} 
48 # define CC_IS_CAF      'c'
49 # define CC_IS_DICT     'd'
50 # define CC_IS_SUBSUMED 'S'
51 # define CC_IS_BORING   'B'
52
53 # define STATIC_CC_REF(cc_ident) &CAT2(cc_ident,_struct)
54 # define DYN_CC_REF(cc_ident)    cc_ident /* unused */
55
56 # define CC_DECLARE(cc_ident,name,module,group,subsumed,is_local)       \
57      is_local struct cc CAT2(cc_ident,_struct)                          \
58         = {NOT_REGISTERED, UNHASHED, name, module, group,               \
59            subsumed, INIT_CC_STATS};                                    \
60      is_local CostCentre cc_ident = STATIC_CC_REF(cc_ident)
61
62 #endif /* defined(PROFILING) || defined(CONCURRENT) */
63 \end{code}
64
65 Definitions relating to the profiling field as a whole.
66
67 \begin{code}
68 #define PROF_FIXED_HDR                  (CC_HDR_SIZE)   
69 #define PROF_HDR_POSN                   AFTER_PAR_HDR
70 #define AFTER_PROF_HDR                  (PROF_FIXED_HDR+PROF_HDR_POSN)
71 #define SET_PROF_HDR(closure,cc)        SET_CC_HDR(closure,cc)
72 #define SET_STATIC_PROF_HDR(ident)      SET_STATIC_CC_HDR(ident)
73 \end{code}
74
75 %************************************************************************
76 %*                                                                      *
77 \subsection[no-cost-centres]{Dummy definitions if no cost centres}
78 %*                                                                      *
79 %************************************************************************
80
81 The cost-centre profiling is only on if the driver turns on
82 @PROFILING@.
83
84 These are the {\em dummy} definitions in force if we do {\em NOT}
85 turn on @PROFILING@.  Get them out of the way....
86
87 \begin{code}
88 #if !defined(PROFILING)
89
90 /*** Declaration Definitions ***/
91
92 # define CAT_DECLARE(base_name, kind, descr, type)
93
94 # define CC_HDR_SIZE 0                  /* No CC in fixed header */
95
96 # define SET_CC_HDR(closure, cc)        /* Dont set CC header */
97 # define SET_STATIC_CC_HDR(cc)          /* No static CC header */
98
99 # define SET_CCC(cc_ident,do_scc_count)
100 # define SET_DICT_CCC(cc_ident,do_scc_count)
101 # define SET_CCC_RTS(cc_ident,do_sub_count,do_count)
102
103 # define RESTORE_CCC(cc)
104
105 # define ENTER_CC_T(cc)
106 # define ENTER_CC_TCL(closure)
107 # define ENTER_CC_F(cc)
108 # define ENTER_CC_FCL(closure)
109 # define ENTER_CC_FSUB()
110 # define ENTER_CC_FCAF(cc)
111 # define ENTER_CC_FLOAD(cc)
112 # define ENTER_CC_PAP(cc)
113 # define ENTER_CC_PAP_CL(closure)
114
115 /*** Timer and Heap Definitions ***/
116
117 # define OR_INTERVAL_EXPIRED    /* No || as it is false */
118
119 # define CC_ALLOC(cc, size, kind)
120 # define HEAP_PROFILE_CLOSURE(closure,size)
121
122 # ifndef PAR
123 #  define START_TIME_PROFILER
124 #  define RESTART_TIME_PROFILER
125 #  define STOP_TIME_PROFILER
126 # endif
127
128 #endif /* !defined(PROFILING) */
129 \end{code}
130
131 %************************************************************************
132 %*                                                                      *
133 \subsection[declaring-cost-centres]{Declaring Cost Centres}
134 %*                                                                      *
135 %************************************************************************
136
137 Now for the cost-centre profiling stuff.
138
139 %************************************************************************
140 %*                                                                      *
141 \subsection[cost-centres]{Location of Cost Centres}
142 %*                                                                      *
143 %************************************************************************
144
145 We have a current cost centre, a list of registered cost centres, and
146 an additional cost centre field within the fixed header of all
147 closures. This is adjacent to the info pointer.
148
149 \begin{code}
150 #if defined(PROFILING)
151
152 CC_EXTERN(CC_SUBSUMED);         /* top level fns SUBSUMED cost centre */
153 CC_EXTERN(CC_OVERHEAD);         /* costs due only to profiling machinery */
154 CC_EXTERN(CC_DONTZuCARE);       /* placeholder only */
155
156 CC_EXTERN(CC_CAFs);             /* prelude cost centre (CAFs  only) */
157 CC_EXTERN(CC_DICTs);            /* prelude cost centre (DICTs only) */
158
159 # define IS_CAF_OR_DICT_CC(cc) \
160     ((cc)->is_subsumed & ' ')   /* tests for lower case character */
161
162 # define IS_SUBSUMED_CC(cc) ((cc)->is_subsumed == CC_IS_SUBSUMED)
163
164 \end{code}
165
166 Definitions referring to the Cost Centre sub-field of the fixed header.
167 \begin{code}
168
169 # define CC_HDR_SIZE            1       /* words of header */
170                                         /*R SMinterface.lh */
171
172 # define CC_HDR_POSN            PROF_HDR_POSN   /* position in header */
173
174 # define CC_HDR(closure)        (((P_)(closure))[CC_HDR_POSN])
175
176 # define SET_CC_HDR(closure, cc) \
177         CC_HDR(closure) = (W_)(cc)      /* Set closures cost centre */
178                                         /*R SMinterface.lh (CCC) */
179 \end{code}
180
181 For static closures ...
182 \begin{code}
183 # define SET_STATIC_CC_HDR(cc_ident) \
184         ,  (W_) STATIC_CC_REF(cc_ident)         /* static initialisation */
185                                                 /*R SMinterface.lh */
186 \end{code}
187
188 The @/*R @{\em file}@ */@ comments indicate that the macro is used
189 regardless in {\em file} so we need a null definition if cost centres
190 are not being used.
191
192 %************************************************************************
193 %*                                                                      *
194 \subsection{Setting the Current Cost Centre}
195 %*                                                                      *
196 %************************************************************************
197
198 On execution of an @_scc_@ expression a new cost centre is set.
199
200 If the new cost centre is different from the CCC we set the CCC and
201 count the entry.
202
203 If the cost centre is the same as the CCC no action is required. We do
204 not count the entry to avoid large counts arising from simple
205 recursion.  (Huh?  WDP 94/07)
206
207 \begin{code}
208 # define SET_CCC_X(cc,do_subcc_count,do_subdict_count,do_scc_count)                             \
209         do {                                                                                    \
210         if ((do_subcc_count)) { CCC->sub_scc_count++; }       /* inc subcc count of CCC */      \
211         if ((do_subdict_count)) { CCC->sub_dictcc_count++; }  /* inc sub dict count of CCC */   \
212         CCC = (CostCentre)(cc);                               /* set CCC to ident cc */         \
213         ASSERT_IS_REGISTERED(CCC,1);                                                            \
214         if ((do_scc_count)) { CCC->scc_count++; }             /* inc scc count of new CCC*/     \
215         } while(0)
216
217 # define SET_CCC(cc_ident,do_scc_count) \
218          SET_CCC_X(STATIC_CC_REF(cc_ident),do_scc_count,0,do_scc_count)
219
220 # define SET_DICT_CCC(cc_ident,do_scc_count) \
221          SET_CCC_X(STATIC_CC_REF(cc_ident),0,do_scc_count,do_scc_count)
222
223 # define SET_CCC_RTS(cc_ident,do_sub_count,do_scc_count) \
224          SET_CCC_X(STATIC_CC_REF(cc_ident),do_sub_count,0,do_scc_count)
225 \end{code}
226
227 We have this @RESTORE_CCC@ macro, rather than just an assignment,
228 in case we want to do any paranoia-checking here.
229 \begin{code}
230 # define RESTORE_CCC(cc)                \
231         do {                            \
232         CCC = (CostCentre) (cc);        \
233         ASSERT_IS_REGISTERED(CCC,1);    \
234         } while(0)
235 \end{code}
236
237 On entry to top level CAFs we count the scc ...
238 \begin{code}
239 # define ENTER_CC_CAF_X(cc)                                             \
240         do {                                                            \
241         CCC->sub_cafcc_count++; /* inc subcaf count of CCC */           \
242         CCC = (CostCentre)(cc); /* set CCC to ident cc */               \
243         ASSERT_IS_REGISTERED(CCC,1);                                    \
244         CCC->scc_count++;       /* inc scc count of CAF cc */           \
245         } while(0)
246
247 # define ENTER_CC_CAF(cc_ident)   ENTER_CC_CAF_X(STATIC_CC_REF(cc_ident))
248 # define ENTER_CC_CAF_CL(closure) ENTER_CC_CAF_X((CostCentre)CC_HDR(closure))
249 \end{code}
250
251 On entering a closure we only count the enter to thunks ...
252 \begin{code}
253 # define ENTER_CC_T(cc)                                 \
254         do {                                            \
255         CCC = (CostCentre)(cc);                         \
256         ASSERT_IS_REGISTERED(CCC,1);                    \
257         CCC_DETAIL_COUNT(CCC->thunk_count);             \
258         } while(0)      
259
260 # define ENTER_CC_TCL(closure)                          \
261         ENTER_CC_T(CC_HDR(closure))
262
263 /* Here is our special "hybrid" case when we do *not* set the CCC.
264    (a) The closure is a function, not a thunk;
265    (b) The CC is CAF/DICT-ish.
266 */
267 # define ENTER_CC_F(centre)                             \
268         do {                                            \
269         CostCentre cc = (CostCentre) (centre);          \
270         ASSERT_IS_REGISTERED(cc,1);                     \
271         if ( ! IS_CAF_OR_DICT_CC(cc) ) {                \
272             CCC = cc;                                   \
273         } else {                                        \
274             CCC_DETAIL_COUNT(cc->caffun_subsumed);      \
275             CCC_DETAIL_COUNT(CCC->subsumed_caf_count);  \
276         }                                               \
277         CCC_DETAIL_COUNT(CCC->function_count);          \
278         } while(0)
279
280 # define ENTER_CC_FCL(closure)                          \
281         ENTER_CC_F(CC_HDR(closure))
282
283 # define ENTER_CC_FSUB()                                \
284         do {                                            \
285         CCC_DETAIL_COUNT(CCC->subsumed_fun_count);      \
286         CCC_DETAIL_COUNT(CCC->function_count);          \
287         } while(0)
288
289 # define ENTER_CC_FCAF(centre)                          \
290         do {                                            \
291         CostCentre cc = (CostCentre) (centre);          \
292         ASSERT_IS_REGISTERED(cc,1);                     \
293         CCC_DETAIL_COUNT(cc->caffun_subsumed);          \
294         CCC_DETAIL_COUNT(CCC->subsumed_caf_count);      \
295         CCC_DETAIL_COUNT(CCC->function_count);          \
296         } while(0)
297
298 # define ENTER_CC_FLOAD(cc)                             \
299         do {                                            \
300         CCC = (CostCentre)(cc);                         \
301         ASSERT_IS_REGISTERED(CCC,1);                    \
302         CCC_DETAIL_COUNT(CCC->function_count);          \
303         } while(0)
304
305 /* These ENTER_CC_PAP things are only used in the RTS */
306
307 # define ENTER_CC_PAP(centre)                           \
308         do {                                            \
309         CostCentre cc = (CostCentre) (centre);          \
310         ASSERT_IS_REGISTERED(cc,1);                     \
311         if ( ! IS_CAF_OR_DICT_CC(cc) ) {                \
312             CCC = cc;                                   \
313         } else {                                        \
314             CCC_DETAIL_COUNT(cc->caffun_subsumed);      \
315             CCC_DETAIL_COUNT(CCC->subsumed_caf_count);  \
316         }                                               \
317         CCC_DETAIL_COUNT(CCC->pap_count);               \
318         } while(0)                      
319                                         
320 # define ENTER_CC_PAP_CL(closure)                       \
321         ENTER_CC_PAP(CC_HDR(closure))
322
323 # if defined(PROFILING_DETAIL_COUNTS)
324 # define CCC_DETAIL_COUNT(inc_this) ((inc_this)++)
325 # else
326 # define CCC_DETAIL_COUNT(inc_this) /*nothing*/
327 # endif
328
329 #endif /* PROFILING */
330 \end{code}
331
332 %************************************************************************
333 %*                                                                      *
334 \subsection{``Registering'' cost-centres}
335 %*                                                                      *
336 %************************************************************************
337
338 Cost centres are registered at startup by calling a registering
339 routine in each module. Each module registers its cost centres and
340 calls the registering routine for all imported modules. The RTS calls
341 the registering routine for the module Main. This registering must be
342 done before initialisation since the evaluation required for
343 initialisation may use the cost centres.
344
345 As the code for each module uses tail calls we use an auxiliary stack
346 (in the heap) to record imported modules still to be registered. At
347 the bottom of the stack is NULL which indicates that
348 @miniInterpretEnd@ should be resumed.
349
350 @START_REGISTER@ and @END_REGISTER@ are special macros used to
351 delimit the function. @END_REGISTER@ pops the next registering
352 routine off the stack and jumps to it. @REGISTER_CC@ registers a cost
353 centre. @REGISTER_IMPORT@ pushes a modules registering routine onto
354 the register stack.
355
356 \begin{code}
357 #if defined(PROFILING)
358
359 extern F_ _regMain (STG_NO_ARGS);
360 extern F_ *register_stack;
361
362 # define PUSH_REGISTER_STACK(reg_function)                              \
363         *(register_stack++) = (F_)reg_function
364
365 # define POP_REGISTER_STACK                                             \
366         *(--register_stack)
367
368 # define START_REGISTER_CCS(reg_mod_name)                               \
369         static int _module_registered = 0;                              \
370         STGFUN(reg_mod_name) {                                          \
371             FUNBEGIN;                                                   \
372             if (! _module_registered) {                                 \
373                 _module_registered = 1
374
375 # define START_REGISTER_PRELUDE(reg_mod_name)                           \
376         static int CAT2(reg_mod_name,_done) = 0;                        \
377         STGFUN(reg_mod_name) {                                          \
378             FUNBEGIN;                                                   \
379             if (! CAT2(reg_mod_name,_done)) {                           \
380                 CAT2(reg_mod_name,_done) = 1
381
382 # define REGISTER_IMPORT(reg_mod_name)                                  \
383         do { extern F_ reg_mod_name (STG_NO_ARGS) ;                     \
384           PUSH_REGISTER_STACK(reg_mod_name) ;                           \
385         } while (0)
386         
387 # define END_REGISTER_CCS()                                             \
388         };                                                              \
389         do {                                                            \
390             F_ cont = POP_REGISTER_STACK;                               \
391             if (cont == NULL) {                                         \
392                 RESUME_(miniInterpretEnd);                              \
393             } else {                                                    \
394                 JMP_(cont);                                             \
395             }                                                           \
396         } while(0);                                                     \
397         FUNEND; }
398
399 #endif  /* PROFILING */
400 \end{code}
401
402 We don't want to attribute costs to an unregistered cost-centre:
403 \begin{code}
404 #if !defined(PROFILING) || !defined(DEBUG)
405 # define ASSERT_IS_REGISTERED(cc,chk_not_overhead) /*nothing*/
406 #else
407 # define ASSERT_IS_REGISTERED(cc,chk_not_overhead)                              \
408         do {    /* beware of cc name-capture */                                 \
409         CostCentre c_c = (CostCentre) (cc);                                     \
410         if (c_c->registered == NOT_REGISTERED) {                                \
411             fprintf(stderr,"Entering unregistered CC: %s\n",c_c->label);        \
412             /* unsafe c-call, BTW */                                            \
413         }                                                                       \
414         if ( (chk_not_overhead) && c_c == STATIC_CC_REF(CC_OVERHEAD) ) {        \
415             fprintf(stderr,"CC should not be OVERHEAD!: %s\n",c_c->label);      \
416             /* unsafe c-call, BTW */                                            \
417         } } while(0)
418 #endif
419
420 #define REGISTER_CC(cc)                                                 \
421         do {                                                            \
422         extern CostCentre cc;                                           \
423         if (((CostCentre)(cc))->registered == NOT_REGISTERED) {         \
424             ((CostCentre)(cc))->registered = Registered_CC;             \
425             Registered_CC = (CostCentre)(cc);                           \
426         }} while(0)
427
428 \end{code}
429
430 %************************************************************************
431 %*                                                                      *
432 \subsection[declaring-closure-categories]{Declaring Closure Categories}
433 %*                                                                      *
434 %************************************************************************
435
436 Closure category records are attached to the info table of the
437 closure. They are declared with the info table. Hashing will map
438 similar categories to the same hash value allowing statistics to be
439 grouped by closure category.
440
441 The declaration macros expand to nothing if cost centre profiling is
442 not required.
443
444 Note from ADR: Very dubious Malloc Ptr addition -- should probably just
445 reuse @CON_K@ (or something) in runtime/main/StgStartup.lhc.
446 Similarily, the SP stuff should probably be the highly uninformative
447 @INTERNAL_KIND@.
448
449 SOF 4/96: Renamed MallocPtr_K to ForeignObj_K 
450
451 \begin{code}
452 #if defined(PROFILING)
453
454 # define CON_K          1
455 # define FN_K           2
456 # define PAP_K          3
457 # define THK_K          4
458 # define BH_K           5
459 # define ARR_K          6
460
461 # ifndef PAR
462 #  define ForeignObj_K  7  /* Malloc Pointer */
463 #  define SPT_K         8  /* Stable Pointer Table */
464 # endif /* !PAR */
465
466 # define INTERNAL_KIND  10
467
468 typedef struct ClCat {
469    hash_t index_val;    /* hashed value */
470    I_    selected; /* is this category selected (-1 == not memoised, selected? 0 or 1) */
471    I_    kind;     /* closure kind -- as above */
472    char *descr;    /* source derived string detailing closure description */
473    char *type;      /* source derived string detailing closure type */
474 } *ClCategory;
475
476 /* We put pointers to these ClCat things in info tables.
477    We need these ClCat things because they are mutable,
478    whereas info tables are immutable.  (WDP 94/11)
479
480    We really should not make funny names by appending _CAT.
481 */
482
483 # define MK_CAT_IDENT(i)   CAT2(i,_CAT)
484 # define REF_CAT_IDENT(i)  (&MK_CAT_IDENT(i))
485
486 # define CAT_DECLARE(base_name, kind, descr, type) \
487         static struct ClCat MK_CAT_IDENT(base_name) = {UNHASHED,-1,kind,descr,type};
488
489 #endif /* PROFILING */
490 \end{code}
491
492 %************************************************************************
493 %*                                                                      *
494 \subsection[timer-interupts]{Processing of Timer Signals}
495 %*                                                                      *
496 %************************************************************************
497
498 Stuff to do with timer signals:
499 \begin{code}
500 #if defined(PROFILING) || defined(PAR)
501
502 extern I_ time_profiling;       /* Flag indicating if timer/serial profiling is required */
503
504 extern I_ interval_expired;     /* Flag set by signal handler */
505 extern I_ current_interval;     /* Current interval number -- used as time stamp */
506 extern I_ interval_ticks;       /* No of ticks in an interval */
507
508 extern I_ previous_ticks;       /* ticks in previous intervals */
509 extern I_ current_ticks;        /* ticks in current interval */
510
511 extern void set_time_profile_handler(STG_NO_ARGS);
512 extern void start_time_profiler(STG_NO_ARGS);
513 extern void restart_time_profiler(STG_NO_ARGS);
514 extern void stop_time_profiler(STG_NO_ARGS);
515
516 # define TICK_FREQUENCY         50                      /* ticks per second */
517 # define TICK_MILLISECS         (1000/TICK_FREQUENCY)   /* milli-seconds per tick */
518
519 # define DEFAULT_INTERVAL       TICK_FREQUENCY          /* 1 second */
520
521 /* These are never called directly from threaded code */
522 # define START_TIME_PROFILER    ULTRASAFESTGCALL0(void,(void *),start_time_profiler)            /*R StgOverflow.lc */
523 # define RESTART_TIME_PROFILER  ULTRASAFESTGCALL0(void,(void *),restart_time_profiler)          /*R StgOverflow.lc */
524 # define STOP_TIME_PROFILER     ULTRASAFESTGCALL0(void,(void *),stop_time_profiler)             /*R StgOverflow.lc */
525
526 # if defined(PROFILING)
527 #  define OR_INTERVAL_EXPIRED   || (interval_expired)           /*R StgMacros.h */
528 # endif
529 \end{code}
530
531
532 %************************************************************************
533 %*                                                                      *
534 \subsection[indexing]{Indexing of Cost Centres and Categories}
535 %*                                                                      *
536 %************************************************************************
537
538 Cost Centres and Closure Categories are hashed to provide indexes
539 against which arbitrary information can be stored. These indexes are
540 memoised in the appropriate cost centre or category record and
541 subsequent hashes avoided by the index routine (it simply returns the
542 memoised index).
543
544 There are different features which can be hashed allowing information
545 to be stored for different groupings. Cost centres have the cost
546 centre recorded (using the pointer), module and group. Closure
547 categories have the closure description and the type
548 description. Records with the same feature will be hashed to the same
549 index value.
550
551 The initialisation routines, @init_index_<feature>@, allocate a hash
552 table in which the cost centre / category records are stored. The
553 lower bound for the table size is taken from @max_<feature>_no@. They
554 return the actual table size used (the next power of 2). Unused
555 locations in the hash table are indicated by a 0 entry. Successive
556 @init_index_<feature>@ calls just return the actual table size.
557
558 Calls to @index_<feature>@ will insert the cost centre / category
559 record in the <feature> hash table, if not already inserted. The hash
560 index is memoised in the record and returned. 
561
562 CURRENTLY ONLY ONE MEMOISATION SLOT IS AVILABLE IN EACH RECORD SO
563 HASHING CAN ONLY BE DONE ON ONE FEATURE FOR EACH RECORD. This can be
564 easily relaxed at the expense of extra memoisation space or continued
565 rehashing.
566
567 The initialisation routines must be called before initialisation of
568 the stacks and heap as they require to allocate storage. It is also
569 expected that the caller may want to allocate additional storage in
570 which to store profiling information based on the return table size
571 value(s).
572
573 \begin{code}
574 # if defined(PROFILING)
575
576 #  define DEFAULT_MAX_CC     4096
577 #  define DEFAULT_MAX_MOD     256
578 #  define DEFAULT_MAX_GRP     128
579 #  define DEFAULT_MAX_DESCR  4096
580 #  define DEFAULT_MAX_TYPE   1024
581
582 extern hash_t max_cc_no;                        /* Hash on CC ptr */
583 extern CostCentre *index_cc_table;
584 extern hash_t init_index_cc(STG_NO_ARGS);
585 extern hash_t index_cc PROTO((CostCentre cc));
586
587 extern hash_t max_mod_no;                       /* Hash on CC module */
588 extern CostCentre *index_mod_table;
589 extern hash_t init_index_mod(STG_NO_ARGS);
590 extern hash_t index_mod PROTO((CostCentre cc));
591
592 extern hash_t max_grp_no;                       /* Hash on CC group */
593 extern CostCentre *index_grp_table;
594 extern hash_t init_index_grp(STG_NO_ARGS);
595 extern hash_t index_grp PROTO((CostCentre cc));
596
597 extern hash_t max_descr_no;                     /* Hash on closure description */
598 extern ClCategory *index_descr_table;
599 extern hash_t init_index_descr(STG_NO_ARGS);
600 extern hash_t index_descr PROTO((ClCategory clcat));
601
602 extern hash_t max_type_no;                      /* Hash on type description */
603 extern ClCategory *index_type_table;
604 extern hash_t init_index_type(STG_NO_ARGS);
605 extern hash_t index_type PROTO((ClCategory clcat));
606
607 # endif /* PROFILING */
608 \end{code}
609
610
611 %************************************************************************
612 %*                                                                      *
613 \subsection[metering]{Metering of Statistics}
614 %*                                                                      *
615 %************************************************************************
616
617 @scc_count@ is incremented by the @SetCC@ macro in section
618 \ref{manipulating-cost-centres} above. Below we have the time tick and
619 memory alloc macros.
620
621 \begin{code}
622 # define CC_TICK(centre)                                                \
623         do { CostCentre cc = (CostCentre) (centre);                     \
624         ASSERT_IS_REGISTERED(cc,1);                                     \
625         cc->time_ticks += 1;                                            \
626         } while(0)
627
628 # if defined(PROFILING)
629 # define CC_ALLOC(centre, size, kind)                                   \
630         do { CostCentre cc = (CostCentre) (centre);                     \
631         ASSERT_IS_REGISTERED(cc,0/*OK if OVERHEAD*/);                   \
632         CCC_DETAIL_COUNT(cc->mem_allocs);                               \
633         cc->mem_alloc += (size) - (PROF_FIXED_HDR + TICKY_FIXED_HDR);   \
634         } while(0) 
635 # endif
636 \end{code}
637
638
639 %************************************************************************
640 %*                                                                      *
641 \subsection[cost-centre-profiling]{Cost Centre Profiling}
642 %*                                                                      *
643 %************************************************************************
644
645 \begin{code}
646 I_      init_cc_profiling PROTO((I_ rts_argc, char *rts_argv[], char *prog_argv[]));
647 void    report_cc_profiling PROTO((I_ final));
648
649 void    cc_register(STG_NO_ARGS);
650 void    cc_sort PROTO((CostCentre *sort, char sort_on));
651 rtsBool cc_to_ignore PROTO((CostCentre));
652 \end{code}
653
654 %************************************************************************
655 %*                                                                      *
656 \subsection[heap-profiling]{Heap Profiling}
657 %*                                                                      *
658 %************************************************************************
659
660 \begin{code}
661 # if defined(PROFILING)
662
663 I_ heap_profile_init PROTO((char *argv[]));
664
665 void heap_profile_finish(STG_NO_ARGS);
666
667 void heap_profile_setup(STG_NO_ARGS);      /* called at start of heap profile */
668 void heap_profile_done(STG_NO_ARGS);      /* called at end of heap profile */
669
670 void (* heap_profile_fn) PROTO((P_ closure,I_ size));
671
672 extern I_ earlier_ticks;                /* no. of earlier ticks grouped */
673 extern hash_t time_intervals;           /* no. of time intervals reported -- 18 */
674
675 # define HEAP_PROFILE_CLOSURE(closure,size)     \
676         do {                                    \
677         if (heap_profile_fn) {                  \
678             STGCALL2(void,(void *, P_, I_),(*heap_profile_fn),closure,size); \
679         }} while(0)
680
681 # endif /* PROFILING */
682 \end{code}
683
684 End multi-slurp protection:
685 \begin{code}
686 #endif /* PROFILING || PAR */
687
688 #endif /* CostCentre_H */
689 \end{code}