1 *********************************************************************
3 Stuff for printing out GC statistics
5 usertime() -- The current user time in seconds
6 elapsedtime() -- The current elapsed time in seconds
13 *********************************************************************
17 #define _INCLUDE_HPUX_SOURCE
21 #include "SMinternal.h"
22 #include "RednCounts.h"
24 #ifdef HAVE_SYS_TYPES_H
25 #include <sys/types.h>
32 #ifdef HAVE_SYS_TIMES_H
33 #include <sys/times.h>
36 #ifdef HAVE_SYS_TIME_H
40 #if defined(HAVE_SYS_RESOURCE_H) && ! irix_TARGET_OS
41 #include <sys/resource.h>
44 #ifdef HAVE_SYS_TIMEB_H
45 #include <sys/timeb.h>
49 #include <sys/syscall.h>
50 #define getrusage(a, b) syscall(SYS_GETRUSAGE, a, b)
51 #define HAVE_GETRUSAGE
54 static StgDouble GC_start_time, GC_tot_time = 0; /* User GC Time */
55 static StgDouble GCe_start_time, GCe_tot_time = 0; /* Elapsed GC time */
57 #if defined(GCap) || defined(GCgn)
58 static StgDouble GC_min_time = 0;
59 static StgDouble GCe_min_time = 0;
61 static I_ GC_min_no = 0;
62 static I_ GC_min_since_maj = 0;
63 static I_ GC_live_maj = 0; /* Heap live at last major collection */
64 static I_ GC_alloc_since_maj = 0; /* Heap alloc since collection major */
67 static I_ GC_maj_no = 0;
68 static ullong GC_tot_alloc = 0; /* Total heap allocated -- 64 bits? */
70 static I_ GC_start_faults = 0, GC_end_faults = 0;
74 ullong_format_string(ullong x, char *s, rtsBool with_commas)
76 ullong_format_string(x, s, with_commas)
83 sprintf(s, "%ld", (I_)x);
84 else if (x < (ullong)1000000)
85 sprintf(s, (with_commas) ? "%ld,%3.3ld" : "%ld%3.3ld",
86 (I_)((x)/(ullong)1000),
87 (I_)((x)%(ullong)1000));
88 else if (x < (ullong)1000000000)
89 sprintf(s, (with_commas) ? "%ld,%3.3ld,%3.3ld" : "%ld%3.3ld%3.3ld",
90 (I_)((x)/(ullong)1000000),
91 (I_)((x)/(ullong)1000%(ullong)1000),
92 (I_)((x)%(ullong)1000));
94 sprintf(s, (with_commas) ? "%ld,%3.3ld,%3.3ld,%3.3ld" : "%ld%3.3ld%3.3ld%3.3ld",
95 (I_)((x)/(ullong)1000000000),
96 (I_)((x)/(ullong)1000000%(ullong)1000),
97 (I_)((x)/(ullong)1000%(ullong)1000),
98 (I_)((x)%(ullong)1000));
102 /* "constants" for "usertime" and "elapsedtime" */
104 static StgDouble ElapsedTimeStart = 0.0; /* setup when beginning things */
105 static StgDouble TicksPerSecond = 0.0; /* ditto */
107 /* usertime() -- The current user time in seconds */
112 #if ! (defined(HAVE_GETRUSAGE) || defined(HAVE_TIMES))
113 /* We will #ifdef around the fprintf for machines
114 we *know* are unsupported. (WDP 94/05)
116 fprintf(stderr, "NOTE: `usertime' does nothing!\n");
119 #else /* not stumped */
121 /* "times" is the more standard, but we prefer "getrusage"
122 (because we are old worn-out BSD hackers)
124 # if defined(HAVE_GETRUSAGE) && ! irix_TARGET_OS
127 getrusage(RUSAGE_SELF, &t);
128 return(t.ru_utime.tv_sec + 1e-6*t.ru_utime.tv_usec);
130 # else /* HAVE_TIMES */
134 return(((StgDouble)(t.tms_utime))/TicksPerSecond);
136 # endif /* HAVE_TIMES */
137 #endif /* not stumped */
141 /* elapsedtime() -- The current elapsed time in seconds */
146 #if ! (defined(HAVE_TIMES) || defined(HAVE_FTIME))
147 /* We will #ifdef around the fprintf for machines
148 we *know* are unsupported. (WDP 94/05)
150 fprintf(stderr, "NOTE: `elapsedtime' does nothing!\n");
153 #else /* not stumped */
155 /* "ftime" may be nicer, but "times" is more standard;
156 but, on a Sun, if you do not get the SysV one, you are *hosed*...
159 # if defined(HAVE_TIMES) && ! sunos4_TARGET_OS
162 return (((StgDouble) times(&t))/TicksPerSecond - ElapsedTimeStart);
164 # else /* HAVE_FTIME */
168 return t.time + 1e-3*t.millitm - ElapsedTimeStart;
170 # endif /* HAVE_FTIME */
171 #endif /* not stumped */
175 start_time(STG_NO_ARGS)
179 /* Determine TicksPerSecond ... */
181 ticks = sysconf(_SC_CLK_TCK);
183 fprintf(stderr, "stat_init: bad call to 'sysconf'!\n");
186 TicksPerSecond = (StgDouble) ticks;
188 #else /* no "sysconf"; had better guess */
190 TicksPerSecond = (StgDouble) (HZ);
192 # else /* had better guess wildly */
193 /* We will #ifdef around the fprintf for machines
194 we *know* are unsupported. (WDP 94/05)
196 fprintf(stderr, "NOTE: Guessing `TicksPerSecond = 60'!\n");
197 TicksPerSecond = 60.0;
201 ElapsedTimeStart = elapsedtime();
204 static StgDouble InitUserTime = 0.0; /* user time taken for initialization */
205 static StgDouble InitElapsedTime = 0.0; /* elapsed time taken for initialization */
207 void end_init(STG_NO_ARGS)
209 InitUserTime = usertime();
210 InitElapsedTime = elapsedtime();
214 pagefaults(STG_NO_ARGS)
216 #if !defined(HAVE_GETRUSAGE) || irix_TARGET_OS
221 getrusage(RUSAGE_SELF, &t);
226 /* Called at the beginning of execution of the program */
227 /* Writes the command line and inits stats header */
229 void stat_init(collector, comment1, comment2)
230 char *collector, *comment1, *comment2;
232 if (SM_statsfile != NULL) {
233 char temp[BIG_STRING_LEN];
234 ullong_format_string( (ullong)SM_word_heap_size*sizeof(W_), temp, rtsTrue/*commas*/);
235 fprintf(SM_statsfile, "\nCollector: %s HeapSize: %s (bytes)\n\n", collector, temp);
236 if (SM_stats_verbose) {
237 #if !defined(HAVE_GETRUSAGE) || irix_TARGET_OS
238 fprintf(SM_statsfile, "NOTE: `pagefaults' does nothing!\n");
240 fprintf(SM_statsfile,
241 /*######## ####### ####### ##.# ##.## ##.## ####.## ####.## #### ####*/
242 " Alloc Collect Live Resid GC GC TOT TOT Page Flts %s\n",
244 fprintf(SM_statsfile,
245 " bytes bytes bytes ency user elap user elap GC MUT %s\n",
249 #if defined(GCap) || defined(GCgn)
251 fprintf(SM_statsfile,
252 /*######## ####### ##.# ####### ##.# ### ##.## ##.## ##.## ##.## ####.## ####.## #### ####*/
253 " Alloc Promote Promo Live Resid Minor Minor Minor Major Major TOT TOT Page Flts\n");
254 fprintf(SM_statsfile,
255 " bytes bytes ted bytes ency No user elap user elap user elap MUT Major\n");
257 #endif /* generational */
259 fflush(SM_statsfile);
264 /* Called at the beginning of each GC */
265 static I_ rub_bell = 0;
271 #if defined(GCap) || defined(GCgn)
272 I_ bell = alloc == 0 ? SM_ring_bell : 0;
273 #else /* ! generational */
274 I_ bell = SM_ring_bell;
275 #endif /* ! generational */
279 fprintf(stderr, " GC ");
282 fprintf(stderr, "\007");
286 if (SM_statsfile != NULL) {
287 GC_start_time = usertime();
288 GCe_start_time = elapsedtime();
290 #if defined(GCap) || defined(GCgn)
291 if (SM_stats_verbose || alloc == 0) {
292 GC_start_faults = pagefaults();
294 #else /* ! generational */
295 if (SM_stats_verbose) {
296 GC_start_faults = pagefaults();
298 #endif /* ! generational */
304 /* Called at the end of each GC */
307 stat_endGC(alloc, collect, live, comment)
308 I_ alloc, collect, live;
311 if (SM_statsfile != NULL) {
312 StgDouble time = usertime();
313 StgDouble etime = elapsedtime();
315 if (SM_stats_verbose){
316 I_ faults = pagefaults();
318 fprintf(SM_statsfile, "%8ld %7ld %7ld %5.1f%%",
319 alloc*sizeof(W_), collect*sizeof(W_), live*sizeof(W_), collect == 0 ? 0.0 : (live / (StgFloat) collect * 100));
320 fprintf(SM_statsfile, " %5.2f %5.2f %7.2f %7.2f %4ld %4ld %s\n",
321 (time-GC_start_time),
322 (etime-GCe_start_time),
325 faults - GC_start_faults,
326 GC_start_faults - GC_end_faults,
329 GC_end_faults = faults;
330 fflush(SM_statsfile);
333 #if defined(GCap) || defined(GCgn)
334 else if(alloc == 0 && collect != 0) {
335 I_ faults = pagefaults();
337 fprintf(SM_statsfile, "%8ld %7ld %5.1f%% %7ld %5.1f%%",
338 GC_alloc_since_maj*sizeof(W_), (collect - GC_live_maj)*sizeof(W_),
339 (collect - GC_live_maj) / (StgFloat) GC_alloc_since_maj * 100,
340 live*sizeof(W_), live / (StgFloat) SM_word_heap_size * 100);
341 fprintf(SM_statsfile, " %3ld %5.2f %5.2f %5.2f %5.2f %7.2f %7.2f %4ld %4ld\n",
342 GC_min_since_maj, GC_min_time, GCe_min_time,
343 (time-GC_start_time),
344 (etime-GCe_start_time),
347 faults - GC_start_faults,
348 GC_start_faults - GC_end_faults
351 GC_end_faults = faults;
352 fflush(SM_statsfile);
354 #endif /* generational */
356 #if defined(GCap) || defined(GCgn)
357 if (alloc == 0 && collect != 0) {
360 GC_min_no += GC_min_since_maj;
361 GC_min_since_maj = 0;
362 GC_tot_alloc += (ullong) GC_alloc_since_maj;
363 GC_alloc_since_maj = 0;
364 GC_tot_time += time-GC_start_time + GC_min_time;
366 GCe_tot_time += etime-GCe_start_time + GCe_min_time;
370 GC_alloc_since_maj += alloc;
371 GC_min_time += time-GC_start_time;
372 GCe_min_time += etime-GCe_start_time;
374 #else /* ! generational */
376 GC_tot_alloc += (ullong) alloc;
377 GC_tot_time += time-GC_start_time;
378 GCe_tot_time += etime-GCe_start_time;
379 #endif /* ! generational */
384 fprintf(stderr, "\b\b\b \b\b\b");
390 /* Called at the end of execution -- to print a summary of statistics */
396 if (SM_statsfile != NULL){
397 char temp[BIG_STRING_LEN];
398 StgDouble time = usertime();
399 StgDouble etime = elapsedtime();
401 if (SM_stats_verbose) {
402 fprintf(SM_statsfile, "%8ld\n\n", alloc*sizeof(W_));
405 #if defined(GCap) || defined (GCgn)
407 fprintf(SM_statsfile, "%8ld %7.7s %6.6s %7.7s %6.6s",
408 (GC_alloc_since_maj + alloc)*sizeof(W_), "", "", "", "");
409 fprintf(SM_statsfile, " %3ld %5.2f %5.2f\n\n",
410 GC_min_since_maj, GC_min_time, GCe_min_time);
412 GC_min_no += GC_min_since_maj;
413 GC_tot_time += GC_min_time;
414 GCe_tot_time += GCe_min_time;
415 GC_tot_alloc += (ullong) (GC_alloc_since_maj + alloc);
416 ullong_format_string(GC_tot_alloc*sizeof(W_), temp, rtsTrue/*commas*/);
417 fprintf(SM_statsfile, "%11s bytes allocated in the heap\n", temp);
418 if ( ResidencySamples > 0 ) {
419 ullong_format_string(MaxResidency*sizeof(W_), temp, rtsTrue/*commas*/);
420 fprintf(SM_statsfile, "%11s bytes maximum residency (%.1f%%, %ld sample(s))\n",
422 MaxResidency / (StgFloat) SM_word_heap_size * 100,
425 fprintf(SM_statsfile, "%11ld garbage collections performed (%ld major, %ld minor)\n\n",
426 GC_maj_no + GC_min_no, GC_maj_no, GC_min_no);
428 #else /* ! generational */
430 GC_tot_alloc += (ullong) alloc;
431 ullong_format_string(GC_tot_alloc*sizeof(W_), temp, rtsTrue/*commas*/);
432 fprintf(SM_statsfile, "%11s bytes allocated in the heap\n", temp);
433 if ( ResidencySamples > 0 ) {
434 ullong_format_string(MaxResidency*sizeof(W_), temp, rtsTrue/*commas*/);
435 fprintf(SM_statsfile, "%11s bytes maximum residency (%.1f%%, %ld sample(s))\n",
437 MaxResidency / (StgFloat) SM_word_heap_size * 100,
440 fprintf(SM_statsfile, "%11ld garbage collections performed\n\n", GC_maj_no);
442 #endif /* ! generational */
444 fprintf(SM_statsfile, " INIT time %6.2fs (%6.2fs elapsed)\n",
445 InitUserTime, InitElapsedTime);
446 fprintf(SM_statsfile, " MUT time %6.2fs (%6.2fs elapsed)\n",
447 time - GC_tot_time - InitUserTime,
448 etime - GCe_tot_time - InitElapsedTime);
449 fprintf(SM_statsfile, " GC time %6.2fs (%6.2fs elapsed)\n",
450 GC_tot_time, GCe_tot_time);
451 fprintf(SM_statsfile, " Total time %6.2fs (%6.2fs elapsed)\n\n",
454 fprintf(SM_statsfile, " %%GC time %5.1f%% (%.1f%% elapsed)\n\n",
455 GC_tot_time*100./time, GCe_tot_time*100./etime);
457 ullong_format_string((ullong)(GC_tot_alloc*sizeof(W_)/(time - GC_tot_time)), temp, rtsTrue/*commas*/);
458 fprintf(SM_statsfile, " Alloc rate %s bytes per MUT second\n\n", temp);
460 fprintf(SM_statsfile, " Productivity %5.1f%% of total user, %.1f%% of total elapsed\n\n",
461 (time - GC_tot_time - InitUserTime) * 100. / time,
462 (time - GC_tot_time - InitUserTime) * 100. / etime);
463 fflush(SM_statsfile);
464 fclose(SM_statsfile);