/[MITgcm]/mitgcm.org/devel/buildweb/pkg/swish-e/src/mem.c
ViewVC logotype

Contents of /mitgcm.org/devel/buildweb/pkg/swish-e/src/mem.c

Parent Directory Parent Directory | Revision Log Revision Log | View Revision Graph Revision Graph


Revision 1.1.1.1 - (show annotations) (download) (vendor branch)
Fri Sep 20 19:47:29 2002 UTC (22 years, 10 months ago) by adcroft
Branch: Import, MAIN
CVS Tags: baseline, HEAD
Changes since 1.1: +0 -0 lines
File MIME type: text/plain
Importing web-site building process.

1 /*
2 $Id: mem.c,v 1.29 2002/05/31 23:10:14 whmoseley Exp $
3 **
4 ** This program and library is free software; you can redistribute it and/or
5 ** modify it under the terms of the GNU (Library) General Public License
6 ** as published by the Free Software Foundation; either version 2
7 ** of the License, or any later version.
8 **
9 ** This program is distributed in the hope that it will be useful,
10 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
11 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 ** GNU (Library) General Public License for more details.
13 **
14 ** You should have received a copy of the GNU (Library) General Public License
15 ** along with this program; if not, write to the Free Software
16 ** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
17 **
18 ** Author: Bill Meier, June 2001
19 **
20 ** To Do:
21 ** Memory statistics doesn't really require use of Mem_ routines
22 */
23
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <memory.h>
27 #include "swish.h"
28 #include "error.h"
29 #include "string.h"
30
31 #include "mem.h"
32
33 /* we can use the real ones here! */
34
35 #undef malloc
36 #undef realloc
37 #undef free
38
39
40 /* size of a longword */
41 #define longSize (sizeof(long))
42
43 /* typical machine has pagesize 4096 (not critical anyway, just can help malloc) */
44 #define pageSize (1<<12)
45
46
47 /* simple cases first ... */
48
49 #if ! (MEM_DEBUG | MEM_TRACE | MEM_STATISTICS)
50
51
52 /* emalloc - malloc a block of memory */
53 void *emalloc(size_t size)
54 {
55 void *p;
56
57 if ((p = malloc(size)) == NULL)
58 progerr("Ran out of memory (could not allocate %lu more bytes)!", size);
59
60 return p;
61 }
62
63
64 /* erealloc - realloc a block of memory */
65 void *erealloc(void *ptr, size_t size)
66 {
67 void *p;
68
69 if ((p = realloc(ptr, size)) == NULL)
70 progerr("Ran out of memory (could not reallocate %lu more bytes)!", size);
71
72 return p;
73 }
74
75
76 /* efree - free a block of memory */
77 void efree(void *ptr)
78 {
79 free(ptr);
80 }
81
82
83 /* Mem_Summary - print out a memory usage summary */
84 void Mem_Summary(char *title, int final)
85 {
86 return;
87 }
88
89
90
91 #else // (MEM_DEBUG | MEM_TRACE | MEM_STATISTICS)
92
93
94
95 /*
96 ** Now we get into the debugging/trace memory allocator. I apologize for the
97 ** conditionals in this code, but it does work :-)
98 */
99
100 /* parameters of typical allocators (just for statistics) */
101 #define MIN_CHUNK 16
102 #define CHUNK_ROUNDOFF (sizeof(long) - 1)
103
104
105 /* Random value for a GUARD at beginning and end of allocated memory */
106 #define GUARD 0x14739182
107
108 #if MEM_TRACE
109
110 size_t memory_trace_counter = 0;
111
112 typedef struct
113 {
114 char *File;
115 int Line;
116 // void *Ptr; // only needed for extra special debugging
117 size_t Size;
118 size_t Count;
119
120 } TraceBlock;
121
122
123 // mem break point: helps a little to track down unfreed memory
124 // Say if you see
125 // Unfreed: string.c line 958: Size: 11 Counter: 402
126 // you can then add above line 958: Mem_bp( 402 )
127 // and then set a breakpoint for progwarn, and backtrace to find the allocation
128
129 void Mem_bp(int n)
130 {
131 if ( n == memory_trace_counter )
132 progwarn("At counter position %d", n );
133 }
134
135 #endif
136
137
138 /* MemHeader is what is before the user allocated block - for our bookkeeping */
139 typedef struct
140 {
141 #if MEM_TRACE
142 TraceBlock *Trace;
143 #endif
144 #if MEM_DEBUG
145 unsigned long Guard1;
146 #endif
147 size_t Size;
148 #if MEM_DEBUG
149 void *Start;
150 unsigned long Guard2;
151 #endif
152 } MemHeader;
153
154
155 /* MemTail is what is after the user allocated block - for our bookkeeping */
156 #if MEM_DEBUG
157 typedef struct
158 {
159 unsigned long Guard;
160 } MemTail;
161
162
163 /* Define the extra amount of memory we need for our bookkeeping */
164 #define MEM_OVERHEAD_SIZE (sizeof(MemHeader) + sizeof(MemTail))
165 #else
166 #define MEM_OVERHEAD_SIZE (sizeof(MemHeader))
167 #endif
168
169
170 #if MEM_TRACE
171
172 #define MAX_TRACE 1000000
173
174 static TraceBlock TraceData[MAX_TRACE];
175 static TraceBlock *Free = NULL;
176 static int last;
177
178 #endif
179
180 static unsigned int MAllocCalls = 0;
181 static unsigned int MReallocCalls = 0;
182 static unsigned int MFreeCalls = 0;
183 static size_t MAllocCurrentOverhead = 0;
184 static size_t MAllocMaximumOverhead = 0;
185 static size_t MAllocCurrent = 0;
186 static size_t MAllocMaximum = 0;
187 static size_t MAllocCurrentEstimated = 0;
188 static size_t MAllocMaximumEstimated = 0;
189
190
191 #if MEM_DEBUG
192 #define MEM_ERROR(str) \
193 { \
194 printf("\nMemory free error! At %s line %d\n", file, line); \
195 printf str; \
196 fflush(stdout); \
197 }
198 #endif
199
200 #if MEM_TRACE
201
202 static TraceBlock *AllocTrace(char *file, int line, void *ptr, size_t size)
203 {
204 TraceBlock *Block;
205 int i;
206
207 if (Free)
208 {
209 Block = Free;
210 Free = NULL;
211 }
212 else
213 {
214 for (i = last; i < MAX_TRACE; i++) /** $$$ What if we run off the end? **/
215 if (TraceData[i].File == NULL)
216 break;
217
218 Block = &TraceData[i];
219 last = i + 1;
220 }
221
222 Block->File = file;
223 Block->Line = line;
224 // Block->Ptr = ptr; // only needed for extra special debugging
225 Block->Size = size;
226 Block->Count = memory_trace_counter++;
227
228 return Block;
229 }
230
231 #endif
232
233 static size_t Estimated(size_t size)
234 {
235 if (size <= MIN_CHUNK)
236 return MIN_CHUNK;
237
238 return (size + CHUNK_ROUNDOFF) & (~CHUNK_ROUNDOFF);
239 }
240
241 /* Mem_Alloc - Allocate a chunk of memory */
242
243 void * Mem_Alloc (size_t Size, char *file, int line)
244
245 /*
246 * FUNCTIONAL DESCRIPTION:
247 *
248 * This routine will allocate a chunk of memory of a specified size.
249 *
250 * FORMAL PARAMETERS:
251 *
252 * Size Size in bytes of the chunk to allocate
253 *
254 * ROUTINE VALUE:
255 *
256 * Address of allocated memory
257 *
258 * SIDE EFFECTS:
259 *
260 * Fatal error and exit if can't allocate memory
261 */
262
263 {
264
265 size_t MemSize; /* Actual size of memory to alloc */
266 unsigned char *MemPtr; /* Pointer to allocated memory */
267 MemHeader *Header; /* Header of memory */
268
269
270 /*
271 * Adjust size to account for the memory header and tail information we
272 * include. This is so we know how much we allocated to be able to free it,
273 * and also in support of memory debugging routines.
274 */
275
276 MemSize = Size + MEM_OVERHEAD_SIZE;
277
278 /*
279 * Get the memory; die if we can't...
280 */
281
282 MemPtr = (unsigned char *)malloc(MemSize);
283
284 if (MemPtr == NULL)
285 {
286 printf("At file %s line %d:\n", file, line);
287 progerr("Ran out of memory (could not allocate %lu more bytes)!", MemSize);
288 }
289
290
291 /*
292 * Keep a running total of the memory allocated for statistical purposes.
293 * Save the chunk size in the first long word of the chunk, and return the
294 * address of the chunk (following the chunk size) to the caller.
295 */
296
297 MAllocCalls++;
298 MAllocCurrentOverhead += MEM_OVERHEAD_SIZE;
299
300 if (MAllocCurrentOverhead > MAllocMaximumOverhead)
301 MAllocMaximumOverhead = MAllocCurrentOverhead;
302
303 MAllocCurrent += Size;
304 MAllocCurrentEstimated += Estimated(Size);
305
306
307 if (MAllocCurrent > MAllocMaximum)
308 MAllocMaximum = MAllocCurrent;
309
310 if (MAllocCurrentEstimated > MAllocMaximumEstimated)
311 MAllocMaximumEstimated = MAllocCurrentEstimated;
312
313 Header = (MemHeader *)MemPtr;
314 Header->Size = Size;
315 MemPtr = MemPtr + sizeof (MemHeader);
316
317 /*
318 * Add guards, and fill the memory with a pattern
319 */
320
321 #if MEM_DEBUG
322 {
323 MemTail *Tail;
324
325 Header->Start = MemPtr;
326 Header->Guard1 = GUARD;
327 Header->Guard2 = GUARD;
328 memset(MemPtr, 0xAA, Size);
329 Tail = (MemTail *)(MemPtr + Size);
330 Tail->Guard = GUARD;
331 }
332 #endif
333
334 #if MEM_TRACE
335 Header->Trace = AllocTrace(file, line, MemPtr, Size);
336 #endif
337
338 // printf("Alloc: %s line %d: Addr: %08X Size: %u\n", file, line, MemPtr, Size);
339
340 return (MemPtr);
341 }
342
343
344 /* Mem_Free - Free a chunk of memory */
345
346 void Mem_Free (void *Address, char *file, int line)
347
348 /*
349 * FUNCTIONAL DESCRIPTION:
350 *
351 * This routine will free a chunk of previously allocated memory.
352 * This memory must have been allocated via Mem_Alloc.
353 *
354 * FORMAL PARAMETERS:
355 *
356 * Address Address of the memory chunk to free
357 *
358 * ROUTINE VALUE:
359 *
360 * NONE
361 *
362 * SIDE EFFECTS:
363 *
364 * Severe error is signaled if can't free the memory
365 */
366
367 {
368
369 MemHeader *Header;
370 size_t MemSize; /* Size of chunk to free */
371 size_t UserSize;
372 void *MemPtr;
373
374 /* ANSI allows free of NULL */
375
376 if (!Address)
377 return;
378
379 /*
380 * Get the size of the chunk to free from the long word preceding the
381 * address of the chunk.
382 */
383
384 Header = (MemHeader *)Address - 1;
385
386 #if MEM_DEBUG
387 {
388 MemTail *Tail;
389
390 if ( (long)Address & (~(longSize-1)) != 0 )
391 MEM_ERROR(("Address %08X not longword aligned\n", (unsigned int)Address));
392
393 if (Address != Header->Start)
394 MEM_ERROR(("Already free: %08X\n", (unsigned int)Address));
395 // Err_Signal (PWRK$_BUGMEMFREE, 1, Address);
396
397 if (Header->Guard1 != GUARD)
398 MEM_ERROR(("Head Guard 1 overwritten: %08X\n", (unsigned int)&Header->Guard1));
399 // Err_Signal (PWRK$_BUGMEMGUARD1, 4, Address,
400 // Header->Guard1, 4, &Header->Guard1);
401
402 if (Header->Guard2 != GUARD)
403 MEM_ERROR(("Head Guard 2 overwritten: %08X\n", (unsigned int)&Header->Guard2));
404 // Err_Signal (PWRK$_BUGMEMGUARD1, 4, Address,
405 // Header->Guard2, 4, &Header->Guard2);
406
407 Tail = (MemTail *)((unsigned char *)Address + Header->Size);
408
409 if (Tail->Guard != GUARD)
410 MEM_ERROR(("Tail Guard overwritten: %08X\n", (unsigned int)&Tail->Guard));
411 // Err_Signal (PWRK$_BUGMEMGUARD2, 4, Address,
412 // Tail->Guard, 4, &Tail->Guard);
413
414 }
415 #endif
416
417
418 MFreeCalls++;
419 MemPtr = (unsigned char *)Header;
420 UserSize = Header->Size;
421 MemSize = UserSize + MEM_OVERHEAD_SIZE;
422
423 // printf("Free: %s line %d: Addr: %08X Size: %u\n", file, line, Address, UserSize);
424
425 #if MEM_TRACE
426 Free = Header->Trace;
427 // printf(" Allocated at %s line %d:\n", Free->File, Free->Line);
428 Free->File = NULL;
429 #endif
430
431 #if MEM_DEBUG
432 memset (MemPtr, 0xDD, MemSize);
433 #endif
434
435 /* Subtract chunk size from running total */
436
437 MAllocCurrent -= UserSize;
438 MAllocCurrentEstimated -= Estimated(UserSize);
439
440 MAllocCurrentOverhead -= MEM_OVERHEAD_SIZE;
441
442
443 /* Free the memory */
444
445 free(MemPtr);
446
447 }
448
449
450 /* Mem_Realloc - realloc a block of memory */
451
452 void *Mem_Realloc (void *Address, size_t Size, char *file, int line)
453 {
454 void *MemPtr;
455 MemHeader *Header;
456 size_t OldSize;
457
458 MReallocCalls++;
459 MAllocCalls--;
460 MFreeCalls--;
461
462 MemPtr = Mem_Alloc(Size, file, line);
463
464 if (Address)
465 {
466 Header = (MemHeader *)Address - 1;
467 OldSize = Header->Size;
468
469 memcpy(MemPtr, Address, (OldSize < Size ? OldSize : Size));
470
471 Mem_Free(Address, file, line);
472 }
473
474 // printf("Realloc: %s line %d: Addr: %08X Size: %u to %u\n", file, line, Address, OldSize, Size);
475
476 return MemPtr;
477 }
478
479
480 /* Mem_Summary - Give a memory usage summary */
481
482 void Mem_Summary(char *title, int final)
483 {
484
485 #if MEM_STATISTICS
486 printf("\nMemory usage summary: %s\n\n", title);
487 printf("Alloc calls: %u, Realloc calls: %u, Free calls: %u\n", MAllocCalls, MReallocCalls, MFreeCalls);
488 printf("Requested: Maximum usage: %u, Current usage: %u\n", MAllocMaximum, MAllocCurrent);
489 printf("Estimated: Maximum usage: %u, Current usage: %u\n", MAllocMaximumEstimated, MAllocCurrentEstimated);
490
491 #endif
492
493 #if MEM_TRACE
494 if (final)
495 {
496 int i;
497
498 printf("\nUnfreed memory: %s\n\n", title);
499 for (i = 0; i < MAX_TRACE; i++)
500 if (TraceData[i].File)
501 printf("Unfreed: %s line %d: Size: %d Counter: %d\n",
502 TraceData[i].File, TraceData[i].Line, TraceData[i].Size, TraceData[i].Count);
503 }
504 #endif
505
506 }
507
508 #endif
509
510
511 /*************************************************************************
512 **
513 ** Mem Zone routines -- efficient memory allocation if you don't need
514 ** realloc and free...
515 **
516 */
517
518 /* round up to a long word */
519 #define ROUND_LONG(n) (((n) + longSize - 1) & (~(longSize - 1)))
520
521 /* round up to a page */
522 #define ROUND_PAGE(n) (((n) + pageSize - 1) & (~(pageSize - 1)))
523
524
525 typedef struct _zone {
526 struct _zone *next; /* link to next chunk */
527 size_t free; /* bytes free in this chunk */
528 unsigned char *ptr; /* start of free space in this chunk */
529 void *alloc; /* ptr to malloced memory (for free) */
530 size_t size; /* size of allocation (for statistics) */
531 } ZONE;
532
533
534 /* allocate a chunk of memory from the OS */
535 static ZONE *allocChunk(size_t size)
536 {
537 ZONE *zone;
538
539 zone = emalloc(sizeof(ZONE));
540 zone->alloc = emalloc(size);
541 zone->size = size;
542 zone->ptr = zone->alloc;
543 zone->free = size;
544 zone->next = NULL;
545
546 return zone;
547 }
548
549 /* create a memory zone */
550 MEM_ZONE *Mem_ZoneCreate(char *name, size_t size, int attributes)
551 {
552 MEM_ZONE *head;
553
554 head = emalloc(sizeof(MEM_ZONE));
555 head->name = estrdup(name);
556
557 size = ROUND_PAGE(size);
558 if (size == 0)
559 size = pageSize*64;
560 head->size = size;
561
562 head->attributes = attributes;
563 head->allocs = 0;
564 head->next = NULL;
565
566 return head;
567 }
568
569 /* allocate memory from a zone (can use like malloc if you aren't going to realloc) */
570 void *Mem_ZoneAlloc(MEM_ZONE *head, size_t size)
571 {
572 ZONE *zone;
573 ZONE *newzone;
574 unsigned char *ptr;
575
576 /* statistics */
577 head->allocs++;
578
579 size = ROUND_LONG(size);
580
581 zone = head->next;
582
583 /* If not enough free in this chunk, allocate a new one. Don't worry about the
584 small amount of unused space at the end. If we are asking for a really big
585 chunk allocate a new buffer just for that!
586 */
587
588 if (!zone || (zone->free < size))
589 {
590 newzone = allocChunk(size > head->size ? size : head->size);
591 head->next = newzone;
592 newzone->next = zone;
593 zone = newzone;
594 }
595
596 /* decrement free, advance pointer, and return allocation to the user */
597 zone->free -= size;
598 ptr = zone->ptr;
599 zone->ptr += size;
600
601 return ptr;
602 }
603
604
605
606 void Mem_ZoneFree(MEM_ZONE **head)
607 {
608 ZONE *next;
609 ZONE *tmp;
610
611 if (!*head)
612 return;
613
614 #if MEM_STATISTICS
615 Mem_ZoneStatistics(*head);
616 #endif
617
618 next = (*head)->next;
619 while (next)
620 {
621 efree(next->alloc);
622 tmp = next->next;
623 efree(next);
624 next = tmp;
625 }
626
627 efree((*head)->name);
628 efree(*head);
629 *head = NULL;
630 }
631
632 #if MEM_STATISTICS
633 void Mem_ZoneStatistics(MEM_ZONE *head)
634 {
635 int chunks = 0;
636 size_t used = 0;
637 size_t free = 0;
638 size_t wasted = 0;
639 ZONE *zone;
640
641 for (zone = head->next; zone; zone = zone->next)
642 {
643 if (zone == head->next)
644 free = zone->free;
645
646 chunks++;
647 used += zone->size - zone->free;
648 wasted += zone->free;
649 }
650
651 wasted -= free;
652
653 printf("Zone '%s':\n Chunks:%d, Allocs:%u, Used:%u, Free:%u, Wasted:%u\n",
654 head->name, chunks, head->allocs, used, free, wasted);
655 }
656 #endif
657
658 /* Frees all memory chunks but preserves head */
659 /* 2001-17 jmruiz modified to avoid the document peak problem (one document can
660 use a lot of memory and, in the old way, this memory was never reused)
661 */
662 void Mem_ZoneReset(MEM_ZONE *head)
663 {
664 ZONE *next, *tmp;
665
666 if (!head)
667 return;
668
669 head->allocs = 0;
670
671 next = head->next;
672 while (next)
673 {
674 efree(next->alloc);
675 tmp = next->next;
676 efree(next);
677 next = tmp;
678 }
679 head->next = NULL;
680 }
681
682 /* Routine that returns the amount of memory allocated by a zone */
683 int Mem_ZoneSize(MEM_ZONE *head)
684 {
685 ZONE *next;
686 int size = 0;
687
688 if (!head)
689 return 0;
690
691 next = head->next;
692 while (next)
693 {
694 size += next->size;
695 next = next->next;
696 }
697
698 return size;
699 }
700
701

  ViewVC Help
Powered by ViewVC 1.1.22