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