[project @ 1996-01-08 20:28:12 by partain]
[ghc-hetmet.git] / ghc / runtime / profiling / LifeProfile.lc
1 \section[LifeProfile.lc]{Code for Lifetime Profiling}
2
3 \tr{life_profile} is the accumulated age at death profile. It is
4 calculated from the difference of the prev and cur age profiles.
5
6 \tr{update_profile} is the accumulated age at update profile.
7
8 \begin{code}
9 #include "rtsdefs.h"
10 \end{code}
11
12 Only have lifetime profiling if @LIFE_PROFILE@ defined
13
14 \begin{code}
15 #if defined(LIFE_PROFILE)
16 \end{code}
17
18 Note: Heap Lookahead may cause age increment when no alloc occurs !
19
20 Could avoid it and assume space is available. If a closure was then
21 allocated it may be given a younger age. Subsequent Heap Check would
22 increment age.
23
24 \begin{code}
25 I_ do_life_prof = 0;     /* Global Flag */
26 I_ CurrentTime  = 0;     /* Current time  (in LifeIntervals) */
27 I_ LifeInterval = DEFAULT_LIFE_INTERVAL;    /* words alloced */
28
29 W_ closures_updated = 0;
30 W_ closures_alloced = 0;
31
32 static W_ words_allocated = 0;
33
34 static StgChar* prog;
35 static I_ over_alloc = 0;
36 static I_ progress = 999;
37 \end{code}
38
39
40 \tr{cur_age_profile} is a histogram of live words of each age.
41
42 \tr{prev_age_profile} is a histogram of the live words at the last
43 profile expressed in the ages they wold be at the current profile.
44 When the current is copied into the previous it must be shifted along.
45 \tr{prev_age_profile[0]} is always 0!
46
47 \begin{code}
48 static I_ intervals; /* No of active intervals -- report to 10Mb */
49
50 static W_ cur_age_profile[INTERVALS];
51 static W_ cur_older = 0;
52 static W_ prev_age_profile[INTERVALS];
53 static W_ prev_older = 0;
54
55 static W_ life_profile[INTERVALS];
56 static W_ life_older = 0;
57 static W_ update_profile[INTERVALS];
58 static W_ update_older = 0;
59 \end{code}
60
61 \begin{code}
62 I_
63 life_profile_init(rts_argv, prog_argv)
64     StgChar *rts_argv[];
65     StgChar *prog_argv[];
66 {
67     I_ i;
68
69     if (! do_life_prof)
70         return 0;
71
72     prog = prog_argv[0];
73
74     /* report up to 10Mb (2.5 Mwords) */
75     intervals = 2500000 / LifeInterval;
76     if (intervals > INTERVALS) 
77         intervals = INTERVALS;
78
79     for (i = 0; i < intervals; i++) {
80         cur_age_profile[i] = 0;
81         prev_age_profile[i] = 0;
82         life_profile[i] = 0;
83         update_profile[i] = 0;
84     }
85
86     return 0;
87 }
88
89 void life_profile_setup(STG_NO_ARGS)
90 {
91     return;
92 }
93
94 I_
95 life_profile_done(alloc, reqsize)
96     I_ alloc;
97     I_ reqsize;
98 {
99     I_ i, actual_alloc, slop, shift_prev_age;
100
101     life_profile[0] += cur_age_profile[0];     /* age 0 still alive */
102
103     for (i = 1; i < intervals; i++) {
104         life_profile[i] += prev_age_profile[i] - cur_age_profile[i];
105         prev_age_profile[i] = cur_age_profile[i-1];
106         cur_age_profile[i-1] = 0;
107     }
108     life_older += prev_older - cur_older;
109     prev_older = cur_age_profile[intervals-1] + cur_older;
110     cur_age_profile[intervals-1] = 0;
111     cur_older = 0;
112
113     CurrentTime++;
114
115     words_allocated += alloc;
116
117     actual_alloc = words_allocated - closures_alloced;
118     slop = CurrentTime * LifeInterval - actual_alloc;
119
120     shift_prev_age = 0;
121     while (slop < 0) {
122         /* over allocated due to large reqsize */
123         CurrentTime++;
124         slop += LifeInterval;
125         over_alloc++;
126         shift_prev_age++;
127     }
128     if (shift_prev_age) {
129         /* shift prev age profile as we have skipped profiles */
130         for (i = intervals - 1; i >= intervals - shift_prev_age; i--) {
131             prev_older += prev_age_profile[i];
132         }           
133         for (i = intervals - 1; i >= shift_prev_age; i--) {
134             prev_age_profile[i] = prev_age_profile[i-shift_prev_age];
135         }
136         for (i = shift_prev_age - 1; i >= 0; i--) {
137             prev_age_profile[i] = 0;
138         }
139     }
140
141     if (++progress == 1000 || do_life_prof > 1) {
142         fprintf(stderr, "%s: intervals %ld interval %ld alloc %ld slop %ld req %ld (over %ld)\n",
143                 prog, CurrentTime, LifeInterval, actual_alloc, slop, reqsize, over_alloc);
144         progress = 0;
145     }
146
147     if (slop + LifeInterval < reqsize) {
148         return(reqsize);
149     } else {
150         return(slop + LifeInterval);
151     }
152 }
153
154 void
155 life_profile_finish(alloc, prog_argv)
156     I_ alloc;
157     StgChar *prog_argv[];
158 {
159     I_ report, i;
160     StgChar life_filename[32];
161     FILE *life_file;
162     W_ total_life, total_upd, total_interval,
163             accum_life, accum_upd;
164
165     if (! do_life_prof)
166         return;
167
168     total_interval = words_allocated + alloc - closures_alloced;
169
170     /* convert age 0 still alive to age 0 died */
171     life_profile[0] = closures_alloced - life_profile[0];
172
173     /* All the prev stuff just died ! */
174     for (i = 1; i < intervals; i++) {
175         life_profile[i] += prev_age_profile[i];
176     }
177     life_older += prev_older;
178
179     /* Produce liftime reports */
180     sprintf(life_filename, "%0.24s.life", prog_argv[0]);
181     if ( (life_file = fopen(life_filename,"w")) == NULL ) {
182         fprintf(stderr, "Can't open life profile report file %s\n", life_filename);
183     }
184     else {
185         for(i = 0, total_life = total_upd = 0; i < intervals; i++) {
186             total_life += life_profile[i];
187             total_upd  += update_profile[i];
188         }
189         total_life += life_older;
190         total_upd  += update_older;
191         
192         if (total_life != closures_alloced) {
193             fprintf(stderr, "Warning: Life Profile: %1lu closures in profile, %1lu allocated\n",
194                     total_life, closures_alloced);
195         }
196         if (total_upd != closures_updated) {
197             fprintf(stderr, "Warning: Update Age Profile: %1lu closures in profile, %1lu updated\n",
198                     total_upd, closures_updated);
199         }
200         
201         fprintf(life_file, "\tClosure Lifetime Profile  (%s)\n", time_str());
202         fprintf(life_file, "\n\t  ");
203         for(i = 0; prog_argv[i]; i++)
204             fprintf(life_file, " %s", prog_argv[i]);
205         fprintf(life_file, "\n\n\ttotal closures alloced: %lu\n",
206                 closures_alloced);
207         fprintf(life_file, "\ttotal closures updated: %lu\n",
208                 closures_updated);
209         fprintf(life_file, "\ttotal bytes alloced:    %lu\n",
210                 total_interval*sizeof(W_));
211         fprintf(life_file, "\n  age (allocation)       liftime      age when updated\n");
212         fprintf(life_file, "     bytes  %%total  %%closures   No    %%updates    No\n");
213
214         accum_life = 0;
215         accum_upd = 0;
216
217         report = 0;
218         while (report < intervals) {
219             I_ life = 0;
220             I_ upd  = 0;
221
222             i = report;
223             report += GROUPED;
224
225             while(i < report) {
226                 life += life_profile[i];
227                 upd  += update_profile[i];
228                 i++;
229             }
230
231             accum_life += life;
232             accum_upd += upd;
233
234             fprintf(life_file, "  %8ld %7.3f   %6.2f%9lu   %6.2f%9lu\n",
235                     (report)*LifeInterval*sizeof(W_),
236                     (report)*LifeInterval/(StgFloat)total_interval*100,
237                     accum_life/(StgFloat)closures_alloced*100,
238                     life,
239                     accum_upd/(StgFloat)closures_updated*100,
240                     upd);
241         }
242
243         fprintf(life_file, "     older           %6.2f%9lu   %6.2f%9lu\n\n",
244                 life_older/(StgFloat)closures_alloced*100,
245                 life_older,
246                 update_older/(StgFloat)closures_updated*100,
247                 update_older);
248
249         fprintf(life_file, "Raw Data:   lifetime   update\n");
250         for(i = 0; i < intervals; i++) {
251             fprintf(life_file, "  %8ld %9lu %9lu\n",
252                     (i+1)*LifeInterval*sizeof(W_), life_profile[i], update_profile[i]);
253         }
254
255         fclose(life_file);
256     }
257     return;
258 }
259
260
261 void
262 life_profile_closure(closure, size)
263     P_ closure;
264     I_ size;
265 {
266     I_ age;
267
268     age = CurrentTime - AGE_HDR(closure);
269     if (age < intervals)
270         cur_age_profile[age] += 1;
271     else
272         cur_older += 1;
273     return;
274 }
275
276 extern void update_profile_closure(closure)
277     P_ closure;
278 {
279     I_ age;
280     
281     if (! do_life_prof)
282         return;
283
284     age = CurrentTime - AGE_HDR(closure);
285     if (age < intervals)
286         update_profile[age] += 1;
287     else
288         update_older += 1;
289     closures_updated++;
290     return;
291 }
292
293 \end{code}
294
295
296 \begin{code}
297 #endif /* LIFE_PROFILE */
298 \end{code}
299