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