ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/common/malloc.c
Revision: 1.9
Committed: Wed Oct 3 21:01:59 1990 UTC (33 years, 7 months ago) by greg
Content type: text/plain
Branch: MAIN
Changes since 1.8: +60 -1 lines
Log Message:
added memory statistics gathering (-DMSTATS)

File Contents

# User Rev Content
1 greg 1.1 /* Copyright (c) 1990 Regents of the University of California */
2    
3     #ifndef lint
4     static char SCCSid[] = "$SunId$ LBL";
5     #endif
6    
7     /*
8     * Fast malloc for memory hogs and VM environments.
9     * Performs a minimum of searching through free lists.
10 greg 1.4 * malloc(), realloc() and free() use buckets
11     * containing blocks in powers of two, similar to CIT routines.
12     * bfree() puts memory from any source into malloc free lists.
13     * bmalloc() doesn't keep track of free lists -- it's usually
14 greg 1.3 * just a buffered call to sbrk(2). However, bmalloc will
15     * call mscrounge() if sbrk fails.
16 greg 1.8 * mscrounge() returns whatever free memory it can find to satisfy the
17 greg 1.3 * request along with the number of bytes (modified).
18 greg 1.1 *
19     * Greg Ward Lawrence Berkeley Laboratory
20     */
21    
22 greg 1.6 #include <errno.h>
23    
24 greg 1.9 #ifdef MSTATS
25     #include <stdio.h>
26    
27     static unsigned b_nalloced = 0;
28     static unsigned b_nfreed = 0;
29     static unsigned b_nscrounged = 0;
30     static unsigned m_nalloced = 0;
31     static unsigned m_nfreed = 0;
32     static unsigned m_nwasted = 0;
33     #else
34 greg 1.1 #define NULL 0
35 greg 1.9 #endif
36 greg 1.1
37     #ifndef ALIGN
38     #define ALIGN int /* align type */
39     #endif
40     #define BYTES_WORD sizeof(ALIGN)
41    
42 greg 1.9 #define MAXINCR (1<<16) /* largest sbrk(2) increment */
43 greg 1.3
44 greg 1.1 #ifdef NOVMEM
45     #define getpagesize() BYTES_WORD
46     #endif
47     /* malloc free lists */
48     typedef union m_head {
49     union m_head *next;
50     int bucket;
51     ALIGN dummy;
52     } M_HEAD;
53    
54     #define FIRSTBUCKET 3
55     #define NBUCKETS 30
56    
57     static M_HEAD *free_list[NBUCKETS];
58    
59    
60     char *
61 greg 1.4 mscrounge(np) /* search free lists to satisfy request */
62 greg 1.3 register unsigned *np;
63     {
64     char *p;
65     register int bucket;
66     register unsigned bsiz;
67    
68     for (bucket = FIRSTBUCKET, bsiz = 1<<FIRSTBUCKET;
69     bucket < NBUCKETS; bucket++, bsiz <<= 1)
70     if (free_list[bucket] != NULL && bsiz+sizeof(M_HEAD) >= *np) {
71     *np = bsiz+sizeof(M_HEAD);
72     p = (char *)free_list[bucket];
73     free_list[bucket] = free_list[bucket]->next;
74 greg 1.9 #ifdef MSTATS
75     b_nscrounged += *np;
76     #endif
77 greg 1.3 return(p);
78     }
79     *np = 0;
80     return(NULL);
81     }
82    
83    
84     char *
85 greg 1.1 bmalloc(n) /* allocate a block of n bytes, sans header */
86     register unsigned n;
87     {
88     extern char *sbrk();
89 greg 1.3 static unsigned pagesz = 0;
90     static unsigned amnt;
91 greg 1.1 static char *bpos;
92 greg 1.3 static unsigned nrem;
93     unsigned thisamnt;
94 greg 1.1 register char *p;
95    
96 greg 1.9 #ifdef MSTATS
97     b_nalloced += n;
98     #endif
99 greg 1.1 if (pagesz == 0) { /* initialize */
100 greg 1.2 pagesz = amnt = getpagesize();
101 greg 1.1 nrem = (int)sbrk(0); /* page align break */
102     nrem = pagesz - (nrem&(pagesz-1));
103     bpos = sbrk(nrem); /* word aligned! */
104     if ((int)bpos == -1)
105     return(NULL);
106     }
107    
108     n = (n+(BYTES_WORD-1))&~(BYTES_WORD-1); /* word align rqst. */
109    
110     if (n > nrem) { /* need more core */
111 greg 1.3 if (n > amnt) { /* big chunk */
112     thisamnt = (n+(pagesz-1))&~(pagesz-1);
113     if (thisamnt <= MAXINCR) /* increase amnt */
114     amnt = thisamnt;
115     } else
116     thisamnt = amnt;
117     p = sbrk(thisamnt);
118 greg 1.4 if ((int)p == -1) { /* uh-oh, ENOMEM */
119 greg 1.3 thisamnt = n; /* search free lists */
120     p = mscrounge(&thisamnt);
121     if (p == NULL) /* we're really out */
122     return(NULL);
123     }
124     if (p != bpos+nrem) { /* not an increment */
125 greg 1.4 bfree(bpos, nrem); /* free what we have */
126 greg 1.1 bpos = p;
127 greg 1.3 nrem = thisamnt;
128 greg 1.4 } else /* otherwise tack on */
129 greg 1.3 nrem += thisamnt;
130 greg 1.1 }
131     p = bpos;
132     bpos += n; /* advance */
133     nrem -= n;
134     return(p);
135     }
136    
137    
138     bfree(p, n) /* free n bytes of random memory */
139 greg 1.2 register char *p;
140     register unsigned n;
141 greg 1.1 {
142     register int bucket;
143     register unsigned bsiz;
144 greg 1.9
145     #ifdef MSTATS
146     b_nfreed += n;
147     #endif
148 greg 1.4 /* align pointer */
149 greg 1.6 bsiz = BYTES_WORD - ((unsigned)p&(BYTES_WORD-1));
150 greg 1.4 if (bsiz < BYTES_WORD) {
151     p += bsiz;
152     n -= bsiz;
153 greg 1.1 }
154 greg 1.4 /* fill big buckets first */
155     for (bucket = NBUCKETS-1, bsiz = 1<<(NBUCKETS-1);
156     bucket >= FIRSTBUCKET; bucket--, bsiz >>= 1)
157     if (n >= bsiz+sizeof(M_HEAD)) {
158     ((M_HEAD *)p)->next = free_list[bucket];
159     free_list[bucket] = (M_HEAD *)p;
160     p += bsiz+sizeof(M_HEAD);
161     n -= bsiz+sizeof(M_HEAD);
162     }
163 greg 1.1 }
164    
165    
166     char *
167     malloc(n) /* allocate n bytes of memory */
168     unsigned n;
169     {
170 greg 1.6 extern int errno;
171 greg 1.1 register M_HEAD *mp;
172     register int bucket;
173     register unsigned bsiz;
174 greg 1.2 /* find first bucket that fits */
175 greg 1.6 for (bucket = FIRSTBUCKET, bsiz = 1<<FIRSTBUCKET;
176     bucket < NBUCKETS; bucket++, bsiz <<= 1)
177     if (bsiz >= n)
178     break;
179     if (bucket >= NBUCKETS) {
180     errno = EINVAL;
181     return(NULL);
182     }
183 greg 1.9 #ifdef MSTATS
184     m_nalloced += bsiz + sizeof(M_HEAD);
185     m_nwasted += bsiz + sizeof(M_HEAD) - n;
186     #endif
187 greg 1.4 if (free_list[bucket] == NULL) { /* need more core */
188 greg 1.1 mp = (M_HEAD *)bmalloc(bsiz+sizeof(M_HEAD));
189     if (mp == NULL)
190     return(NULL);
191 greg 1.4 } else { /* got it */
192 greg 1.1 mp = free_list[bucket];
193     free_list[bucket] = mp->next;
194     }
195 greg 1.4 mp->bucket = bucket; /* tag block */
196 greg 1.1 return((char *)(mp+1));
197     }
198    
199    
200     char *
201     realloc(op, n) /* reallocate memory using malloc() */
202 greg 1.6 register char *op;
203 greg 1.1 unsigned n;
204     {
205 greg 1.6 char *p;
206 greg 1.1 register unsigned on;
207 greg 1.6 /* get old size */
208 greg 1.5 if (op != NULL)
209     on = 1 << ((M_HEAD *)op-1)->bucket;
210     else
211     on = 0;
212 greg 1.6 if (n <= on && (n > on>>1 || on == 1<<FIRSTBUCKET))
213 greg 1.5 return(op); /* same bucket */
214     p = malloc(n);
215     if (p != NULL)
216 greg 1.1 #ifdef BSD
217 greg 1.2 bcopy(op, p, n>on ? on : n);
218 greg 1.1 #else
219 greg 1.2 (void)memcpy(p, op, n>on ? on : n);
220 greg 1.1 #endif
221 greg 1.5 free(op);
222 greg 1.1 return(p);
223     }
224    
225    
226     free(p) /* free memory allocated by malloc */
227     char *p;
228     {
229     register M_HEAD *mp;
230     register int bucket;
231    
232 greg 1.2 if (p == NULL)
233     return;
234 greg 1.1 mp = (M_HEAD *)p - 1;
235     bucket = mp->bucket;
236     mp->next = free_list[bucket];
237     free_list[bucket] = mp;
238 greg 1.9 #ifdef MSTATS
239     m_nfreed += (1 << bucket) + sizeof(M_HEAD);
240     #endif
241 greg 1.1 }
242    
243    
244     #ifndef NOVMEM
245     #ifndef BSD
246     #include <sys/var.h>
247     int
248     getpagesize() /* use SYSV var structure to get page size */
249     {
250     struct var v;
251    
252 greg 1.8 uvar(&v);
253     return(1 << v.v_pageshift);
254 greg 1.1 }
255     #endif
256 greg 1.9 #endif
257    
258    
259     #ifdef MSTATS
260     printmemstats(fp) /* print memory statistics to stream */
261     FILE *fp;
262     {
263     register int i;
264     int n;
265     register M_HEAD *mp;
266     unsigned int total = 0;
267    
268     fprintf(fp, "Memory statistics:\n");
269     fprintf(fp, "\tbmalloc: %d bytes allocated\n", b_nalloced);
270     fprintf(fp, "\tbmalloc: %d bytes freed\n", b_nfreed);
271     fprintf(fp, "\tbmalloc: %d bytes scrounged\n", b_nscrounged);
272     fprintf(fp, "\tmalloc: %d bytes allocated\n", m_nalloced);
273     fprintf(fp, "\tmalloc: %d bytes wasted (%.1f%%)\n", m_nwasted,
274     100.0*m_nwasted/m_nalloced);
275     fprintf(fp, "\tmalloc: %d bytes freed\n", m_nfreed);
276     for (i = NBUCKETS-1; i >= FIRSTBUCKET; i--) {
277     n = 0;
278     for (mp = free_list[i]; mp != NULL; mp = mp->next)
279     n++;
280     if (n) {
281     fprintf(fp, "\t%d * %u\n", n, 1<<i);
282     total += n * ((1<<i) + sizeof(M_HEAD));
283     }
284     }
285     fprintf(fp, "\t %u total bytes in free list\n", total);
286     }
287 greg 1.1 #endif