1/* stats.c - malloc statistics */
2
3/*  Copyright (C) 2001-2003 Free Software Foundation, Inc.
4
5    This program is free software; you can redistribute it and/or modify
6    it under the terms of the GNU General Public License as published by
7    the Free Software Foundation; either version 2, or (at your option)
8    any later version.
9
10    This program is distributed in the hope that it will be useful,
11    but WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13    GNU General Public License for more details.
14
15    You should have received a copy of the GNU General Public License
16    along with this program; if not, write to the Free Software
17    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111 USA. */
18
19#ifdef HAVE_CONFIG_H
20#  include <config.h>
21#endif
22
23#include "imalloc.h"
24
25#ifdef MALLOC_STATS
26
27#include <stdio.h>
28#ifdef HAVE_UNISTD_H
29#  include <unistd.h>
30#endif
31#include <string.h>
32
33#include "mstats.h"
34
35extern int malloc_free_blocks __P((int));
36
37extern struct _malstats _mstats;
38
39extern FILE *_imalloc_fopen __P((char *, char *, char *, char *, size_t));
40
41struct bucket_stats
42malloc_bucket_stats (size)
43     int size;
44{
45  struct bucket_stats v;
46
47  v.nfree = 0;
48
49  if (size < 0 || size >= NBUCKETS)
50    {
51      v.blocksize = 0;
52      v.nused = v.nmal = v.nmorecore = v.nlesscore = v.nsplit = 0;
53      return v;
54    }
55
56  v.blocksize = 1 << (size + 3);
57  v.nused = _mstats.nmalloc[size];
58  v.nmal = _mstats.tmalloc[size];
59  v.nmorecore = _mstats.nmorecore[size];
60  v.nlesscore = _mstats.nlesscore[size];
61  v.nsplit = _mstats.nsplit[size];
62  v.ncoalesce = _mstats.ncoalesce[size];
63
64  v.nfree = malloc_free_blocks (size);	/* call back to malloc.c */
65
66  return v;
67}
68
69/* Return a copy of _MSTATS, with two additional fields filled in:
70   BYTESFREE is the total number of bytes on free lists.  BYTESUSED
71   is the total number of bytes in use.  These two fields are fairly
72   expensive to compute, so we do it only when asked to. */
73struct _malstats
74malloc_stats ()
75{
76  struct _malstats result;
77  struct bucket_stats v;
78  register int i;
79
80  result = _mstats;
81  result.bytesused = result.bytesfree = 0;
82  for (i = 0; i < NBUCKETS; i++)
83    {
84      v = malloc_bucket_stats (i);
85      result.bytesfree += v.nfree * v.blocksize;
86      result.bytesused += v.nused * v.blocksize;
87    }
88  return (result);
89}
90
91static void
92_print_malloc_stats (s, fp)
93     char *s;
94     FILE *fp;
95{
96  register int i;
97  unsigned long totused, totfree;
98  struct bucket_stats v;
99
100  fprintf (fp, "Memory allocation statistics: %s\n    size\tfree\tin use\ttotal\tmorecore lesscore split\tcoalesce\n", s ? s : "");
101  for (i = totused = totfree = 0; i < NBUCKETS; i++)
102    {
103      v = malloc_bucket_stats (i);
104      if (v.nmal > 0)
105	fprintf (fp, "%8lu\t%4d\t%6d\t%5d\t%8d\t%d %5d %8d\n", (unsigned long)v.blocksize, v.nfree, v.nused, v.nmal, v.nmorecore, v.nlesscore, v.nsplit, v.ncoalesce);
106      totfree += v.nfree * v.blocksize;
107      totused += v.nused * v.blocksize;
108    }
109  fprintf (fp, "\nTotal bytes in use: %lu, total bytes free: %lu\n",
110	   totused, totfree);
111  fprintf (fp, "\nTotal bytes requested by application: %lu\n", _mstats.bytesreq);
112  fprintf (fp, "Total mallocs: %d, total frees: %d, total reallocs: %d (%d copies)\n",
113	   _mstats.nmal, _mstats.nfre, _mstats.nrealloc, _mstats.nrcopy);
114  fprintf (fp, "Total sbrks: %d, total bytes via sbrk: %d\n",
115  	   _mstats.nsbrk, _mstats.tsbrk);
116  fprintf (fp, "Total blocks split: %d, total block coalesces: %d\n",
117  	   _mstats.tbsplit, _mstats.tbcoalesce);
118}
119
120void
121print_malloc_stats (s)
122     char *s;
123{
124  _print_malloc_stats (s, stderr);
125}
126
127void
128fprint_malloc_stats (s, fp)
129     char *s;
130     FILE *fp;
131{
132  _print_malloc_stats (s, fp);
133}
134
135#define TRACEROOT "/var/tmp/maltrace/stats."
136
137void
138trace_malloc_stats (s, fn)
139     char *s, *fn;
140{
141  FILE *fp;
142  char defname[sizeof (TRACEROOT) + 64];
143  static char mallbuf[1024];
144
145  fp = _imalloc_fopen (s, fn, TRACEROOT, defname, sizeof (defname));
146  if (fp)
147    {
148      setvbuf (fp, mallbuf, _IOFBF, sizeof (mallbuf));
149      _print_malloc_stats (s, fp);
150      fflush(fp);
151      fclose(fp);
152    }
153}
154
155#endif /* MALLOC_STATS */
156
157#if defined (MALLOC_STATS) || defined (MALLOC_TRACE)
158FILE *
159_imalloc_fopen (s, fn, def, defbuf, defsiz)
160     char *s;
161     char *fn;
162     char *def;
163     char *defbuf;
164     size_t defsiz;
165{
166  char fname[1024];
167  long l;
168  FILE *fp;
169
170  l = (long)getpid ();
171  if (fn == 0)
172    {
173      sprintf (defbuf, "%s%ld", def, l);
174      fp = fopen(defbuf, "w");
175    }
176  else
177    {
178      char *p, *q, *r;
179      char pidbuf[32];
180      int sp;
181
182      sprintf (pidbuf, "%ld", l);
183      if ((strlen (pidbuf) + strlen (fn) + 2) >= sizeof (fname))
184	return;
185      for (sp = 0, p = fname, q = fn; *q; )
186	{
187	  if (sp == 0 && *q == '%' && q[1] == 'p')
188	    {
189	      sp = 1;
190	      for (r = pidbuf; *r; )
191		*p++ = *r++;
192	      q += 2;
193	    }
194	  else
195	    *p++ = *q++;
196	}
197      *p = '\0';
198      fp = fopen (fname, "w");
199    }
200
201  return fp;
202}
203#endif /* MALLOC_STATS || MALLOC_TRACE */
204