[project @ 1996-01-10 12:38:57 by partain]
[ghc-hetmet.git] / ghc / includes / RednCounts.lh
1 %
2 % (c) The GRASP/AQUA Project, Glasgow University, 1992-1995
3 %
4 %************************************************************************
5 %*                                                                      *
6 \section[RednCounts.lh]{Interface (and macros) for reduction-count statistics}
7 %*                                                                      *
8 %************************************************************************
9
10 Multi-slurp protection:
11 \begin{code}
12 #ifndef REDNCOUNTS_H
13 #define REDNCOUNTS_H
14 \end{code}
15
16 There are macros in here for:
17 \begin{enumerate}
18 \item
19 ``SPAT-profiling'' (\tr{DO_SPAT_PROFILING}), counting instructions
20 per ``activity,'' using the SPAT instruction-trace analysis tools.
21 \item
22 ``Ticky-ticky profiling'' (\tr{DO_REDN_COUNTING}), counting the
23 number of various STG-events (updates, enters, etc.)
24
25 This file goes with \tr{RednCounts.lc}, which initialises the counters
26 and does the printing [ticky-ticky only].
27
28 %************************************************************************
29 %*                                                                      *
30 \subsection[SPAT-macros]{Macros for SPAT instruction counting}
31 %*                                                                      *
32 %************************************************************************
33
34 These definitions are for instruction tracing, e.g. using SPAT on the
35 SPARC.
36
37 \begin{code}
38 #ifdef DO_SPAT_PROFILING
39
40 #define ACT_BASE                0x000000ab /* random; to fit in 13 bits */
41
42 #define ACT_UNKNOWN             (0+ACT_BASE)
43 #define ACT_GC                  (1+ACT_BASE)
44 #define ACT_REDN                (2+ACT_BASE)
45 #define ACT_ASTK_STUB           (3+ACT_BASE)
46 #define ACT_FILL_IN_HEAP        (4+ACT_BASE)
47 #define ACT_HEAP_CHK            (5+ACT_BASE)
48 #define ACT_RETURN              (6+ACT_BASE)
49 #define ACT_UPDATE              (7+ACT_BASE)
50 #define ACT_PUSH_UPDF           (8+ACT_BASE)
51 #define ACT_ARGS_CHK            (9+ACT_BASE)
52 #define ACT_UPDATE_PAP          (10+ACT_BASE)
53 #define ACT_INDIRECT            (11+ACT_BASE)
54 #define ACT_PRIM                (12+ACT_BASE)
55
56 #define ACT_OVERHEAD            (14+ACT_BASE) /* only used in analyser */
57 #define ACT_TAILCALL            (15+ACT_BASE)
58         /* Note: quite a lot gets lumped under TAILCALL; the analyser
59            untangles it with other info. WDP 95/01
60         */
61
62 #define ACTIVITIES              16
63
64 #define ACT_GC_STOP             (ACTIVITIES+1)
65 #define ACT_PRIM_STOP           (ACTIVITIES+2)
66
67 /* values that "signal" the start/stop of something,
68    thus suggesting to the analyser that it stop/start something.
69
70    I do not think they are used (WDP 95/01)
71 */
72
73 #define ACT_SIGNAL_BASE         0xbababa00 /* pretty random; yes */
74
75 #define ACT_START_GOING         (1+ACT_SIGNAL_BASE)
76 #define ACT_STOP_GOING          (2+ACT_SIGNAL_BASE)
77 #define ACT_START_GC            (3+ACT_SIGNAL_BASE)
78 #define ACT_STOP_GC             (4+ACT_SIGNAL_BASE)
79
80 #define SET_ACTIVITY(act)       do { /* ActivityReg = (act) */          \
81                                 __asm__ volatile ("or %%g0,%1,%0"       \
82                                 : "=r" (ActivityReg)                    \
83                                 : "I" (act));                           \
84                                 } while(0)
85
86 #define ALLOC_HEAP(n)           /* nothing */
87 #define UN_ALLOC_HEAP(n)        /* nothing */
88 #define DO_ASTK_HWM()           /* nothing */
89 #define DO_BSTK_HWM()           /* nothing */
90
91 #define A_STK_STUB(n)           /* nothing */
92 #define A_STK_REUSE(n)          /* not used at all */
93 #define B_STK_REUSE(n)          /* ditto */
94
95 #define ALLOC_FUN(a,g,s,t)      SET_ACTIVITY(ACT_FILL_IN_HEAP)
96 #define ALLOC_THK(a,g,s,t)      SET_ACTIVITY(ACT_FILL_IN_HEAP)
97 #define ALLOC_CON(a,g,s,t)      SET_ACTIVITY(ACT_FILL_IN_HEAP)
98 #define ALLOC_TUP(a,g,s,t)      SET_ACTIVITY(ACT_FILL_IN_HEAP)
99 #define ALLOC_BH(a,g,s,t)       SET_ACTIVITY(ACT_FILL_IN_HEAP)
100 /*#define ALLOC_PAP(a,g,s,t)    SET_ACTIVITY(ACT_FILL_IN_HEAP)*/
101 #define ALLOC_UPD_PAP(a,g,s,t)  SET_ACTIVITY(ACT_UPDATE_PAP) /* NB */
102 /*#define ALLOC_UPD_CON(a,g,s,t) SET_ACTIVITY(ACT_FILL_IN_HEAP) */
103 #define ALLOC_PRIM(a,g,s,t)     SET_ACTIVITY(ACT_FILL_IN_HEAP)
104 #define ALLOC_PRIM2(w)          SET_ACTIVITY(ACT_FILL_IN_HEAP)
105 #define ALLOC_STK(a,g,s)        SET_ACTIVITY(ACT_FILL_IN_HEAP)
106 #define ALLOC_TSO(a,g,s)        SET_ACTIVITY(ACT_FILL_IN_HEAP)
107 #define ALLOC_FMBQ(a,g,s)       SET_ACTIVITY(ACT_FILL_IN_HEAP)
108 #define ALLOC_FME(a,g,s)        SET_ACTIVITY(ACT_FILL_IN_HEAP)
109 #define ALLOC_BF(a,g,s)         SET_ACTIVITY(ACT_FILL_IN_HEAP)
110
111 /* we only use the ENT_ macros to be sure activity is set to "reduction" */
112 #define ENT_VIA_NODE()          /* nothing */
113 #define ENT_THK()               SET_ACTIVITY(ACT_REDN)
114 #define ENT_FUN_STD()           SET_ACTIVITY(ACT_REDN)
115 #define ENT_FUN_DIRECT(f,f_str,f_arity,Aargs,Bargs,arg_kinds,wrap,wrap_kinds) \
116                                 SET_ACTIVITY(ACT_REDN)
117 #define ENT_CON(n)              SET_ACTIVITY(ACT_REDN)
118 #define ENT_IND(n)              SET_ACTIVITY(ACT_REDN)
119 #define ENT_PAP(n)              SET_ACTIVITY(ACT_UPDATE_PAP) /* NB */
120
121 #define RET_NEW_IN_HEAP()       SET_ACTIVITY(ACT_RETURN)
122 #define RET_NEW_IN_REGS()       SET_ACTIVITY(ACT_RETURN)
123 #define RET_OLD_IN_HEAP()       SET_ACTIVITY(ACT_RETURN)
124 #define RET_OLD_IN_REGS()       SET_ACTIVITY(ACT_RETURN)
125 #define RET_SEMI_BY_DEFAULT()   SET_ACTIVITY(ACT_RETURN)
126 #define RET_SEMI_IN_HEAP()      SET_ACTIVITY(ACT_RETURN)
127 #define RET_SEMI_IN_REGS()      SET_ACTIVITY(ACT_RETURN)
128 #define VEC_RETURN()            /* nothing */
129
130 #define UPDF_OMITTED()          /* nothing (set directly by PUSH_STD_UPD_FRAME) */
131 #define UPDF_STD_PUSHED()       SET_ACTIVITY(ACT_PUSH_UPDF)
132 #define UPDF_CON_PUSHED()       /* nothing */
133 #define UPDF_HOLE_PUSHED()      /* nothing */
134 #define UPDF_RCC_PUSHED()       /* nothing */
135 #define UPDF_RCC_OMITTED()      /* nothing */
136
137 #define UPD_EXISTING()          /* nothing -- used in .lc code */
138 #define UPD_CON_W_NODE()        SET_ACTIVITY(ACT_UPDATE)
139 #define UPD_CON_IN_PLACE()      SET_ACTIVITY(ACT_UPDATE)
140 #define UPD_PAP_IN_PLACE()      /* nothing -- UpdatePAP has its own activity */
141 #define UPD_CON_IN_NEW()        SET_ACTIVITY(ACT_UPDATE)
142 #define UPD_PAP_IN_NEW()        /* nothing -- UpdatePAP has its own activity */
143 \end{code}
144
145 For special subsequent enter counting:
146 \begin{code}
147 #define UPDATED_SET_UPDATED(n)   /* nothing */
148 #define ENTERED_CHECK_UPDATED(n) /* nothing */
149 \end{code}
150
151 For a generational collector:
152 \begin{code}
153 #define UPD_NEW_IND()                   /* nothing (set elsewhere [?]) */
154 #define UPD_NEW_IN_PLACE_PTRS()         /* nothing */
155 #define UPD_NEW_IN_PLACE_NOPTRS()       /* nothing */
156 #define UPD_OLD_IND()                   /* nothing */
157 #define UPD_OLD_IN_PLACE_PTRS()         /* nothing */
158 #define UPD_OLD_IN_PLACE_NOPTRS()       /* nothing */
159
160 #endif /* DO_SPAT_PROFILING */
161 \end{code}
162
163 %************************************************************************
164 %*                                                                      *
165 \subsection[ticky-ticky-macros]{Stuff for ``ticky-ticky'' profiling}
166 %*                                                                      *
167 %************************************************************************
168
169 \begin{code}
170 #ifdef DO_REDN_COUNTING
171
172 #define SET_ACTIVITY(act)       /* quickly: make this do NOTHING */
173 \end{code}
174
175 Measure what proportion of ...:
176 \begin{itemize}
177 \item
178 ... Enters are to data values, function values, thunks.
179 \item
180 ... allocations are for data values, functions values, thunks.
181 \item
182 ... updates are for data values, function values.
183 \item
184 ... updates ``fit''
185 \item
186 ... return-in-heap (dynamic)
187 \item
188 ... vectored return (dynamic)
189 \item
190 ... updates are wasted (never re-entered).
191 \item
192 ... constructor returns get away without hitting an update.
193 \end{enumerate}
194
195 %************************************************************************
196 %*                                                                      *
197 \subsubsection[ticky-stk-heap-use]{Stack and heap usage}
198 %*                                                                      *
199 %************************************************************************
200
201 Things we are interested in here:
202 \begin{itemize}
203 \item
204 How many times we do a heap check and move @Hp@; comparing this with
205 the allocations gives an indication of how many things we get per trip
206 to the well:
207 \begin{code}
208 #define ALLOC_HEAP(n)   ALLOC_HEAP_ctr++; ALLOC_HEAP_tot += (n)
209 \end{code}
210
211 If we do a ``heap lookahead,'' we haven't really allocated any
212 heap, so we need to undo the effects of an \tr{ALLOC_HEAP}:
213 \begin{code}
214 #define UN_ALLOC_HEAP(n) ALLOC_HEAP_ctr--; ALLOC_HEAP_tot -= (n)
215 \end{code}
216
217 \item
218 The stack high-water marks.  This is {\em direction-sensitive}!!
219 (A stack grows downward, B stack upwards)
220 \begin{code}
221 #ifndef CONCURRENT
222 #define DO_ASTK_HWM()   if (SpA < max_SpA) { max_SpA = SpA; }
223 #define DO_BSTK_HWM()   if (SpB > max_SpB) { max_SpB = SpB; }
224 #else
225 /* 
226  * This is not direction sensitive, because we threads people are well-behaved.
227  * However, it might be a good idea to cache the constant bits (DEP + BOT and
228  * HWM) from the STKO and TSO in more readily accessible places. -- ToDo!
229  */
230 #define DO_ASTK_HWM() {             \
231   I_ depth = STKO_ADEP(StkOReg) + AREL((I_) STKO_ASTK_BOT(StkOReg) - (I_) SpA);\
232   if (depth > TSO_AHWM(CurrentTSO)) \
233     TSO_AHWM(CurrentTSO) = depth;   \
234 }
235 #define DO_BSTK_HWM() {             \
236   I_ depth = STKO_BDEP(StkOReg) + BREL((I_) STKO_BSTK_BOT(StkOReg) - (I_) SpB);\
237   if (depth > TSO_BHWM(CurrentTSO)) \
238     TSO_BHWM(CurrentTSO) = depth;   \
239 }
240 #endif
241 \end{code}
242
243 \item
244 Re-use of stack slots, and stubbing of stack slots:
245 \begin{code}
246 #define A_STK_STUB(n)   A_STK_STUB_ctr += (n)
247 #define A_STK_REUSE(n)  A_STK_REUSE_ctr += (n) /* not used at all? */
248 #define B_STK_REUSE(n)  B_STK_REUSE_ctr += (n) /* not used at all? */
249 \end{code}
250 \end{itemize}
251
252 %************************************************************************
253 %*                                                                      *
254 \subsubsection[ticky-allocs]{Allocations}
255 %*                                                                      *
256 %************************************************************************
257
258 We count things every time we allocate something in the dynamic heap.
259 For each, we count the number of words of (1)~``admin'' (header),
260 (2)~good stuff (useful pointers and data), and (3)~``slop'' (extra
261 space, in hopes it will allow an in-place update).
262
263 The first five macros are inserted when the compiler generates code
264 to allocate something; the categories correspond to the @ClosureClass@
265 datatype (manifest functions, thunks, constructors, big tuples, and
266 partial applications).
267 \begin{code}
268 #define ALLOC_FUN(a,g,s,t) ASSERT((t) == (a)+(g)+(s)); \
269                          ALLOC_FUN_ctr++;       ALLOC_FUN_adm += (a); \
270                          ALLOC_FUN_gds += (g);  ALLOC_FUN_slp += (s); \
271                          ALLOC_HISTO(FUN,a,g,s)
272 #define ALLOC_THK(a,g,s,t) ASSERT((t) == (a)+(g)+(s)); \
273                          ALLOC_THK_ctr++;       ALLOC_THK_adm += (a); \
274                          ALLOC_THK_gds += (g);  ALLOC_THK_slp += (s); \
275                          ALLOC_HISTO(THK,a,g,s)
276 #define ALLOC_CON(a,g,s,t) ASSERT((t) == (a)+(g)+(s)); \
277                          ALLOC_CON_ctr++;       ALLOC_CON_adm += (a); \
278                          ALLOC_CON_gds += (g);  ALLOC_CON_slp += (s); \
279                          ALLOC_HISTO(CON,a,g,s)
280 #define ALLOC_TUP(a,g,s,t) ASSERT((t) == (a)+(g)+(s)); \
281                          ALLOC_TUP_ctr++;       ALLOC_TUP_adm += (a); \
282                          ALLOC_TUP_gds += (g);  ALLOC_TUP_slp += (s); \
283                          ALLOC_HISTO(TUP,a,g,s)
284 #define ALLOC_BH(a,g,s,t)  ASSERT((t) == (a)+(g)+(s)); \
285                          ALLOC_BH_ctr++;        ALLOC_BH_adm += (a); \
286                          ALLOC_BH_gds += (g);   ALLOC_BH_slp += (s); \
287                          ALLOC_HISTO(BH,a,g,s)
288 #if 0
289 #define ALLOC_PAP(a,g,s,t) ASSERT((t) == (a)+(g)+(s)); \
290                          ALLOC_PAP_ctr++;       ALLOC_PAP_adm += (a); \
291                          ALLOC_PAP_gds += (g);  ALLOC_PAP_slp += (s); \
292                          ALLOC_HISTO(PAP,a,g,s)
293 #endif
294 \end{code}
295
296 We may also allocate space when we do an update, and there isn't
297 enough space.  These macros suffice (for: updating with a partial
298 application and a constructor):
299 \begin{code}
300 #define ALLOC_UPD_PAP(a,g,s,t) ASSERT((t) == (a)+(g)+(s)); \
301                          ALLOC_UPD_PAP_ctr++;  ALLOC_UPD_PAP_adm += (a); \
302                          ALLOC_UPD_PAP_gds += (g); ALLOC_UPD_PAP_slp += (s); \
303                          ALLOC_HISTO(UPD_PAP,a,g,s)
304 #if 0
305 #define ALLOC_UPD_CON(a,g,s,t) ASSERT((t) == (a)+(g)+(s)); \
306                          ALLOC_UPD_CON_ctr++;  ALLOC_UPD_CON_adm += (a); \
307                          ALLOC_UPD_CON_gds += (g); ALLOC_UPD_CON_slp += (s); \
308                          ALLOC_HISTO(UPD_CON,a,g,s)
309 #endif /* 0 */
310 \end{code}
311
312 In the threaded world, we allocate space for the spark pool, stack objects,
313 and thread state objects.
314
315 \begin{code}
316
317 #define ALLOC_STK(a,g,s) ALLOC_STK_ctr++;       ALLOC_STK_adm += (a); \
318                          ALLOC_STK_gds += (g);  ALLOC_STK_slp += (s); \
319                          ALLOC_HISTO(STK,a,g,s)
320
321 #define ALLOC_TSO(a,g,s) ALLOC_TSO_ctr++;       ALLOC_TSO_adm += (a); \
322                          ALLOC_TSO_gds += (g);  ALLOC_TSO_slp += (s); \
323                          ALLOC_HISTO(TSO,a,g,s)
324
325 #define ALLOC_FMBQ(a,g,s) ALLOC_FMBQ_ctr++;     ALLOC_FMBQ_adm += (a); \
326                          ALLOC_FMBQ_gds += (g); ALLOC_FMBQ_slp += (s); \
327                          ALLOC_HISTO(FMBQ,a,g,s)
328
329 #define ALLOC_FME(a,g,s) ALLOC_FME_ctr++;       ALLOC_FME_adm += (a); \
330                          ALLOC_FME_gds += (g);  ALLOC_FME_slp += (s); \
331                          ALLOC_HISTO(FME,a,g,s)
332
333 #define ALLOC_BF(a,g,s)  ALLOC_BF_ctr++;        ALLOC_BF_adm += (a); \
334                          ALLOC_BF_gds += (g);   ALLOC_BF_slp += (s); \
335                          ALLOC_HISTO(BF,a,g,s)
336
337 \end{code}
338
339 The histogrammy bit is fairly straightforward; the \tr{-2} is: one for
340 0-origin C arrays; the other one because we do {\em no} one-word
341 allocations, so we would never inc that histogram slot; so we shift
342 everything over by one.
343 \begin{code}
344 #define ALLOC_HISTO(categ,a,g,s) \
345         { I_ __idx;                                              \
346           __idx = (a) + (g) + (s) - 2;                           \
347          CAT3(ALLOC_,categ,_hst)[((__idx > 4) ? 4 : __idx)] += 1;} 
348 \end{code}
349
350 Some hard-to-account-for words are allocated by/for primitives,
351 includes Integer support.  @ALLOC_PRIM2@ tells us about these.  We
352 count everything as ``goods'', which is not strictly correct.
353 (@ALLOC_PRIM@ is the same sort of stuff, but we know the
354 admin/goods/slop breakdown.)
355 \begin{code}
356 #define ALLOC_PRIM(a,g,s,t) ASSERT((t) == (a)+(g)+(s)); \
357                           ALLOC_PRIM_ctr++;      ALLOC_PRIM_adm += (a); \
358                           ALLOC_PRIM_gds += (g); ALLOC_PRIM_slp += (s); \
359                           ALLOC_HISTO(PRIM,a,g,s)
360 #define ALLOC_PRIM2(w) ALLOC_PRIM_ctr++; ALLOC_PRIM_gds +=(w); \
361                        ALLOC_HISTO(PRIM,0,w,0)
362 \end{code}
363
364 %************************************************************************
365 %*                                                                      *
366 \subsubsection[ticky-enters]{Enters}
367 %*                                                                      *
368 %************************************************************************
369
370 \begin{code}
371 #define ENT_VIA_NODE()  ENT_VIA_NODE_ctr++      /* via ENT_ macro */
372
373 #define ENT_THK()       ENT_THK_ctr++
374 #define ENT_FUN_STD()   ENT_FUN_STD_ctr++       /* manifest fun; std entry pt */
375
376 #define ENT_CON(n)      ENTERED_CHECK_UPDATED(n); ENT_CON_ctr++  /* enter code for constructor */
377 #define ENT_IND(n)      ENTERED_CHECK_UPDATED(n); ENT_IND_ctr++  /* enter indirection */
378 #define ENT_PAP(n)      ENTERED_CHECK_UPDATED(n); ENT_PAP_ctr++  /* enter partial application */
379 \end{code}
380
381 We do more magical things with @ENT_FUN_DIRECT@.  Besides simply knowing
382 how many ``fast-entry-point'' enters there were, we'd like {\em simple}
383 information about where those enters were, and the properties thereof.
384 \begin{code}
385 struct ent_counter {
386     unsigned    registeredp:16, /* 0 == no, 1 == yes */
387                 arity:16,       /* arity (static info) */
388                 Astk_args:16,   /* # of args off A stack */
389                 Bstk_args:16;   /* # of args off B stack */
390                                 /* (rest of args are in registers) */
391     StgChar     *f_str;         /* name of the thing */
392     StgChar     *f_arg_kinds;   /* info about the args types */
393     StgChar     *wrap_str;      /* name of its wrapper (if any) */
394     StgChar     *wrap_arg_kinds;/* info about the orig wrapper's arg types */
395     I_          ctr;            /* the actual counter */
396     struct ent_counter *link;   /* link to chain them all together */
397 };
398
399 /* OLD: extern void RegisterEntryPt PROTO((struct ent_counter *)); */
400 extern struct ent_counter *ListOfEntryCtrs;
401
402 #define ENT_FUN_DIRECT(f_ct,f_str,f_arity,Aargs,Bargs,arg_kinds,wrap,wrap_kinds) \
403         static struct ent_counter f_ct                          \
404           = { 0,                                                \
405               (f_arity), (Aargs), (Bargs), (f_str), (arg_kinds),\
406               (wrap), (wrap_kinds),                             \
407               0, NULL };                                        \
408         if ( ! f_ct.registeredp ) {                             \
409             /* hook this one onto the front of the list */      \
410             f_ct.link = ListOfEntryCtrs;                        \
411             ListOfEntryCtrs = & (f_ct);                         \
412                                                                 \
413             /* mark it as "registered" */                       \
414             f_ct.registeredp = 1;                               \
415         }                                                       \
416         f_ct.ctr += 1;                                          \
417         ENT_FUN_DIRECT_ctr++ /* the old boring one */
418 \end{code}
419
420 %************************************************************************
421 %*                                                                      *
422 \subsubsection[ticky-returns]{Returns}
423 %*                                                                      *
424 %************************************************************************
425
426 Whenever a ``return'' occurs, it is returning the constituent parts of
427 a data constructor.  The parts can be returned either in registers, or
428 by allocating some heap to put it in (the @ALLOC_*@ macros account for
429 the allocation).  The constructor can either be an existing one
430 (\tr{*OLD*}) or we could have {\em just} figured out this stuff
431 (\tr{*NEW*}).
432
433 Here's some special magic that Simon wants [edited to match names
434 actually used]:
435 \begin{display}
436 From: Simon L Peyton Jones <simonpj>
437 To: partain, simonpj
438 Subject: counting updates
439 Date: Wed, 25 Mar 92 08:39:48 +0000
440
441 I'd like to count how many times we update in place when actually Node
442 points to the thing.  Here's how:
443
444 \tr{RET_OLD_IN_REGS} sets the variable \tr{ReturnInRegsNodeValid} to \tr{True};
445 \tr{RET_NEW_IN_REGS} sets it to \tr{False}.
446
447 \tr{RET_SEMI_???} sets it to??? ToDo [WDP]
448
449 \tr{UPD_CON_IN_PLACE} tests the variable, and increments \tr{UPD_IN_PLACE_COPY_ctr}
450 if it is true.
451
452 Then we need to report it along with the update-in-place info.
453 \end{display}
454
455 \begin{code}
456 #define RET_NEW_IN_HEAP()       RET_NEW_IN_HEAP_ctr++
457 #define RET_OLD_IN_HEAP()       RET_OLD_IN_HEAP_ctr++
458
459 #define RET_NEW_IN_REGS()       RET_NEW_IN_REGS_ctr++; \
460                                 ReturnInRegsNodeValid = 0
461 #define RET_OLD_IN_REGS()       RET_OLD_IN_REGS_ctr++; \
462                                 ReturnInRegsNodeValid = 1
463
464 #define RET_SEMI_BY_DEFAULT()   RET_SEMI_BY_DEFAULT_ctr++
465 #define RET_SEMI_IN_HEAP()      RET_SEMI_IN_HEAP_ctr++
466 #define RET_SEMI_IN_REGS()      RET_SEMI_IN_REGS_ctr++
467 \end{code}
468
469 Of all the returns (sum of four categories above), how many were
470 vectored?  (The rest were obviously unvectored).
471 \begin{code}
472 #define VEC_RETURN()            VEC_RETURN_ctr++
473 \end{code}
474
475 %************************************************************************
476 %*                                                                      *
477 \subsubsection[ticky-update-frames]{Update frames}
478 %*                                                                      *
479 %************************************************************************
480
481 These macros count up the following update information.
482
483 %partain:\begin{center}
484 \begin{tabular}{ll} \hline
485 Macro                   &       Counts                                  \\ \hline
486                         &                                               \\
487 \tr{UPDF_STD_PUSHED}    &       Update frame pushed                     \\
488 \tr{UPDF_CON_PUSHED}    &       Constructor update frame pushed         \\
489 \tr{UPDF_HOLE_PUSHED}   &       An update frame to update a black hole  \\
490 \tr{UPDF_OMITTED}       &       A thunk decided not to push an update frame \\
491                         &       (all subsets of \tr{ENT_THK})           \\
492 \tr{UPDF_RCC_PUSHED}    &       Cost Centre restore frame pushed        \\
493 \tr{UPDF_RCC_OMITTED}   &       Cost Centres not required -- not pushed \\\hline
494 \end{tabular}
495 %partain:\end{center}
496
497 \begin{code}
498 #define UPDF_OMITTED()          UPDF_OMITTED_ctr++
499
500 #define UPDF_STD_PUSHED()       UPDF_STD_PUSHED_ctr++
501 #define UPDF_CON_PUSHED()       UPDF_CON_PUSHED_ctr++
502 #define UPDF_HOLE_PUSHED()      UPDF_HOLE_PUSHED_ctr++
503
504 #define UPDF_RCC_PUSHED()       UPDF_RCC_PUSHED_ctr++
505 #define UPDF_RCC_OMITTED()      UPDF_RCC_OMITTED_ctr++
506 \end{code}
507
508 %************************************************************************
509 %*                                                                      *
510 \subsubsection[ticky-updates]{Updates}
511 %*                                                                      *
512 %************************************************************************
513
514 These macros record information when we do an update.  We always
515 update either with a data constructor (CON) or a partial application
516 (PAP).
517
518 %partain:\begin{center}
519 \begin{tabular}{|l|l|}\hline
520 Macro                   &       Where                                           \\ \hline
521                         &                                                       \\
522 \tr{UPD_EXISTING}       &       Updating with an indirection to something       \\
523                         &       already in the heap                             \\
524
525 \tr{UPD_CON_W_NODE}     &       Updating with a CON: by indirecting to Node     \\
526
527 \tr{UPD_CON_IN_PLACE}   &       Ditto, but in place                             \\
528 \tr{UPD_CON_IN_NEW}     &       Ditto, but allocating the object                \\
529
530 \tr{UPD_PAP_IN_PLACE}   &       Same, but updating w/ a PAP                     \\
531 \tr{UPD_PAP_IN_NEW}     &                                                       \\\hline
532 \end{tabular}
533 %partain:\end{center}
534
535 \begin{code}
536 #define UPD_EXISTING()          UPD_EXISTING_ctr++
537
538 #define UPD_CON_W_NODE()        UPD_CON_W_NODE_ctr++
539
540 #define UPD_CON_IN_NEW()        UPD_CON_IN_NEW_ctr++
541 #define UPD_PAP_IN_NEW()        UPD_PAP_IN_NEW_ctr++
542 /* ToDo: UPD_NEW_COPY_ctr, as below */
543
544 #define UPD_CON_IN_PLACE()      UPD_CON_IN_PLACE_ctr++ ; \
545                                 UPD_IN_PLACE_COPY_ctr += ReturnInRegsNodeValid
546                                 /* increments if True; otherwise, no */
547 #define UPD_PAP_IN_PLACE()      UPD_PAP_IN_PLACE_ctr++ ; \
548                                 UPD_IN_PLACE_COPY_ctr += ReturnInRegsNodeValid
549                                 /* increments if True; otherwise, no */
550 \end{code}
551
552 For a generational collector:
553 \begin{code}
554 #define UPD_NEW_IND()                   UPD_NEW_IND_ctr++;
555 #define UPD_NEW_IN_PLACE_PTRS()         UPD_NEW_IN_PLACE_PTRS_ctr++;
556 #define UPD_NEW_IN_PLACE_NOPTRS()       UPD_NEW_IN_PLACE_NOPTRS_ctr++;
557 #define UPD_OLD_IND()                   UPD_OLD_IND_ctr++;                      
558 #define UPD_OLD_IN_PLACE_PTRS()         UPD_OLD_IN_PLACE_PTRS_ctr++;
559 #define UPD_OLD_IN_PLACE_NOPTRS()       UPD_OLD_IN_PLACE_NOPTRS_ctr++;
560 \end{code}
561
562 %************************************************************************
563 %*                                                                      *
564 \subsubsection[ticky-updates-entered]{Updates Subsequently Entered}
565 %*                                                                      *
566 %************************************************************************
567
568 If @UPDATES_ENTERED_COUNT@ is defined we add the Age word to the
569 closures.  This is used to record indicate if a closure has been
570 updated but not yet entered. It is set when the closure is updated and
571 cleared when subsequently entered.
572
573 The commoning up of @CONST@, @CHARLIKE@ and @INTLIKE@ closures is
574 turned if this is required. This has only been done for 2s collection.
575 It is done using a nasty hack which defines the @_Evacuate@ and
576 @_Scavenge@ code for @CONST@, @CHARLIKE@ and @INTLIKE@ info tables to
577 be @_Evacuate_1@ and @_Scavenge_1_0@.
578
579 Unfortunately this broke everything so it has not been done ;-(.
580 Instead we have to run with enough heap so no garbage collection is
581 needed for accurate numbers. ToDo: Fix this!
582
583 As implemented it can not be used in conjunction with heap profiling
584 or lifetime profiling becasue they make conflicting use the Age word!
585
586 \begin{code}
587 #if defined(UPDATES_ENTERED_COUNT)
588
589 #define UPDATED_SET_UPDATED(n)  AGE_HDR(n) = 1
590
591 #define ENTERED_CHECK_UPDATED(n)        \
592         if (AGE_HDR(n)) {               \
593             if (AGE_HDR(n) == 1) {      \
594                 UPD_ENTERED_ctr++;      \
595                 AGE_HDR(n) += 1;        \
596             } else {                    \
597                 UPD_ENTERED_AGAIN_ctr++; \
598                 AGE_HDR(n) = 0;         \
599         }}
600
601 #else  /* ! UPDATES_ENTERED_COUNT */
602
603 #define UPDATED_SET_UPDATED(n)   /* nothing */
604 #define ENTERED_CHECK_UPDATED(n) /* nothing */
605
606 #endif /* ! UPDATES_ENTERED_COUNT */
607 \end{code}
608
609 %************************************************************************
610 %*                                                                      *
611 \subsubsection[ticky-counters]{The accumulators (extern decls)}
612 %*                                                                      *
613 %************************************************************************
614
615 \begin{code}
616 extern I_ ALLOC_HEAP_ctr;
617 extern I_ ALLOC_HEAP_tot;
618
619 extern PP_ max_SpA;
620 extern P_  max_SpB;
621
622 extern I_ A_STK_STUB_ctr;
623 /* not used at all?
624 extern I_ A_STK_REUSE_ctr;
625 extern I_ B_STK_REUSE_ctr;
626 */
627
628 extern I_ ALLOC_FUN_ctr;
629 extern I_ ALLOC_FUN_adm;
630 extern I_ ALLOC_FUN_gds;
631 extern I_ ALLOC_FUN_slp;
632 extern I_ ALLOC_FUN_hst[5];
633 extern I_ ALLOC_THK_ctr;
634 extern I_ ALLOC_THK_adm;
635 extern I_ ALLOC_THK_gds;
636 extern I_ ALLOC_THK_slp;
637 extern I_ ALLOC_THK_hst[5];
638 extern I_ ALLOC_CON_ctr;
639 extern I_ ALLOC_CON_adm;
640 extern I_ ALLOC_CON_gds;
641 extern I_ ALLOC_CON_slp;
642 extern I_ ALLOC_CON_hst[5];
643 extern I_ ALLOC_TUP_ctr;
644 extern I_ ALLOC_TUP_adm;
645 extern I_ ALLOC_TUP_gds;
646 extern I_ ALLOC_TUP_slp;
647 extern I_ ALLOC_TUP_hst[5];
648 extern I_ ALLOC_BH_ctr;
649 extern I_ ALLOC_BH_adm;
650 extern I_ ALLOC_BH_gds;
651 extern I_ ALLOC_BH_slp;
652 extern I_ ALLOC_BH_hst[5];
653 /*
654 extern I_ ALLOC_PAP_ctr;
655 extern I_ ALLOC_PAP_adm;
656 extern I_ ALLOC_PAP_gds;
657 extern I_ ALLOC_PAP_slp;
658 extern I_ ALLOC_PAP_hst[5];
659 */
660 /*
661 extern I_ ALLOC_UPD_CON_ctr;
662 extern I_ ALLOC_UPD_CON_adm;
663 extern I_ ALLOC_UPD_CON_gds;
664 extern I_ ALLOC_UPD_CON_slp;
665 extern I_ ALLOC_UPD_CON_hst[5];
666 */
667 extern I_ ALLOC_UPD_PAP_ctr;
668 extern I_ ALLOC_UPD_PAP_adm;
669 extern I_ ALLOC_UPD_PAP_gds;
670 extern I_ ALLOC_UPD_PAP_slp;
671 extern I_ ALLOC_UPD_PAP_hst[5];
672 extern I_ ALLOC_PRIM_ctr;
673 extern I_ ALLOC_PRIM_adm;
674 extern I_ ALLOC_PRIM_gds;
675 extern I_ ALLOC_PRIM_slp;
676 extern I_ ALLOC_PRIM_hst[5];
677
678 #ifdef CONCURRENT
679 extern I_ ALLOC_STK_ctr;
680 extern I_ ALLOC_STK_adm;
681 extern I_ ALLOC_STK_gds;
682 extern I_ ALLOC_STK_slp;
683 extern I_ ALLOC_STK_hst[5];
684 extern I_ ALLOC_TSO_ctr;
685 extern I_ ALLOC_TSO_adm;
686 extern I_ ALLOC_TSO_gds;
687 extern I_ ALLOC_TSO_slp;
688 extern I_ ALLOC_TSO_hst[5];
689 #ifdef PAR
690 extern I_ ALLOC_FMBQ_ctr;
691 extern I_ ALLOC_FMBQ_adm;
692 extern I_ ALLOC_FMBQ_gds;
693 extern I_ ALLOC_FMBQ_slp;
694 extern I_ ALLOC_FMBQ_hst[5];
695 extern I_ ALLOC_FME_ctr;
696 extern I_ ALLOC_FME_adm;
697 extern I_ ALLOC_FME_gds;
698 extern I_ ALLOC_FME_slp;
699 extern I_ ALLOC_FME_hst[5];
700 extern I_ ALLOC_BF_ctr;
701 extern I_ ALLOC_BF_adm;
702 extern I_ ALLOC_BF_gds;
703 extern I_ ALLOC_BF_slp;
704 extern I_ ALLOC_BF_hst[5];
705 #endif
706 #endif
707
708 extern I_ ENT_VIA_NODE_ctr;
709
710 extern I_ ENT_CON_ctr;
711 extern I_ ENT_FUN_STD_ctr;
712 extern I_ ENT_FUN_DIRECT_ctr;
713 extern I_ ENT_IND_ctr;
714 extern I_ ENT_PAP_ctr;
715 extern I_ ENT_THK_ctr;
716
717 extern I_ UPD_ENTERED_ctr;
718 extern I_ UPD_ENTERED_AGAIN_ctr;
719
720 extern I_ RET_NEW_IN_HEAP_ctr;
721 extern I_ RET_NEW_IN_REGS_ctr;
722 extern I_ RET_OLD_IN_HEAP_ctr;
723 extern I_ RET_OLD_IN_REGS_ctr;
724 extern I_ RET_SEMI_BY_DEFAULT_ctr;
725 extern I_ RET_SEMI_IN_HEAP_ctr;
726 extern I_ RET_SEMI_IN_REGS_ctr;
727 extern I_ VEC_RETURN_ctr;
728
729 extern I_ ReturnInRegsNodeValid; /* see below */
730
731 extern I_ UPDF_OMITTED_ctr;
732 extern I_ UPDF_STD_PUSHED_ctr;
733 extern I_ UPDF_CON_PUSHED_ctr;
734 extern I_ UPDF_HOLE_PUSHED_ctr;
735
736 extern I_ UPDF_RCC_PUSHED_ctr;
737 extern I_ UPDF_RCC_OMITTED_ctr;
738
739 extern I_ UPD_EXISTING_ctr;
740 extern I_ UPD_CON_W_NODE_ctr;
741 extern I_ UPD_CON_IN_PLACE_ctr;
742 extern I_ UPD_PAP_IN_PLACE_ctr;
743 extern I_ UPD_CON_IN_NEW_ctr;
744 extern I_ UPD_PAP_IN_NEW_ctr;
745
746 extern I_ UPD_NEW_IND_ctr;
747 extern I_ UPD_NEW_IN_PLACE_PTRS_ctr;
748 extern I_ UPD_NEW_IN_PLACE_NOPTRS_ctr;
749 extern I_ UPD_OLD_IND_ctr;
750 extern I_ UPD_OLD_IN_PLACE_PTRS_ctr;
751 extern I_ UPD_OLD_IN_PLACE_NOPTRS_ctr;
752
753 extern I_ UPD_IN_PLACE_COPY_ctr; /* see below */
754
755 #endif /* DO_REDN_COUNTING */
756 \end{code}
757
758 %************************************************************************
759 %*                                                                      *
760 \subsection[RednCounts-nonmacros]{Un-macros for ``none of the above''}
761 %*                                                                      *
762 %************************************************************************
763
764 \begin{code}
765 #if ! (defined(DO_SPAT_PROFILING) || defined(DO_REDN_COUNTING))
766
767 #define SET_ACTIVITY(act) /* nothing */
768
769 #define ALLOC_HEAP(n)    /* nothing */
770 #define UN_ALLOC_HEAP(n) /* nothing */
771 #define DO_ASTK_HWM()    /* nothing */
772 #define DO_BSTK_HWM()    /* nothing */
773
774 #define A_STK_STUB(n)   /* nothing */
775 #define A_STK_REUSE(n)  /* not used at all */
776 #define B_STK_REUSE(n)  /* not used at all */
777
778 #define ALLOC_FUN(a,g,s,t) /* nothing */
779 #define ALLOC_THK(a,g,s,t) /* nothing */
780 #define ALLOC_CON(a,g,s,t) /* nothing */
781 #define ALLOC_TUP(a,g,s,t) /* nothing */
782 #define ALLOC_BH(a,g,s,t)  /* nothing */
783 /*#define ALLOC_PAP(a,g,s,t) /? nothing */
784 #define ALLOC_PRIM(a,g,s,t) /* nothing */
785 #define ALLOC_PRIM2(w)   /* nothing */
786 #define ALLOC_UPD_PAP(a,g,s,t) /* nothing */
787 /*#define ALLOC_UPD_CON(a,g,s,t) /? nothing */
788 #define ALLOC_STK(a,g,s) /* nothing */
789 #define ALLOC_TSO(a,g,s) /* nothing */
790 #define ALLOC_FMBQ(a,g,s) /* nothing */
791 #define ALLOC_FME(a,g,s) /* nothing */
792 #define ALLOC_BF(a,g,s) /* nothing */
793
794 #define ENT_VIA_NODE()  /* nothing */
795 #define ENT_THK()       /* nothing */
796 #define ENT_FUN_STD()   /* nothing */
797 #define ENT_FUN_DIRECT(f,f_str,f_arity,Aargs,Bargs,arg_kinds,wrap,wrap_kinds) \
798                         /* nothing */ 
799 #define ENT_CON(n)      /* nothing */
800 #define ENT_IND(n)      /* nothing */
801 #define ENT_PAP(n)      /* nothing */
802
803 #define RET_NEW_IN_HEAP()       /* nothing */
804 #define RET_NEW_IN_REGS()       /* nothing */
805 #define RET_OLD_IN_HEAP()       /* nothing */
806 #define RET_OLD_IN_REGS()       /* nothing */
807 #define RET_SEMI_BY_DEFAULT()   /* nothing */
808 #define RET_SEMI_IN_HEAP()      /* nothing */
809 #define RET_SEMI_IN_REGS()      /* nothing */
810 #define VEC_RETURN()            /* nothing */
811
812 #define UPDF_OMITTED()          /* nothing */
813 #define UPDF_STD_PUSHED()       /* nothing */
814 #define UPDF_CON_PUSHED()       /* nothing */
815 #define UPDF_HOLE_PUSHED()      /* nothing */
816
817 #define UPDF_RCC_PUSHED()       /* nothing */
818 #define UPDF_RCC_OMITTED()      /* nothing */
819
820 #define UPD_EXISTING()          /* nothing */
821 #define UPD_CON_W_NODE()        /* nothing */
822 #define UPD_CON_IN_PLACE()      /* nothing */
823 #define UPD_PAP_IN_PLACE()      /* nothing */
824 #define UPD_CON_IN_NEW()        /* nothing */
825 #define UPD_PAP_IN_NEW()        /* nothing */
826 \end{code}
827
828 For special subsequent enter counting:
829 \begin{code}
830 #define UPDATED_SET_UPDATED(n)   /* nothing */
831 #define ENTERED_CHECK_UPDATED(n) /* nothing */
832 \end{code}
833
834 For a generational collector:
835 \begin{code}
836 #define UPD_NEW_IND()                   /* nothing */
837 #define UPD_NEW_IN_PLACE_PTRS()         /* nothing */
838 #define UPD_NEW_IN_PLACE_NOPTRS()       /* nothing */
839 #define UPD_OLD_IND()                   /* nothing */
840 #define UPD_OLD_IN_PLACE_PTRS()         /* nothing */
841 #define UPD_OLD_IN_PLACE_NOPTRS()       /* nothing */
842
843 #endif /* <none-of-the-above> */
844 \end{code}
845
846 End of file multi-slurp protection:
847 \begin{code}
848 #endif /* ! REDNCOUNTS_H */
849 \end{code}