[project @ 1996-01-11 14:06:51 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 '\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(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,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 PAR
118 #  define START_TIME_PROFILER
119 #  define RESTART_TIME_PROFILER
120 #  define STOP_TIME_PROFILER
121 # endif
122
123 #endif /* !defined(PROFILING) */
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(PROFILING)
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 /* PROFILING */
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(PROFILING)
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 # define START_REGISTER_CCS(reg_mod_name)                               \
321         static int _module_registered = 0;                              \
322         STGFUN(reg_mod_name) {                                          \
323             FUNBEGIN;                                                   \
324             if (! _module_registered) {                                 \
325                 _module_registered = 1
326
327 # define START_REGISTER_PRELUDE(reg_mod_name)                           \
328         static int CAT2(reg_mod_name,_done) = 0;                        \
329         STGFUN(reg_mod_name) {                                          \
330             FUNBEGIN;                                                   \
331             if (! CAT2(reg_mod_name,_done)) {                           \
332                 CAT2(reg_mod_name,_done) = 1
333
334 # define REGISTER_IMPORT(reg_mod_name)                                  \
335         do { extern F_ reg_mod_name (STG_NO_ARGS) ;                     \
336           PUSH_REGISTER_STACK(reg_mod_name) ;                           \
337         } while (0)
338         
339 # define END_REGISTER_CCS()                                             \
340         };                                                              \
341         do {                                                            \
342             F_ cont = POP_REGISTER_STACK;                               \
343             if (cont == NULL) {                                         \
344                 RESUME_(miniInterpretEnd);                              \
345             } else {                                                    \
346                 JMP_(cont);                                             \
347             }                                                           \
348         } while(0);                                                     \
349         FUNEND; }
350
351 #endif  /* PROFILING */
352 \end{code}
353
354 We don't want to attribute costs to an unregistered cost-centre:
355 \begin{code}
356 #if !defined(PROFILING) || !defined(DEBUG)
357 # define ASSERT_IS_REGISTERED(cc,chk_not_overhead) /*nothing*/
358 #else
359 # define ASSERT_IS_REGISTERED(cc,chk_not_overhead)                              \
360         do {                                                                    \
361         CostCentre c_c = (CostCentre) (cc);                                     \
362         if (c_c->registered == NOT_REGISTERED) {                                \
363             fprintf(stderr,"Entering unregistered CC: %s\n",c_c->label);        \
364             /* unsafe c-call, BTW */                                            \
365         }                                                                       \
366         if ( (chk_not_overhead) && c_c == STATIC_CC_REF(CC_OVERHEAD) ) {        \
367             fprintf(stderr,"CC should not be OVERHEAD!: %s\n",c_c->label);      \
368             /* unsafe c-call, BTW */                                            \
369         } } while(0)
370 #endif
371
372 #define REGISTER_CC(cc)                                                 \
373         do {                                                            \
374         extern CostCentre cc;                                           \
375         if (((CostCentre)(cc))->registered == NOT_REGISTERED) {         \
376             ((CostCentre)(cc))->registered = Registered_CC;             \
377             Registered_CC = (CostCentre)(cc);                           \
378         }} while(0)
379
380 \end{code}
381
382 %************************************************************************
383 %*                                                                      *
384 \subsection[declaring-closure-categories]{Declaring Closure Categories}
385 %*                                                                      *
386 %************************************************************************
387
388 Closure category records are attached to the info table of the
389 closure. They are declared with the info table. Hashing will map
390 similar categories to the same hash value allowing statistics to be
391 grouped by closure category.
392
393 The declaration macros expand to nothing if cost centre profiling is
394 not required.
395
396 Note from ADR: Very dubious Malloc Ptr addition -- should probably just
397 reuse @CON_K@ (or something) in runtime/main/StgStartup.lhc.
398 Similarily, the SP stuff should probably be the highly uninformative
399 @INTERNAL_KIND@.
400
401 \begin{code}
402 #if defined(PROFILING)
403
404 # define CON_K          1
405 # define FN_K           2
406 # define PAP_K          3
407 # define THK_K          4
408 # define BH_K           5
409 # define ARR_K          6
410
411 # ifndef PAR
412 #  define MallocPtr_K   7  /* Malloc Pointer */
413 #  define SPT_K         8  /* Stable Pointer Table */
414 # endif /* !PAR */
415
416 # define INTERNAL_KIND  10
417
418 typedef struct ClCat {
419    hash_t index_val;    /* hashed value */
420    I_    selected; /* is this category selected (-1 == not memoised, selected? 0 or 1) */
421    I_    kind;     /* closure kind -- as above */
422    char *descr;    /* source derived string detailing closure description */
423    char *type;      /* source derived string detailing closure type */
424 } *ClCategory;
425
426 /* We put pointers to these ClCat things in info tables.
427    We need these ClCat things because they are mutable,
428    whereas info tables are immutable.  (WDP 94/11)
429
430    We really should not make funny names by appending _CAT.
431 */
432
433 # define MK_CAT_IDENT(i)   CAT2(i,_CAT)
434 # define REF_CAT_IDENT(i)  (&MK_CAT_IDENT(i))
435
436 # define CAT_DECLARE(base_name, kind, descr, type) \
437         static struct ClCat MK_CAT_IDENT(base_name) = {UNHASHED,-1,kind,descr,type};
438
439 #endif /* PROFILING */
440 \end{code}
441
442 %************************************************************************
443 %*                                                                      *
444 \subsection[timer-interupts]{Processing of Timer Signals}
445 %*                                                                      *
446 %************************************************************************
447
448 Stuff to do with timer signals:
449 \begin{code}
450 #if defined(PROFILING) || defined(PAR)
451
452 extern I_ time_profiling;       /* Flag indicating if timer/serial profiling is required */
453
454 extern I_ interval_expired;     /* Flag set by signal handler */
455 extern I_ current_interval;     /* Current interval number -- used as time stamp */
456 extern I_ interval_ticks;       /* No of ticks in an interval */
457
458 extern I_ previous_ticks;       /* ticks in previous intervals */
459 extern I_ current_ticks;        /* ticks in current interval */
460
461 extern void set_time_profile_handler(STG_NO_ARGS);
462 extern void start_time_profiler(STG_NO_ARGS);
463 extern void restart_time_profiler(STG_NO_ARGS);
464 extern void stop_time_profiler(STG_NO_ARGS);
465
466 # define TICK_FREQUENCY         50                      /* ticks per second */
467 # define TICK_MILLISECS         (1000/TICK_FREQUENCY)   /* milli-seconds per tick */
468
469 # define DEFAULT_INTERVAL       TICK_FREQUENCY          /* 1 second */
470
471 /* These are never called directly from threaded code */
472 # define START_TIME_PROFILER    ULTRASAFESTGCALL0(void,(void *),start_time_profiler)            /*R StgOverflow.lc */
473 # define RESTART_TIME_PROFILER  ULTRASAFESTGCALL0(void,(void *),restart_time_profiler)          /*R StgOverflow.lc */
474 # define STOP_TIME_PROFILER     ULTRASAFESTGCALL0(void,(void *),stop_time_profiler)             /*R StgOverflow.lc */
475
476 # if defined(PROFILING)
477 #  define OR_INTERVAL_EXPIRED   || (interval_expired)           /*R StgMacros.h */
478 # endif
479 \end{code}
480
481
482 %************************************************************************
483 %*                                                                      *
484 \subsection[indexing]{Indexing of Cost Centres and Categories}
485 %*                                                                      *
486 %************************************************************************
487
488 Cost Centres and Closure Categories are hashed to provide indexes
489 against which arbitrary information can be stored. These indexes are
490 memoised in the appropriate cost centre or category record and
491 subsequent hashes avoided by the index routine (it simply returns the
492 memoised index).
493
494 There are different features which can be hashed allowing information
495 to be stored for different groupings. Cost centres have the cost
496 centre recorded (using the pointer), module and group. Closure
497 categories have the closure description and the type
498 description. Records with the same feature will be hashed to the same
499 index value.
500
501 The initialisation routines, @init_index_<feature>@, allocate a hash
502 table in which the cost centre / category records are stored. The
503 lower bound for the table size is taken from @max_<feature>_no@. They
504 return the actual table size used (the next power of 2). Unused
505 locations in the hash table are indicated by a 0 entry. Successive
506 @init_index_<feature>@ calls just return the actual table size.
507
508 Calls to @index_<feature>@ will insert the cost centre / category
509 record in the <feature> hash table, if not already inserted. The hash
510 index is memoised in the record and returned. 
511
512 CURRENTLY ONLY ONE MEMOISATION SLOT IS AVILABLE IN EACH RECORD SO
513 HASHING CAN ONLY BE DONE ON ONE FEATURE FOR EACH RECORD. This can be
514 easily relaxed at the expense of extra memoisation space or continued
515 rehashing.
516
517 The initialisation routines must be called before initialisation of
518 the stacks and heap as they require to allocate storage. It is also
519 expected that the caller may want to allocate additional storage in
520 which to store profiling information based on the return table size
521 value(s).
522
523 \begin{code}
524 # if defined(PROFILING)
525
526 #  define DEFAULT_MAX_CC     4096
527 #  define DEFAULT_MAX_MOD     256
528 #  define DEFAULT_MAX_GRP     128
529 #  define DEFAULT_MAX_DESCR  4096
530 #  define DEFAULT_MAX_TYPE   1024
531
532 extern hash_t max_cc_no;                        /* Hash on CC ptr */
533 extern CostCentre *index_cc_table;
534 extern hash_t init_index_cc(STG_NO_ARGS);
535 extern hash_t index_cc PROTO((CostCentre cc));
536
537 extern hash_t max_mod_no;                       /* Hash on CC module */
538 extern CostCentre *index_mod_table;
539 extern hash_t init_index_mod(STG_NO_ARGS);
540 extern hash_t index_mod PROTO((CostCentre cc));
541
542 extern hash_t max_grp_no;                       /* Hash on CC group */
543 extern CostCentre *index_grp_table;
544 extern hash_t init_index_grp(STG_NO_ARGS);
545 extern hash_t index_grp PROTO((CostCentre cc));
546
547 extern hash_t max_descr_no;                     /* Hash on closure description */
548 extern ClCategory *index_descr_table;
549 extern hash_t init_index_descr(STG_NO_ARGS);
550 extern hash_t index_descr PROTO((ClCategory clcat));
551
552 extern hash_t max_type_no;                      /* Hash on type description */
553 extern ClCategory *index_type_table;
554 extern hash_t init_index_type(STG_NO_ARGS);
555 extern hash_t index_type PROTO((ClCategory clcat));
556
557 # endif /* PROFILING */
558 \end{code}
559
560
561 %************************************************************************
562 %*                                                                      *
563 \subsection[metering]{Metering of Statistics}
564 %*                                                                      *
565 %************************************************************************
566
567 @scc_count@ is incremented by the @SetCC@ macro in section
568 \ref{manipulating-cost-centres} above. Below we have the time tick and
569 memory alloc macros.
570
571 \begin{code}
572 # define CC_TICK(cc)                                                    \
573         do { CostCentre centre = (CostCentre) (cc);                     \
574         ASSERT_IS_REGISTERED(centre,1);                                 \
575         centre->time_ticks += 1;                                        \
576         } while(0)
577
578 # if defined(PROFILING)
579 #  define CC_ALLOC(cc, size, kind)                                      \
580         do { CostCentre cc_ = (CostCentre) (cc);                        \
581         ASSERT_IS_REGISTERED(cc_,0/*OK if OVERHEAD*/);                  \
582         cc_->mem_allocs += 1;                                           \
583         cc_->mem_alloc  += (size) - (PROF_FIXED_HDR + TICKY_FIXED_HDR); \
584         } while(0) /* beware name-capture by ASSERT_IS...! */
585 # endif
586 \end{code}
587
588
589 %************************************************************************
590 %*                                                                      *
591 \subsection[cost-centre-profiling]{Cost Centre Profiling}
592 %*                                                                      *
593 %************************************************************************
594
595 \begin{code}
596 I_      init_cc_profiling PROTO((I_ rts_argc, char *rts_argv[], char *prog_argv[]));
597 void    report_cc_profiling PROTO((I_ final));
598
599 void    cc_register(STG_NO_ARGS);
600 void    cc_sort PROTO((CostCentre *sort, char sort_on));
601 rtsBool cc_to_ignore PROTO((CostCentre));
602 \end{code}
603
604 %************************************************************************
605 %*                                                                      *
606 \subsection[heap-profiling]{Heap Profiling}
607 %*                                                                      *
608 %************************************************************************
609
610 \begin{code}
611 # if defined(PROFILING)
612
613 extern I_ heap_profile_init PROTO((char *select_cc_str,
614                                    char *select_mod_str,
615                                    char *select_grp_str,
616                                    char *select_descr_str,
617                                    char *select_typ_str,
618                                    char *select_kind_str,
619                                    char *argv[]));
620
621 extern void heap_profile_finish(STG_NO_ARGS);
622
623 extern void heap_profile_setup(STG_NO_ARGS);      /* called at start of heap profile */
624 extern void heap_profile_done(STG_NO_ARGS);       /* called at end of heap profile */
625
626 extern void (* heap_profile_fn) PROTO((P_ closure,I_ size));
627
628 extern I_ earlier_ticks;                /* no. of earlier ticks grouped */
629 extern hash_t time_intervals;           /* no. of time intervals reported -- 18 */
630
631 #  define HEAP_PROFILE_CLOSURE(closure,size) \
632         STGCALL2(void,(void *, P_, I_),(*heap_profile_fn),closure,size)                 /*R SM2s.lh */
633
634 # endif /* PROFILING */
635 \end{code}
636
637 End multi-slurp protection:
638 \begin{code}
639 #endif /* PROFILING || PAR */
640
641 #endif /* CostCentre_H */
642 \end{code}