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

Annotation 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 - (hide 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 adcroft 1.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