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