1 %************************************************************************
3 \section[CostCentre.lh]{Definitions for Cost Centre Profiling}
5 %************************************************************************
7 Multi-slurp protection:
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
18 #if defined(USE_COST_CENTRES) || defined(CONCURRENT)
20 # define CC_EXTERN(cc_ident) \
21 extern struct cc CAT2(cc_ident,_struct); \
22 extern CostCentre cc_ident
24 extern CostCentre CCC; /* the current cost centre */
26 extern CostCentre Registered_CC;/* registered cost centre list */
28 CC_EXTERN(CC_MAIN); /* initial MAIN cost centre */
29 CC_EXTERN(CC_GC); /* Garbage Collection cost center */
32 CC_EXTERN(CC_MSG); /* Communications cost center */
33 CC_EXTERN(CC_IDLE); /* Idle-time cost centre */
36 # define REGISTERED_END (CostCentre)4 /* end of list */
37 /* That 4 look likes a HACK, Patrick.
39 # define NOT_REGISTERED (CostCentre)0 /* not yet registered */
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.
48 # define CC_IS_CAF 'C'
49 # define CC_IS_DICT 'D'
50 # define CC_IS_SUBSUMED 'S'
51 # define CC_IS_BORING '\0'
53 # define STATIC_CC_REF(cc_ident) &CAT2(cc_ident,_struct)
54 # define DYN_CC_REF(cc_ident) cc_ident /* unused */
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)
62 #endif /* defined(USE_COST_CENTRES) || defined(CONCURRENT) */
65 Definitions relating to the profiling field as a whole.
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)
75 %************************************************************************
77 \subsection[no-cost-centres]{Dummy definitions if no cost centres}
79 %************************************************************************
81 The cost-centre profiling is only on if the driver turns on
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....
88 #if !defined(USE_COST_CENTRES)
90 /*** Declaration Definitions ***/
92 # define CAT_DECLARE(base_name, kind, descr, type)
94 # define CC_HDR_SIZE 0 /* No CC in fixed header */
96 # define SET_CC_HDR(closure, cc) /* Dont set CC header */
97 # define SET_STATIC_CC_HDR(cc) /* No static CC header */
99 # define SET_CCC(cc_ident,is_dupd)
101 # define RESTORE_CCC(cc)
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)
110 /*** Timer and Heap Definitions ***/
112 # define OR_INTERVAL_EXPIRED /* No || as it is false */
114 # define CC_ALLOC(cc, size, kind)
115 # define HEAP_PROFILE_CLOSURE(closure,size)
118 # define START_TIME_PROFILER
119 # define RESTART_TIME_PROFILER
120 # define STOP_TIME_PROFILER
123 #endif /* !defined(USE_COST_CENTRES) */
126 %************************************************************************
128 \subsection[declaring-cost-centres]{Declaring Cost Centres}
130 %************************************************************************
132 Now for the cost-centre profiling stuff.
134 %************************************************************************
136 \subsection[cost-centres]{Location of Cost Centres}
138 %************************************************************************
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.
145 #if defined(USE_COST_CENTRES)
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 */
151 CC_EXTERN(CC_CAFs); /* prelude cost centre (CAFs only) */
152 CC_EXTERN(CC_DICTs); /* prelude cost centre (DICTs only) */
154 # define IS_CAF_OR_DICT_CC(cc) \
155 (((cc)->is_subsumed == CC_IS_CAF) || ((cc)->is_subsumed == CC_IS_DICT))
157 # define IS_SUBSUMED_CC(cc) ((cc)->is_subsumed == CC_IS_SUBSUMED)
161 Definitions referring to the Cost Centre sub-field of the fixed header.
164 # define CC_HDR_SIZE 1 /* words of header */
165 /*R SMinterface.lh */
167 # define CC_HDR_POSN PROF_HDR_POSN /* position in header */
169 # define CC_HDR(closure) (((P_)(closure))[CC_HDR_POSN])
171 # define SET_CC_HDR(closure, cc) \
172 CC_HDR(closure) = (W_)(cc) /* Set closures cost centre */
173 /*R SMinterface.lh (CCC) */
176 For static closures ...
178 # define SET_STATIC_CC_HDR(cc_ident) \
179 , (W_) STATIC_CC_REF(cc_ident) /* static initialisation */
180 /*R SMinterface.lh */
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
187 %************************************************************************
189 \subsection{Setting the Current Cost Centre}
191 %************************************************************************
193 On execution of an @_scc_@ expression a new cost centre is set.
195 If the new cost centre is different from the CCC we set the CCC and
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)
203 # define SET_CCC_X(cc,is_dupd) \
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*/ \
210 # define SET_CCC(cc_ident,is_dupd) SET_CCC_X(STATIC_CC_REF(cc_ident),is_dupd)
213 We have this @RESTORE_CCC@ macro, rather than just an assignment,
214 in case we want to do any paranoia-checking here.
216 # define RESTORE_CCC(cc) \
218 CCC = (CostCentre) (cc); \
219 ASSERT_IS_REGISTERED(CCC,1); \
223 On entry to top level CAFs we count the scc ...
225 # define ENTER_CC_CAF_X(cc) \
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 */ \
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))
237 On entering a closure we only count the enter to thunks ...
239 # define ENTER_CC_T(cc) \
241 CCC = (CostCentre)(cc); \
242 ASSERT_IS_REGISTERED(CCC,1); \
243 CCC->thunk_count++; /* inc thunk count of new CCC */ \
246 # define ENTER_CC_TCL(closure) \
247 ENTER_CC_T(CC_HDR(closure))
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.
253 # define ENTER_CC_F(centre) \
255 CostCentre cc = (CostCentre) (centre); \
256 ASSERT_IS_REGISTERED(cc,1); \
257 if ( ! IS_CAF_OR_DICT_CC(cc) ) { \
260 CCC->function_count++; \
263 # define ENTER_CC_FCL(closure) \
264 ENTER_CC_F(CC_HDR(closure))
266 /* These ENTER_CC_PAP things are only used in the RTS */
268 # define ENTER_CC_PAP(centre) \
270 CostCentre cc = (CostCentre) (centre); \
271 ASSERT_IS_REGISTERED(cc,1); \
272 if ( ! IS_CAF_OR_DICT_CC(cc) ) { \
278 # define ENTER_CC_PAP_CL(closure) \
279 ENTER_CC_PAP(CC_HDR(closure))
281 #endif /* USE_COST_CENTRES */
284 %************************************************************************
286 \subsection{``Registering'' cost-centres}
288 %************************************************************************
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.
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.
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
309 #if defined(USE_COST_CENTRES)
311 extern F_ _regMain (STG_NO_ARGS);
312 extern F_ *register_stack;
314 # define PUSH_REGISTER_STACK(reg_function) \
315 *(register_stack++) = (F_)reg_function
317 # define POP_REGISTER_STACK \
322 # define START_REGISTER_CCS(reg_mod_name) \
323 static int _module_registered = 0; \
324 STGFUN(reg_mod_name) { \
326 if (! _module_registered) { \
327 _module_registered = 1
329 # define START_REGISTER_PRELUDE(reg_mod_name) \
330 static int CAT2(reg_mod_name,_done) = 0; \
331 STGFUN(reg_mod_name) { \
333 if (! CAT2(reg_mod_name,_done)) { \
334 CAT2(reg_mod_name,_done) = 1
336 # define REGISTER_IMPORT(reg_mod_name) \
337 do { extern F_ reg_mod_name (STG_NO_ARGS) ; \
338 PUSH_REGISTER_STACK(reg_mod_name) ; \
341 # define END_REGISTER_CCS() \
344 F_ cont = POP_REGISTER_STACK; \
345 if (cont == NULL) { \
346 RESUME_(miniInterpretEnd); \
353 #endif /* USE_COST_CENTRES */
356 We don't want to attribute costs to an unregistered cost-centre:
358 #if !defined(USE_COST_CENTRES) || !defined(DEBUG)
359 # define ASSERT_IS_REGISTERED(cc,chk_not_overhead) /*nothing*/
361 # define ASSERT_IS_REGISTERED(cc,chk_not_overhead) \
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 */ \
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 */ \
374 #define REGISTER_CC(cc) \
376 extern CostCentre cc; \
377 if (((CostCentre)(cc))->registered == NOT_REGISTERED) { \
378 ((CostCentre)(cc))->registered = Registered_CC; \
379 Registered_CC = (CostCentre)(cc); \
384 %************************************************************************
386 \subsection[declaring-closure-categories]{Declaring Closure Categories}
388 %************************************************************************
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.
395 The declaration macros expand to nothing if cost centre profiling is
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
404 #if defined(USE_COST_CENTRES)
414 # define MallocPtr_K 7 /* Malloc Pointer */
415 # define SPT_K 8 /* Stable Pointer Table */
418 # define INTERNAL_KIND 10
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 */
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)
432 We really should not make funny names by appending _CAT.
435 # define MK_CAT_IDENT(i) CAT2(i,_CAT)
436 # define REF_CAT_IDENT(i) (&MK_CAT_IDENT(i))
438 # define CAT_DECLARE(base_name, kind, descr, type) \
439 static struct ClCat MK_CAT_IDENT(base_name) = {UNHASHED,-1,kind,descr,type};
441 #endif /* USE_COST_CENTRES */
444 %************************************************************************
446 \subsection[timer-interupts]{Processing of Timer Signals}
448 %************************************************************************
450 Stuff to do with timer signals:
452 #if defined(USE_COST_CENTRES) || defined(GUM)
454 extern I_ time_profiling; /* Flag indicating if timer/serial profiling is required */
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 */
460 extern I_ previous_ticks; /* ticks in previous intervals */
461 extern I_ current_ticks; /* ticks in current interval */
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);
468 # define TICK_FREQUENCY 50 /* ticks per second */
469 # define TICK_MILLISECS (1000/TICK_FREQUENCY) /* milli-seconds per tick */
472 extern I_ profilerTicks;
473 extern I_ tick_millisecs;
476 # define DEFAULT_INTERVAL TICK_FREQUENCY /* 1 second */
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 */
483 # if defined(USE_COST_CENTRES)
484 # define OR_INTERVAL_EXPIRED || (interval_expired) /*R StgMacros.h */
489 %************************************************************************
491 \subsection[indexing]{Indexing of Cost Centres and Categories}
493 %************************************************************************
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
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
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.
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.
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
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
531 # if defined(USE_COST_CENTRES)
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
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));
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));
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));
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));
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));
564 # endif /* USE_COST_CENTRES */
568 %************************************************************************
570 \subsection[metering]{Metering of Statistics}
572 %************************************************************************
574 @scc_count@ is incremented by the @SetCC@ macro in section
575 \ref{manipulating-cost-centres} above. Below we have the time tick and
579 # define CC_TICK(cc) \
580 do { CostCentre centre = (CostCentre) (cc); \
581 ASSERT_IS_REGISTERED(centre,1); \
582 centre->time_ticks += 1; \
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...! */
596 %************************************************************************
598 \subsection[cost-centre-profiling]{Cost Centre Profiling}
600 %************************************************************************
603 extern I_ cc_profiling; /* Are we performing/reporting cc profiling? */
604 extern I_ heap_profiling_reqd; /* Are we performing heap profiling? */
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 */
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));
614 extern void cc_register(STG_NO_ARGS);
615 extern void cc_sort PROTO((CostCentre *sort, char sort_on));
618 %************************************************************************
620 \subsection[heap-profiling]{Heap Profiling}
622 %************************************************************************
625 # define HEAP_NO_PROFILING 0 /* N.B. Used as indexes into arrays */
627 # if defined(USE_COST_CENTRES)
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
639 # define DESCRchar 'D'
640 # define TYPEchar 'Y'
641 # define TIMEchar 'T'
643 extern I_ heap_profile_init PROTO((I_ prof,
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,
653 extern void heap_profile_finish(STG_NO_ARGS);
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 */
658 extern void (* heap_profile_fn) PROTO((P_ closure,I_ size));
660 extern I_ earlier_ticks; /* no. of earlier ticks grouped */
661 extern hash_t time_intervals; /* no. of time intervals reported -- 18 */
663 # define HEAP_PROFILE_CLOSURE(closure,size) \
664 STGCALL2(void,(void *, P_, I_),(*heap_profile_fn),closure,size) /*R SM2s.lh */
666 # endif /* USE_COST_CENTRES */
669 End multi-slurp protection:
671 #endif /* USE_COST_CENTRES || GUM */
673 #endif /* CostCentre_H */