1 /*
2  * ***************************************************************************
3  * MALOC = < Minimal Abstraction Layer for Object-oriented C >
4  * Copyright (C) 1994-- Michael Holst
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19  *
20  * rcsid="$Id: vmem.c,v 1.16 2010/08/12 05:40:31 fetk Exp $"
21  * ***************************************************************************
22  */
23 
24 /*
25  * ***************************************************************************
26  * File:     vmem.c
27  *
28  * Purpose:  Class Vmem: methods.
29  *
30  * Author:   Michael Holst
31  * ***************************************************************************
32  */
33 
34 #include "vmem_p.h"
35 
36 VEMBED(rcsid="$Id: vmem.c,v 1.16 2010/08/12 05:40:31 fetk Exp $")
37 
38 /* total and misc (default) malloc/free tracking */
39 VPRIVATE Vmem vmemTotal, vmemMisc;
40 VPRIVATE size_t vmemInit=0;
41 
42 /*
43  * ***************************************************************************
44  * Class Vmem: Inlineable methods
45  * ***************************************************************************
46  */
47 #if !defined(VINLINE_MALOC)
48 
49 #endif /* if !defined(VINLINE_MALOC) */
50 /*
51  * ***************************************************************************
52  * Class Vmem: Non-inlineable methods
53  * ***************************************************************************
54  */
55 
56 /*
57  * ***************************************************************************
58  * Routine:  Vmem_init
59  *
60  * Purpose:  Initialize the total log and the catch-all misc log.
61  *
62  * Author:   Michael Holst
63  * ***************************************************************************
64  */
Vmem_init(void)65 VPRIVATE void Vmem_init(void)
66 {
67     if (!vmemInit) {
68 
69         strncpy(vmemTotal.name, "TOTAL", VMAX_ARGLEN);
70         vmemTotal.mallocBytes = 0;
71         vmemTotal.freeBytes = 0;
72         vmemTotal.highWater = 0;
73         vmemTotal.mallocAreas = 0;
74 
75         strncpy(vmemMisc.name, "MISC", VMAX_ARGLEN);
76         vmemMisc.mallocBytes = 0;
77         vmemMisc.freeBytes = 0;
78         vmemMisc.highWater = 0;
79         vmemMisc.mallocAreas = 0;
80 
81         vmemInit = 1;
82     }
83 }
84 
85 /*
86  * ***************************************************************************
87  * Routine:  Vmem_bytesTotal
88  *
89  * Purpose:  Return total size of ALL currently ACTIVE malloc areas that
90  *           went through Vmem_malloc.  This is the current memory footprint.
91  *
92  * Author:   Michael Holst
93  * ***************************************************************************
94  */
Vmem_bytesTotal(void)95 VPUBLIC size_t Vmem_bytesTotal(void)
96 {
97     Vmem_init();
98     return (vmemTotal.mallocBytes - vmemTotal.freeBytes);
99 }
100 
101 /*
102  * ***************************************************************************
103  * Routine:  Vmem_mallocBytesTotal
104  *
105  * Purpose:  Return total size of ALL malloc areas that went through
106  *           Vmem_malloc (even if they have been subsequently freed).
107  *
108  * Author:   Michael Holst
109  * ***************************************************************************
110  */
Vmem_mallocBytesTotal(void)111 VPUBLIC size_t Vmem_mallocBytesTotal(void)
112 {
113     Vmem_init();
114     return vmemTotal.mallocBytes;
115 }
116 
117 /*
118  * ***************************************************************************
119  * Routine:  Vmem_freeBytesTotal
120  *
121  * Purpose:  Return total size of ALL freed malloc areas that
122  *           went through Vmem_free.
123  *
124  * Author:   Michael Holst
125  * ***************************************************************************
126  */
Vmem_freeBytesTotal(void)127 VPUBLIC size_t Vmem_freeBytesTotal(void)
128 {
129     Vmem_init();
130     return vmemTotal.freeBytes;
131 }
132 
133 /*
134  * ***************************************************************************
135  * Routine:  Vmem_highWaterTotal
136  *
137  * Purpose:  Return the high-water malloc bytemark hit by ALL active
138  *           malloc areas; this is the largest active malloc total hit at
139  *           one time by areas obtained through Vmem_malloc.
140  *
141  * Author:   Michael Holst
142  * ***************************************************************************
143  */
Vmem_highWaterTotal(void)144 VPUBLIC size_t Vmem_highWaterTotal(void)
145 {
146     Vmem_init();
147     return vmemTotal.highWater;
148 }
149 
150 /*
151  * ***************************************************************************
152  * Routine:  Vmem_mallocAreasTotal
153  *
154  * Purpose:  Return the total number of ALL individual active malloc areas.
155  *
156  * Author:   Michael Holst
157  * ***************************************************************************
158  */
Vmem_mallocAreasTotal(void)159 VPUBLIC size_t Vmem_mallocAreasTotal(void)
160 {
161     Vmem_init();
162     return vmemTotal.mallocAreas;
163 }
164 
165 /*
166  * ***************************************************************************
167  * Routine:  Vmem_printTotal
168  *
169  * Purpose:  Print current memory statistics for all malloc areas that have
170  *           gone through Vmem_malloc and Vmem_free.
171  *
172  * Author:   Michael Holst
173  * ***************************************************************************
174  */
Vmem_printTotal(void)175 VPUBLIC void Vmem_printTotal(void)
176 {
177     Vmem_init();
178     fprintf(stderr,"%12ld %12ld %12ld %12ld %12ld %% %s\n",
179         (vmemTotal.mallocBytes-vmemTotal.freeBytes),
180         vmemTotal.mallocAreas, vmemTotal.mallocBytes,
181         vmemTotal.freeBytes, vmemTotal.highWater,
182         vmemTotal.name);
183 }
184 
185 /*
186  * ***************************************************************************
187  * Routine:  Vmem_ctor
188  *
189  * Purpose:  Construct the dynamic memory allocation logging object.
190  *
191  * Author:   Michael Holst
192  * ***************************************************************************
193  */
Vmem_ctor(char * name)194 VPUBLIC Vmem *Vmem_ctor(char *name)
195 {
196     Vmem *thee;
197 
198     thee = Vmem_malloc( VNULL, 1, sizeof(Vmem) );
199     VASSERT( thee != VNULL );
200 
201     strncpy( thee->name, name, VMAX_ARGLEN );
202     thee->mallocBytes = 0;
203     thee->freeBytes = 0;
204     thee->highWater = 0;
205     thee->mallocAreas = 0;
206 
207     return thee;
208 }
209 
210 /*
211  * ***************************************************************************
212  * Routine:  Vmem_dtor
213  *
214  * Purpose:  Destruct the dynamic memory allocation logging object.
215  *
216  * Author:   Michael Holst
217  * ***************************************************************************
218  */
Vmem_dtor(Vmem ** thee)219 VPUBLIC void Vmem_dtor(Vmem **thee)
220 {
221     Vmem_free( VNULL, 1, sizeof(Vmem), (void**)thee );
222 }
223 
224 /*
225  * ***************************************************************************
226  * Routine:  Vmem_malloc
227  *
228  * Purpose:  A logged version of malloc.
229  *
230  * Author:   Michael Holst
231  * ***************************************************************************
232  */
Vmem_malloc(Vmem * thee,size_t num,size_t size)233 VPUBLIC void *Vmem_malloc(Vmem *thee, size_t num, size_t size)
234 {
235     size_t btmp;
236     void *ram = VNULL;
237 
238     Vmem_init();
239 
240     /* VWARN( (num > 0) && (size > 0) ); */
241     VASSERT( (num > 0) && (size > 0) );
242     if ( (num > 0) && (size > 0) ) {
243 
244         ram = (void*)calloc((size_t)num, (size_t)size);
245         if (ram == VNULL) {
246             fprintf(stderr, "Unable to allocate memory!\n");
247             fprintf(stderr, "(This often means you don't have enough memory available for this calculation.)\n");
248         }
249         VASSERT( ram != VNULL );
250 
251         vmemTotal.mallocBytes += (num * size);
252         btmp = (vmemTotal.mallocBytes - vmemTotal.freeBytes);
253         if ( vmemTotal.highWater < btmp ) vmemTotal.highWater = btmp;
254         vmemTotal.mallocAreas++;
255 
256         if (thee != VNULL) {
257             thee->mallocBytes += (num * size);
258             btmp = (thee->mallocBytes - thee->freeBytes);
259             if ( thee->highWater < btmp ) thee->highWater = btmp;
260             thee->mallocAreas++;
261         } else {
262             vmemMisc.mallocBytes += (num * size);
263             btmp = (vmemMisc.mallocBytes - vmemMisc.freeBytes);
264             if ( vmemMisc.highWater < btmp ) vmemMisc.highWater = btmp;
265             vmemMisc.mallocAreas++;
266         }
267 
268     }
269 
270     return ram;
271 }
272 
273 /*
274  * ***************************************************************************
275  * Routine:  Vmem_free
276  *
277  * Purpose:  A logged version of free.
278  *
279  * Author:   Michael Holst
280  * ***************************************************************************
281  */
Vmem_free(Vmem * thee,size_t num,size_t size,void ** ram)282 VPUBLIC void Vmem_free(Vmem *thee, size_t num, size_t size, void **ram)
283 {
284     Vmem_init();
285 
286     /* VWARN( (*ram) != VNULL ); */
287     VASSERT( (*ram) != VNULL );
288     if ((*ram) != VNULL) {
289 
290         free(*ram);
291         (*ram) = VNULL;
292 
293         vmemTotal.freeBytes += (num * size);
294         vmemTotal.mallocAreas--;
295 
296         if (thee != VNULL) {
297             thee->freeBytes += (num * size);
298             thee->mallocAreas--;
299         } else {
300             vmemMisc.freeBytes += (num * size);
301             vmemMisc.mallocAreas--;
302         }
303     }
304 }
305 
306 /*
307  * ***************************************************************************
308  * Routine:  Vmem_realloc
309  *
310  * Purpose:  A logged version of realloc (using this is usually a bad idea).
311  *
312  * Author:   Michael Holst
313  * ***************************************************************************
314  */
Vmem_realloc(Vmem * thee,size_t num,size_t size,void ** ram,size_t newNum)315 VPUBLIC void *Vmem_realloc(Vmem *thee, size_t num, size_t size, void **ram,
316     size_t newNum)
317 {
318     void *tee = Vmem_malloc(thee, newNum, size);
319     memcpy(tee, (*ram), size*VMIN2(num,newNum));
320     Vmem_free(thee, num, size, ram);
321     return tee;
322 }
323 
324 /*
325  * ***************************************************************************
326  * Routine:  Vmem_bytes
327  *
328  * Purpose:  Return total of ACTIVE malloc areas used by the Vmem object.
329  *           (If Vmem is VNULL, return the misc catch-all malloc total).
330  *
331  * Author:   Michael Holst
332  * ***************************************************************************
333  */
Vmem_bytes(Vmem * thee)334 VPUBLIC size_t Vmem_bytes(Vmem *thee)
335 {
336     Vmem_init();
337 
338     if (thee != VNULL) {
339         return (thee->mallocBytes - thee->freeBytes);
340     } else {
341         return (vmemMisc.mallocBytes - vmemMisc.freeBytes);
342     }
343 }
344 
345 /*
346  * ***************************************************************************
347  * Routine:  Vmem_mallocBytes
348  *
349  * Purpose:  Return total of all mallocs performed by the Vmem object.
350  *           (If Vmem is VNULL, return the misc catch-all malloc total).
351  *
352  * Author:   Michael Holst
353  * ***************************************************************************
354  */
Vmem_mallocBytes(Vmem * thee)355 VPUBLIC size_t Vmem_mallocBytes(Vmem *thee)
356 {
357     Vmem_init();
358 
359     if (thee != VNULL) {
360         return thee->mallocBytes;
361     } else {
362         return vmemMisc.mallocBytes;
363     }
364 }
365 
366 /*
367  * ***************************************************************************
368  * Routine:  Vmem_freeBytes
369  *
370  * Purpose:  Return total of the frees performed by the Vmem object.
371  *           (If Vmem is VNULL, return misc catch-all free total).
372  *
373  * Author:   Michael Holst
374  * ***************************************************************************
375  */
Vmem_freeBytes(Vmem * thee)376 VPUBLIC size_t Vmem_freeBytes(Vmem *thee)
377 {
378     Vmem_init();
379 
380     if (thee != VNULL) {
381         return thee->freeBytes;
382     } else {
383         return vmemMisc.freeBytes;
384     }
385 }
386 
387 /*
388  * ***************************************************************************
389  * Routine:  Vmem_highWater
390  *
391  * Purpose:  Return the high-water malloc bytemark hit by the Vmem object.
392  *           (If Vmem is VNULL, return misc catch-all malloc highwater).
393  *
394  * Author:   Michael Holst
395  * ***************************************************************************
396  */
Vmem_highWater(Vmem * thee)397 VPUBLIC size_t Vmem_highWater(Vmem *thee)
398 {
399     Vmem_init();
400 
401     if (thee != VNULL) {
402         return thee->highWater;
403     } else {
404         return vmemMisc.highWater;
405     }
406 }
407 
408 /*
409  * ***************************************************************************
410  * Routine:  Vmem_mallocAreas
411  *
412  * Purpose:  Return the total number of individual active malloc areas.
413  *           (If Vmem is VNULL, return misc catch-all malloc areas).
414  *
415  * Author:   Michael Holst
416  * ***************************************************************************
417  */
Vmem_mallocAreas(Vmem * thee)418 VPUBLIC size_t Vmem_mallocAreas(Vmem *thee)
419 {
420     Vmem_init();
421 
422     if (thee != VNULL) {
423         return thee->mallocAreas;
424     } else {
425         return vmemMisc.mallocAreas;
426     }
427 }
428 
429 /*
430  * ***************************************************************************
431  * Routine:  Vmem_print
432  *
433  * Purpose:  Print current memory statistics associated with this Vmem object.
434  *           (If Vmem is VNULL, print info for the catch-all ovject).
435  *
436  * Author:   Michael Holst
437  * ***************************************************************************
438  */
Vmem_print(Vmem * thee)439 VPUBLIC void Vmem_print(Vmem *thee)
440 {
441     Vmem_init();
442 
443     if (thee != VNULL) {
444         fprintf(stderr,"%12ld %12ld %12ld %12ld %12ld %% %s\n",
445             (thee->mallocBytes-thee->freeBytes),
446             thee->mallocAreas, thee->mallocBytes,
447             thee->freeBytes, thee->highWater,
448             thee->name);
449     } else {
450         fprintf(stderr,"%12ld %12ld %12ld %12ld %12ld %% %s\n",
451             (vmemMisc.mallocBytes-vmemMisc.freeBytes),
452             vmemMisc.mallocAreas, vmemMisc.mallocBytes,
453             vmemMisc.freeBytes, vmemMisc.highWater,
454             vmemMisc.name);
455     }
456 }
457 
458