1 /* -----------------------------------------------------------------------------
2 * $Id: Stats.c,v 1.2 1998/12/02 13:28:49 simonm Exp $
4 * Statistics and timing-related functions.
6 * ---------------------------------------------------------------------------*/
8 #define NON_POSIX_SOURCE
15 * Ian: For the moment we just want to ignore
19 #ifdef HAVE_SYS_TIMES_H
20 #undef HAVE_SYS_TIMES_H /* <sys/times.h> */
22 #ifdef HAVE_SYS_RESOURCE_H /* <sys/resource.h> */
23 #undef HAVE_SYS_RESOURCE_H
25 #ifdef HAVE_SYS_TIME_H /* <sys/time.h> */
26 #undef HAVE_SYS_TIME_H
28 #ifdef HAVE_SYS_TIMEB_H
29 #undef HAVE_SYS_TIMEB_H /* <sys/timeb.h> */
32 #undef HAVE_UNISTD_H /* <unistd.h> */
46 #endif /* _NEMESIS_OS_ */
54 #ifdef HAVE_SYS_TIMES_H
55 #include <sys/times.h>
58 #ifdef HAVE_SYS_TIME_H
62 #if defined(HAVE_SYS_RESOURCE_H) && ! irix_TARGET_OS
63 #include <sys/resource.h>
66 #ifdef HAVE_SYS_TIMEB_H
67 #include <sys/timeb.h>
75 #define BIG_STRING_LEN 512
77 static StgDouble ElapsedTimeStart = 0.0;
78 static StgDouble TicksPerSecond = 0.0;
80 static StgDouble InitUserTime = 0.0;
81 static StgDouble InitElapsedTime = 0.0;
83 static ullong GC_tot_alloc = 0;
85 static StgDouble GC_start_time, GC_tot_time = 0; /* User GC Time */
86 static StgDouble GCe_start_time, GCe_tot_time = 0; /* Elapsed GC time */
88 static StgDouble GC_min_time = 0;
89 static StgDouble GCe_min_time = 0;
90 static lnat GC_maj_no = 0;
91 static lnat GC_min_no = 0;
92 static lnat GC_min_since_maj = 0;
93 static lnat GC_live_maj = 0; /* Heap live at last major collection */
94 static lnat GC_alloc_since_maj = 0; /* Heap alloc since collection major */
96 lnat MaxResidency = 0; /* in words; for stats only */
97 lnat ResidencySamples = 0; /* for stats only */
99 static lnat GC_start_faults = 0, GC_end_faults = 0;
101 /* ToDo: convert this to use integers? --SDM */
103 /* elapsedtime() -- The current elapsed time in seconds */
108 #if ! (defined(HAVE_TIMES) || defined(HAVE_FTIME))
109 /* We will #ifdef around the fprintf for machines
110 we *know* are unsupported. (WDP 94/05)
112 fprintf(stderr, "NOTE: `elapsedtime' does nothing!\n");
115 #else /* not stumped */
117 /* "ftime" may be nicer, but "times" is more standard;
118 but, on a Sun, if you do not get the SysV one, you are *hosed*...
121 # if defined(HAVE_TIMES) && ! sunos4_TARGET_OS
123 clock_t r = times(&t);
125 return (((StgDouble)r)/TicksPerSecond - ElapsedTimeStart);
127 # else /* HAVE_FTIME */
131 return (fabs(t.time + 1e-3*t.millitm - ElapsedTimeStart));
133 # endif /* HAVE_FTIME */
134 #endif /* not stumped */
140 # if !defined(HAVE_GETRUSAGE) || irix_TARGET_OS
145 getrusage(RUSAGE_SELF, &t);
150 /* ToDo: use gettimeofday on systems that support it (u-sec accuracy) */
156 /* Determine TicksPerSecond ... */
158 ticks = sysconf(_SC_CLK_TCK);
160 fprintf(stderr, "stat_init: bad call to 'sysconf'!\n");
161 stg_exit(EXIT_FAILURE);
163 TicksPerSecond = (StgDouble) ticks;
165 #else /* no "sysconf"; had better guess */
167 TicksPerSecond = (StgDouble) (HZ);
169 # else /* had better guess wildly */
170 /* We will #ifdef around the fprintf for machines
171 we *know* are unsupported. (WDP 94/05)
173 fprintf(stderr, "NOTE: Guessing `TicksPerSecond = 60'!\n");
174 TicksPerSecond = 60.0;
178 ElapsedTimeStart = elapsedtime();
185 FILE *sf = RtsFlags.GcFlags.statsFile;
187 if (RtsFlags.GcFlags.giveStats) {
188 fprintf(sf, " Alloc Collect Live Resid GC GC TOT TOT Page Flts\n");
189 fprintf(sf, " bytes bytes bytes ency user elap user elap\n");
197 #if ! (defined(HAVE_GETRUSAGE) || defined(HAVE_TIMES))
198 /* We will #ifdef around the fprintf for machines
199 we *know* are unsupported. (WDP 94/05)
201 fprintf(stderr, "NOTE: `usertime' does nothing!\n");
204 #else /* not stumped */
206 # if defined(HAVE_TIMES)
210 return(((StgDouble)(t.tms_utime))/TicksPerSecond);
212 #else /* HAVE_GETRUSAGE */
215 getrusage(RUSAGE_SELF, &t);
216 return(t.ru_utime.tv_sec + 1e-6*t.ru_utime.tv_usec);
218 # endif /* HAVE_GETRUSAGE */
219 #endif /* not stumped */
225 InitUserTime = usertime();
226 InitElapsedTime = elapsedtime();
227 if (InitElapsedTime < 0.0) {
228 InitElapsedTime = 0.0;
232 /* -----------------------------------------------------------------------------
233 Called at the beginning of each GC
234 -------------------------------------------------------------------------- */
236 static nat rub_bell = 0;
241 FILE *sf = RtsFlags.GcFlags.statsFile;
243 nat bell = RtsFlags.GcFlags.ringBell;
247 fprintf(stderr, " GC ");
250 fprintf(stderr, "\007");
255 GC_start_time = usertime();
256 GCe_start_time = elapsedtime();
257 if (RtsFlags.GcFlags.giveStats) {
258 GC_start_faults = pagefaults();
263 /* -----------------------------------------------------------------------------
264 Called at the end of each GC
265 -------------------------------------------------------------------------- */
268 stat_endGC(lnat alloc, lnat collect, lnat live, char *comment)
270 FILE *sf = RtsFlags.GcFlags.statsFile;
273 StgDouble time = usertime();
274 StgDouble etime = elapsedtime();
276 if (RtsFlags.GcFlags.giveStats) {
277 nat faults = pagefaults();
279 fprintf(sf, "%8ld %7ld %7ld %5.1f%%",
280 alloc*sizeof(W_), collect*sizeof(W_), live*sizeof(W_), collect == 0 ? 0.0 : (live / (StgDouble) collect * 100));
281 fprintf(sf, " %5.2f %5.2f %7.2f %7.2f %4ld %4ld %s\n",
282 (time-GC_start_time),
283 (etime-GCe_start_time),
286 faults - GC_start_faults,
287 GC_start_faults - GC_end_faults,
290 GC_end_faults = faults;
295 GC_tot_alloc += (ullong) alloc;
296 GC_tot_time += time-GC_start_time;
297 GCe_tot_time += etime-GCe_start_time;
301 fprintf(stderr, "\b\b\b \b\b\b");
306 /* -----------------------------------------------------------------------------
307 Called at the end of execution
309 NOTE: number of allocations is not entirely accurate: it doesn't
310 take into account the few bytes at the end of the heap that
311 were left unused when the heap-check failed.
312 -------------------------------------------------------------------------- */
317 FILE *sf = RtsFlags.GcFlags.statsFile;
320 char temp[BIG_STRING_LEN];
321 StgDouble time = usertime();
322 StgDouble etime = elapsedtime();
323 StgDouble MutTime, MutElapsedTime;
325 /* avoid divide by zero if time is measured as 0.00 seconds -- SDM */
326 if (time == 0.0) time = 0.0001;
327 if (etime == 0.0) etime = 0.0001;
330 if (RtsFlags.GcFlags.giveStats) {
331 fprintf(sf, "%8d\n\n", alloc*sizeof(W_));
335 fprintf(sf, "%8ld %7.7s %6.6s %7.7s %6.6s",
336 (GC_alloc_since_maj + alloc)*sizeof(W_), "", "", "", "");
337 fprintf(sf, " %3ld %5.2f %5.2f\n\n",
338 GC_min_since_maj, GC_min_time, GCe_min_time);
340 GC_min_no += GC_min_since_maj;
341 GC_tot_time += GC_min_time;
342 GCe_tot_time += GCe_min_time;
343 GC_tot_alloc += GC_alloc_since_maj + alloc;
344 ullong_format_string(GC_tot_alloc*sizeof(W_), temp, rtsTrue/*commas*/);
345 fprintf(sf, "%11s bytes allocated in the heap\n", temp);
346 if ( ResidencySamples > 0 ) {
347 ullong_format_string(MaxResidency*sizeof(W_), temp, rtsTrue/*commas*/);
348 fprintf(sf, "%11s bytes maximum residency (%.1f%%, %ld sample(s))\n",
350 MaxResidency / (StgDouble) RtsFlags.GcFlags.maxHeapSize * 100,
353 fprintf(sf, "%11ld garbage collections performed (%ld major, %ld minor)\n\n",
354 GC_maj_no + GC_min_no, GC_maj_no, GC_min_no);
356 MutTime = time - GC_tot_time - InitUserTime;
357 if (MutTime < 0) { MutTime = 0; }
358 MutElapsedTime = etime - GCe_tot_time - InitElapsedTime;
359 if (MutElapsedTime < 0) { MutElapsedTime = 0; } /* sometimes -0.00 */
361 fprintf(sf, " INIT time %6.2fs (%6.2fs elapsed)\n",
362 InitUserTime, InitElapsedTime);
363 fprintf(sf, " MUT time %6.2fs (%6.2fs elapsed)\n",
364 MutTime, MutElapsedTime);
365 fprintf(sf, " GC time %6.2fs (%6.2fs elapsed)\n",
366 GC_tot_time, GCe_tot_time);
367 fprintf(sf, " Total time %6.2fs (%6.2fs elapsed)\n\n",
370 fprintf(sf, " %%GC time %5.1f%% (%.1f%% elapsed)\n\n",
371 GC_tot_time*100./time, GCe_tot_time*100./etime);
373 if (time - GC_tot_time == 0.0)
374 ullong_format_string(0, temp, rtsTrue/*commas*/);
376 ullong_format_string((ullong)(GC_tot_alloc*sizeof(W_)/
377 (time - GC_tot_time)),
378 temp, rtsTrue/*commas*/);
380 fprintf(sf, " Alloc rate %s bytes per MUT second\n\n", temp);
382 fprintf(sf, " Productivity %5.1f%% of total user, %.1f%% of total elapsed\n\n",
383 (time - GC_tot_time - InitUserTime) * 100. / time,
384 (time - GC_tot_time - InitUserTime) * 100. / etime);