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(PROFILING) || 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 'B'
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, INIT_CC_STATS}; \
60 is_local CostCentre cc_ident = STATIC_CC_REF(cc_ident)
62 #endif /* defined(PROFILING) || 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 @PROFILING@. Get them out of the way....
88 #if !defined(PROFILING)
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,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)
103 # define RESTORE_CCC(cc)
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)
115 /*** Timer and Heap Definitions ***/
117 # define OR_INTERVAL_EXPIRED /* No || as it is false */
119 # define CC_ALLOC(cc, size, kind)
120 # define HEAP_PROFILE_CLOSURE(closure,size)
123 # define START_TIME_PROFILER
124 # define RESTART_TIME_PROFILER
125 # define STOP_TIME_PROFILER
128 #endif /* !defined(PROFILING) */
131 %************************************************************************
133 \subsection[declaring-cost-centres]{Declaring Cost Centres}
135 %************************************************************************
137 Now for the cost-centre profiling stuff.
139 %************************************************************************
141 \subsection[cost-centres]{Location of Cost Centres}
143 %************************************************************************
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.
150 #if defined(PROFILING)
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 */
156 CC_EXTERN(CC_CAFs); /* prelude cost centre (CAFs only) */
157 CC_EXTERN(CC_DICTs); /* prelude cost centre (DICTs only) */
159 # define IS_CAF_OR_DICT_OR_SUB_CC(cc) \
160 ((cc)->is_subsumed & ' ') /* tests for lower case character */
164 Definitions referring to the Cost Centre sub-field of the fixed header.
167 # define CC_HDR_SIZE 1 /* words of header */
168 /*R SMinterface.lh */
170 # define CC_HDR_POSN PROF_HDR_POSN /* position in header */
172 # define CC_HDR(closure) (((P_)(closure))[CC_HDR_POSN])
174 # define SET_CC_HDR(closure, cc) \
175 CC_HDR(closure) = (W_)(cc) /* Set closures cost centre */
176 /*R SMinterface.lh (CCC) */
179 For static closures ...
181 # define SET_STATIC_CC_HDR(cc_ident) \
182 , (W_) STATIC_CC_REF(cc_ident) /* static initialisation */
183 /*R SMinterface.lh */
186 The @/*R @{\em file}@ */@ comments indicate that the macro is used
187 regardless in {\em file} so we need a null definition if cost centres
190 %************************************************************************
192 \subsection{Setting the Current Cost Centre}
194 %************************************************************************
196 On execution of an @_scc_@ expression a new cost centre is set.
198 If the new cost centre is different from the CCC we set the CCC and
201 If the cost centre is the same as the CCC no action is required. We do
202 not count the entry to avoid large counts arising from simple
203 recursion. (Huh? WDP 94/07)
206 # define SET_CCC_X(cc,do_subcc_count,do_subdict_count,do_scc_count) \
208 if ((do_subcc_count)) { CCC->sub_scc_count++; } /* inc subcc count of CCC */ \
209 if ((do_subdict_count)) { CCC->sub_dictcc_count++; } /* inc sub dict count of CCC */ \
210 CCC = (CostCentre)(cc); /* set CCC to ident cc */ \
211 ASSERT_IS_REGISTERED(CCC,1); \
212 if ((do_scc_count)) { CCC->scc_count++; } /* inc scc count of new CCC*/ \
215 # define SET_CCC(cc_ident,do_scc_count) \
216 SET_CCC_X(STATIC_CC_REF(cc_ident),do_scc_count,0,do_scc_count)
218 # define SET_DICT_CCC(cc_ident,do_scc_count) \
219 SET_CCC_X(STATIC_CC_REF(cc_ident),0,do_scc_count,do_scc_count)
221 # define SET_CCC_RTS(cc_ident,do_sub_count,do_scc_count) \
222 SET_CCC_X(STATIC_CC_REF(cc_ident),do_sub_count,0,do_scc_count)
225 We have this @RESTORE_CCC@ macro, rather than just an assignment,
226 in case we want to do any paranoia-checking here.
228 # define RESTORE_CCC(cc) \
230 CCC = (CostCentre) (cc); \
231 ASSERT_IS_REGISTERED(CCC,1); \
235 On entry to top level CAFs we count the scc ...
237 # define ENTER_CC_CAF_X(cc) \
239 CCC->sub_cafcc_count++; /* inc subcaf count of CCC */ \
240 CCC = (CostCentre)(cc); /* set CCC to ident cc */ \
241 ASSERT_IS_REGISTERED(CCC,1); \
242 CCC->scc_count++; /* inc scc count of CAF cc */ \
245 # define ENTER_CC_CAF(cc_ident) ENTER_CC_CAF_X(STATIC_CC_REF(cc_ident))
246 # define ENTER_CC_CAF_CL(closure) ENTER_CC_CAF_X((CostCentre)CC_HDR(closure))
249 On entering a closure we only count the enter to thunks ...
251 # define ENTER_CC_T(cc) \
253 CCC = (CostCentre)(cc); \
254 ASSERT_IS_REGISTERED(CCC,1); \
255 CCC_DETAIL_COUNT(CCC->thunk_count); \
258 # define ENTER_CC_TCL(closure) \
259 ENTER_CC_T(CC_HDR(closure))
261 /* Here is our special "hybrid" case when we do *not* set the CCC.
262 (a) The closure is a function, not a thunk;
263 (b) The CC is CAF/DICT-ish.
265 # define ENTER_CC_F(centre) \
267 CostCentre cc = (CostCentre) (centre); \
268 ASSERT_IS_REGISTERED(cc,1); \
269 if ( ! IS_CAF_OR_DICT_OR_SUB_CC(cc) ) { \
272 CCC_DETAIL_COUNT(cc->caffun_subsumed); \
273 CCC_DETAIL_COUNT(CCC->subsumed_caf_count); \
275 CCC_DETAIL_COUNT(CCC->function_count); \
278 # define ENTER_CC_FCL(closure) \
279 ENTER_CC_F(CC_HDR(closure))
281 # define ENTER_CC_FSUB() \
283 CCC_DETAIL_COUNT(CCC->subsumed_fun_count); \
284 CCC_DETAIL_COUNT(CCC->function_count); \
287 # define ENTER_CC_FCAF(centre) \
289 CostCentre cc = (CostCentre) (centre); \
290 ASSERT_IS_REGISTERED(cc,1); \
291 CCC_DETAIL_COUNT(cc->caffun_subsumed); \
292 CCC_DETAIL_COUNT(CCC->subsumed_caf_count); \
293 CCC_DETAIL_COUNT(CCC->function_count); \
296 # define ENTER_CC_FLOAD(cc) \
298 CCC = (CostCentre)(cc); \
299 ASSERT_IS_REGISTERED(CCC,1); \
300 CCC_DETAIL_COUNT(CCC->function_count); \
303 /* These ENTER_CC_PAP things are only used in the RTS */
305 # define ENTER_CC_PAP(centre) \
307 CostCentre cc = (CostCentre) (centre); \
308 ASSERT_IS_REGISTERED(cc,1); \
309 if ( ! IS_CAF_OR_DICT_OR_SUB_CC(cc) ) { \
312 CCC_DETAIL_COUNT(cc->caffun_subsumed); \
313 CCC_DETAIL_COUNT(CCC->subsumed_caf_count); \
315 CCC_DETAIL_COUNT(CCC->pap_count); \
318 # define ENTER_CC_PAP_CL(closure) \
319 ENTER_CC_PAP(CC_HDR(closure))
321 # if defined(PROFILING_DETAIL_COUNTS)
322 # define CCC_DETAIL_COUNT(inc_this) ((inc_this)++)
324 # define CCC_DETAIL_COUNT(inc_this) /*nothing*/
327 #endif /* PROFILING */
330 %************************************************************************
332 \subsection{``Registering'' cost-centres}
334 %************************************************************************
336 Cost centres are registered at startup by calling a registering
337 routine in each module. Each module registers its cost centres and
338 calls the registering routine for all imported modules. The RTS calls
339 the registering routine for the module Main. This registering must be
340 done before initialisation since the evaluation required for
341 initialisation may use the cost centres.
343 As the code for each module uses tail calls we use an auxiliary stack
344 (in the heap) to record imported modules still to be registered. At
345 the bottom of the stack is NULL which indicates that
346 @miniInterpretEnd@ should be resumed.
348 @START_REGISTER@ and @END_REGISTER@ are special macros used to
349 delimit the function. @END_REGISTER@ pops the next registering
350 routine off the stack and jumps to it. @REGISTER_CC@ registers a cost
351 centre. @REGISTER_IMPORT@ pushes a modules registering routine onto
355 #if defined(PROFILING)
357 extern F_ _regMain (STG_NO_ARGS);
358 extern F_ *register_stack;
360 # define PUSH_REGISTER_STACK(reg_function) \
361 *(register_stack++) = (F_)reg_function
363 # define POP_REGISTER_STACK \
366 # define START_REGISTER_CCS(reg_mod_name) \
367 static int _module_registered = 0; \
368 STGFUN(reg_mod_name) { \
370 if (! _module_registered) { \
371 _module_registered = 1
373 # define START_REGISTER_PRELUDE(reg_mod_name) \
374 static int CAT2(reg_mod_name,_done) = 0; \
375 STGFUN(reg_mod_name) { \
377 if (! CAT2(reg_mod_name,_done)) { \
378 CAT2(reg_mod_name,_done) = 1
380 # define REGISTER_IMPORT(reg_mod_name) \
381 do { extern F_ reg_mod_name (STG_NO_ARGS) ; \
382 PUSH_REGISTER_STACK(reg_mod_name) ; \
385 # define END_REGISTER_CCS() \
388 F_ cont = POP_REGISTER_STACK; \
389 if (cont == NULL) { \
390 RESUME_(miniInterpretEnd); \
397 #else /* PROFILING */
399 /* When things are working these shouldn't be emitted when not profiling,
400 but it was convenient at one point to have them expand to nothing
401 when not profiling. SLPJ Dec 96 */
403 #define START_REGISTER_CCS(reg_mod_name)
404 #define END_REGISTER_CCS()
406 #endif /* PROFILING */
409 We don't want to attribute costs to an unregistered cost-centre:
411 #if !defined(PROFILING) || !defined(DEBUG)
412 # define ASSERT_IS_REGISTERED(cc,chk_not_overhead) /*nothing*/
414 # define ASSERT_IS_REGISTERED(cc,chk_not_overhead) \
415 do { /* beware of cc name-capture */ \
416 CostCentre c_c = (CostCentre) (cc); \
417 if (c_c->registered == NOT_REGISTERED) { \
418 fprintf(stderr,"Entering unregistered CC: %s %s\n",c_c->module, c_c->label); \
419 /* unsafe c-call, BTW */ \
421 if ( (chk_not_overhead) && c_c == STATIC_CC_REF(CC_OVERHEAD) ) { \
422 fprintf(stderr,"CC should not be OVERHEAD!: %s\n",c_c->label); \
423 /* unsafe c-call, BTW */ \
427 #define REGISTER_CC(cc) \
429 extern CostCentre cc; \
430 if (((CostCentre)(cc))->registered == NOT_REGISTERED) { \
431 ((CostCentre)(cc))->registered = Registered_CC; \
432 Registered_CC = (CostCentre)(cc); \
437 %************************************************************************
439 \subsection[declaring-closure-categories]{Declaring Closure Categories}
441 %************************************************************************
443 Closure category records are attached to the info table of the
444 closure. They are declared with the info table. Hashing will map
445 similar categories to the same hash value allowing statistics to be
446 grouped by closure category.
448 The declaration macros expand to nothing if cost centre profiling is
451 Note from ADR: Very dubious Malloc Ptr addition -- should probably just
452 reuse @CON_K@ (or something) in runtime/main/StgStartup.lhc.
453 Similarily, the SP stuff should probably be the highly uninformative
456 SOF 4/96: Renamed MallocPtr_K to ForeignObj_K
459 #if defined(PROFILING)
469 # define ForeignObj_K 7 /* Malloc Pointer */
470 # define SPT_K 8 /* Stable Pointer Table */
473 # define INTERNAL_KIND 10
475 typedef struct ClCat {
476 hash_t index_val; /* hashed value */
477 I_ selected; /* is this category selected (-1 == not memoised, selected? 0 or 1) */
478 I_ kind; /* closure kind -- as above */
479 char *descr; /* source derived string detailing closure description */
480 char *type; /* source derived string detailing closure type */
483 /* We put pointers to these ClCat things in info tables.
484 We need these ClCat things because they are mutable,
485 whereas info tables are immutable. (WDP 94/11)
487 We really should not make funny names by appending _CAT.
490 # define MK_CAT_IDENT(i) CAT2(i,_CAT)
491 # define REF_CAT_IDENT(i) (&MK_CAT_IDENT(i))
493 # define CAT_DECLARE(base_name, kind, descr, type) \
494 static struct ClCat MK_CAT_IDENT(base_name) = {UNHASHED,-1,kind,descr,type};
496 #endif /* PROFILING */
499 %************************************************************************
501 \subsection[timer-interupts]{Processing of Timer Signals}
503 %************************************************************************
505 Stuff to do with timer signals:
507 #if defined(PROFILING) || defined(PAR)
509 extern I_ time_profiling; /* Flag indicating if timer/serial profiling is required */
511 extern I_ interval_expired; /* Flag set by signal handler */
512 extern I_ current_interval; /* Current interval number -- used as time stamp */
513 extern I_ interval_ticks; /* No of ticks in an interval */
515 extern I_ previous_ticks; /* ticks in previous intervals */
516 extern I_ current_ticks; /* ticks in current interval */
518 extern void set_time_profile_handler(STG_NO_ARGS);
519 extern void start_time_profiler(STG_NO_ARGS);
520 extern void restart_time_profiler(STG_NO_ARGS);
521 extern void stop_time_profiler(STG_NO_ARGS);
523 # define TICK_FREQUENCY 50 /* ticks per second */
524 # define TICK_MILLISECS (1000/TICK_FREQUENCY) /* milli-seconds per tick */
526 # define DEFAULT_INTERVAL TICK_FREQUENCY /* 1 second */
528 /* These are never called directly from threaded code */
529 # define START_TIME_PROFILER ULTRASAFESTGCALL0(void,(void *),start_time_profiler) /*R StgOverflow.lc */
530 # define RESTART_TIME_PROFILER ULTRASAFESTGCALL0(void,(void *),restart_time_profiler) /*R StgOverflow.lc */
531 # define STOP_TIME_PROFILER ULTRASAFESTGCALL0(void,(void *),stop_time_profiler) /*R StgOverflow.lc */
533 # if defined(PROFILING)
534 # define OR_INTERVAL_EXPIRED || (interval_expired) /*R StgMacros.h */
539 %************************************************************************
541 \subsection[indexing]{Indexing of Cost Centres and Categories}
543 %************************************************************************
545 Cost Centres and Closure Categories are hashed to provide indexes
546 against which arbitrary information can be stored. These indexes are
547 memoised in the appropriate cost centre or category record and
548 subsequent hashes avoided by the index routine (it simply returns the
551 There are different features which can be hashed allowing information
552 to be stored for different groupings. Cost centres have the cost
553 centre recorded (using the pointer), module and group. Closure
554 categories have the closure description and the type
555 description. Records with the same feature will be hashed to the same
558 The initialisation routines, @init_index_<feature>@, allocate a hash
559 table in which the cost centre / category records are stored. The
560 lower bound for the table size is taken from @max_<feature>_no@. They
561 return the actual table size used (the next power of 2). Unused
562 locations in the hash table are indicated by a 0 entry. Successive
563 @init_index_<feature>@ calls just return the actual table size.
565 Calls to @index_<feature>@ will insert the cost centre / category
566 record in the <feature> hash table, if not already inserted. The hash
567 index is memoised in the record and returned.
569 CURRENTLY ONLY ONE MEMOISATION SLOT IS AVILABLE IN EACH RECORD SO
570 HASHING CAN ONLY BE DONE ON ONE FEATURE FOR EACH RECORD. This can be
571 easily relaxed at the expense of extra memoisation space or continued
574 The initialisation routines must be called before initialisation of
575 the stacks and heap as they require to allocate storage. It is also
576 expected that the caller may want to allocate additional storage in
577 which to store profiling information based on the return table size
581 # if defined(PROFILING)
583 # define DEFAULT_MAX_CC 4096
584 # define DEFAULT_MAX_MOD 256
585 # define DEFAULT_MAX_GRP 128
586 # define DEFAULT_MAX_DESCR 4096
587 # define DEFAULT_MAX_TYPE 1024
589 extern hash_t max_cc_no; /* Hash on CC ptr */
590 extern CostCentre *index_cc_table;
591 extern hash_t init_index_cc(STG_NO_ARGS);
592 extern hash_t index_cc PROTO((CostCentre cc));
594 extern hash_t max_mod_no; /* Hash on CC module */
595 extern CostCentre *index_mod_table;
596 extern hash_t init_index_mod(STG_NO_ARGS);
597 extern hash_t index_mod PROTO((CostCentre cc));
599 extern hash_t max_grp_no; /* Hash on CC group */
600 extern CostCentre *index_grp_table;
601 extern hash_t init_index_grp(STG_NO_ARGS);
602 extern hash_t index_grp PROTO((CostCentre cc));
604 extern hash_t max_descr_no; /* Hash on closure description */
605 extern ClCategory *index_descr_table;
606 extern hash_t init_index_descr(STG_NO_ARGS);
607 extern hash_t index_descr PROTO((ClCategory clcat));
609 extern hash_t max_type_no; /* Hash on type description */
610 extern ClCategory *index_type_table;
611 extern hash_t init_index_type(STG_NO_ARGS);
612 extern hash_t index_type PROTO((ClCategory clcat));
614 # endif /* PROFILING */
618 %************************************************************************
620 \subsection[metering]{Metering of Statistics}
622 %************************************************************************
624 @scc_count@ is incremented by the @SetCC@ macro in section
625 \ref{manipulating-cost-centres} above. Below we have the time tick and
629 # define CC_TICK(centre) \
630 do { CostCentre cc = (CostCentre) (centre); \
631 ASSERT_IS_REGISTERED(cc,1); \
632 cc->time_ticks += 1; \
635 # if defined(PROFILING)
636 # define CC_ALLOC(centre, size, kind) \
637 do { CostCentre cc = (CostCentre) (centre); \
638 ASSERT_IS_REGISTERED(cc,0/*OK if OVERHEAD*/); \
639 CCC_DETAIL_COUNT(cc->mem_allocs); \
640 cc->mem_alloc += (size) - (PROF_FIXED_HDR + TICKY_FIXED_HDR); \
646 %************************************************************************
648 \subsection[cost-centre-profiling]{Cost Centre Profiling}
650 %************************************************************************
653 I_ init_cc_profiling PROTO((I_ rts_argc, char *rts_argv[], char *prog_argv[]));
654 void report_cc_profiling PROTO((I_ final));
656 void cc_register(STG_NO_ARGS);
657 void cc_sort PROTO((CostCentre *sort, char sort_on));
658 rtsBool cc_to_ignore PROTO((CostCentre));
661 %************************************************************************
663 \subsection[heap-profiling]{Heap Profiling}
665 %************************************************************************
668 # if defined(PROFILING)
670 I_ heap_profile_init PROTO((char *argv[]));
672 void heap_profile_finish(STG_NO_ARGS);
674 void heap_profile_setup(STG_NO_ARGS); /* called at start of heap profile */
675 void heap_profile_done(STG_NO_ARGS); /* called at end of heap profile */
677 void (* heap_profile_fn) PROTO((P_ closure,I_ size));
679 extern I_ earlier_ticks; /* no. of earlier ticks grouped */
680 extern hash_t time_intervals; /* no. of time intervals reported -- 18 */
682 # define HEAP_PROFILE_CLOSURE(closure,size) \
684 if (heap_profile_fn) { \
685 STGCALL2(void,(void *, P_, I_),(*heap_profile_fn),closure,size); \
688 # endif /* PROFILING */
691 End multi-slurp protection:
693 #endif /* PROFILING || PAR */
695 #endif /* CostCentre_H */