ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/common/malloc.c
Revision: 1.10
Committed: Tue Nov 13 14:39:05 1990 UTC (33 years, 5 months ago) by greg
Content type: text/plain
Branch: MAIN
Changes since 1.9: +7 -3 lines
Log Message:
added check for zero request

File Contents

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