1 \section[LifeProfile.lc]{Code for Lifetime Profiling}
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.
6 \tr{update_profile} is the accumulated age at update profile.
12 Only have lifetime profiling if @LIFE_PROFILE@ defined
15 #if defined(LIFE_PROFILE)
18 Note: Heap Lookahead may cause age increment when no alloc occurs !
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
25 I_ do_life_prof = 0; /* Global Flag */
26 I_ CurrentTime = 0; /* Current time (in LifeIntervals) */
27 I_ LifeInterval = DEFAULT_LIFE_INTERVAL; /* words alloced */
29 W_ closures_updated = 0;
30 W_ closures_alloced = 0;
32 static W_ words_allocated = 0;
35 static I_ over_alloc = 0;
36 static I_ progress = 999;
40 \tr{cur_age_profile} is a histogram of live words of each age.
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!
48 static I_ intervals; /* No of active intervals -- report to 10Mb */
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;
55 static W_ life_profile[INTERVALS];
56 static W_ life_older = 0;
57 static W_ update_profile[INTERVALS];
58 static W_ update_older = 0;
63 life_profile_init(rts_argv, prog_argv)
74 /* report up to 10Mb (2.5 Mwords) */
75 intervals = 2500000 / LifeInterval;
76 if (intervals > INTERVALS)
77 intervals = INTERVALS;
79 for (i = 0; i < intervals; i++) {
80 cur_age_profile[i] = 0;
81 prev_age_profile[i] = 0;
83 update_profile[i] = 0;
89 void life_profile_setup(STG_NO_ARGS)
95 life_profile_done(alloc, reqsize)
99 I_ i, actual_alloc, slop, shift_prev_age;
101 life_profile[0] += cur_age_profile[0]; /* age 0 still alive */
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;
108 life_older += prev_older - cur_older;
109 prev_older = cur_age_profile[intervals-1] + cur_older;
110 cur_age_profile[intervals-1] = 0;
115 words_allocated += alloc;
117 actual_alloc = words_allocated - closures_alloced;
118 slop = CurrentTime * LifeInterval - actual_alloc;
122 /* over allocated due to large reqsize */
124 slop += LifeInterval;
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];
133 for (i = intervals - 1; i >= shift_prev_age; i--) {
134 prev_age_profile[i] = prev_age_profile[i-shift_prev_age];
136 for (i = shift_prev_age - 1; i >= 0; i--) {
137 prev_age_profile[i] = 0;
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);
147 if (slop + LifeInterval < reqsize) {
150 return(slop + LifeInterval);
155 life_profile_finish(alloc, prog_argv)
157 StgChar *prog_argv[];
160 StgChar life_filename[32];
162 W_ total_life, total_upd, total_interval,
163 accum_life, accum_upd;
168 total_interval = words_allocated + alloc - closures_alloced;
170 /* convert age 0 still alive to age 0 died */
171 life_profile[0] = closures_alloced - life_profile[0];
173 /* All the prev stuff just died ! */
174 for (i = 1; i < intervals; i++) {
175 life_profile[i] += prev_age_profile[i];
177 life_older += prev_older;
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);
185 for(i = 0, total_life = total_upd = 0; i < intervals; i++) {
186 total_life += life_profile[i];
187 total_upd += update_profile[i];
189 total_life += life_older;
190 total_upd += update_older;
192 if (total_life != closures_alloced) {
193 fprintf(stderr, "Warning: Life Profile: %1lu closures in profile, %1lu allocated\n",
194 total_life, closures_alloced);
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);
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",
207 fprintf(life_file, "\ttotal closures updated: %lu\n",
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");
218 while (report < intervals) {
226 life += life_profile[i];
227 upd += update_profile[i];
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,
239 accum_upd/(StgFloat)closures_updated*100,
243 fprintf(life_file, " older %6.2f%9lu %6.2f%9lu\n\n",
244 life_older/(StgFloat)closures_alloced*100,
246 update_older/(StgFloat)closures_updated*100,
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]);
262 life_profile_closure(closure, size)
268 age = CurrentTime - AGE_HDR(closure);
270 cur_age_profile[age] += 1;
276 extern void update_profile_closure(closure)
284 age = CurrentTime - AGE_HDR(closure);
286 update_profile[age] += 1;
297 #endif /* LIFE_PROFILE */