ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/common/malloc.c
(Generate patch)

Comparing ray/src/common/malloc.c (file contents):
Revision 1.1 by greg, Tue Sep 25 17:14:04 1990 UTC vs.
Revision 2.6 by greg, Fri Sep 4 09:57:43 1992 UTC

# Line 1 | Line 1
1 < /* Copyright (c) 1990 Regents of the University of California */
1 > /* Copyright (c) 1992 Regents of the University of California */
2  
3   #ifndef lint
4   static char SCCSid[] = "$SunId$ LBL";
# Line 7 | Line 7 | static char SCCSid[] = "$SunId$ LBL";
7   /*
8   * Fast malloc for memory hogs and VM environments.
9   * Performs a minimum of searching through free lists.
10 * bmalloc() doesn't keep track of free lists -- it's basically
11 *      just a buffered call to sbrk().
12 * bfree() puts memory from any source into malloc() 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 + * mcompact() takes the same arguments as mscrounge() (and is in fact
19 + *      called by mscrounge() under dire circumstances), but it uses
20 + *      memory compaction to return a larger block.  (MCOMP)
21   *
22   *      Greg Ward       Lawrence Berkeley Laboratory
23   */
24  
25 + #include  <errno.h>
26 +
27 + extern int      errno;
28 +
29 + #ifdef MSTATS
30 + #include  <stdio.h>
31 + static unsigned b_nsbrked = 0;
32 + static unsigned b_nalloced = 0;
33 + static unsigned b_nfreed = 0;
34 + static unsigned b_nscrounged = 0;
35 + static unsigned b_ncompacted = 0;
36 + static unsigned m_nalloced = 0;
37 + static unsigned m_nfreed = 0;
38 + static unsigned m_nwasted = 0;
39 + #else
40   #define  NULL           0
41 + #endif
42  
43   #ifndef ALIGN
44   #define  ALIGN          int                     /* align type */
45   #endif
46   #define  BYTES_WORD     sizeof(ALIGN)
47  
48 < #ifdef  NOVMEM
49 < #define  getpagesize()  BYTES_WORD
48 > #ifndef  MAXINCR
49 > #define  MAXINCR        (1<<16)                 /* largest sbrk(2) increment */
50   #endif
29
51                                          /* malloc free lists */
52   typedef union m_head {
53          union m_head    *next;
54 <        int             bucket;
54 >        struct {
55 >                short           magic;
56 >                short           bucket;
57 >        }       a;
58          ALIGN           dummy;
59   } M_HEAD;
60  
61 + #define MAGIC           0x1a2           /* magic number for allocated memory */
62 +
63   #define FIRSTBUCKET     3
64   #define NBUCKETS        30
65  
66   static M_HEAD   *free_list[NBUCKETS];
67  
68 + static ALIGN    dummy_mem;
69  
70 + static char     *memlim[2];
71 +
72 + #define DUMMYLOC        ((char *)&dummy_mem)
73 +
74 + #define BADPTR(p)       ((p) < memlim[0] | (p) >= memlim[1])
75 +
76 + #ifdef  MCOMP                   /* memory compaction routines */
77 + static char     seedtab[1024];          /* seed for compaction table */
78 +
79 + static struct mblk {
80 +        char            *ptr;   /* pointer to memory block */
81 +        unsigned        siz;    /* size of memory block */
82 + }       cptab = {seedtab, sizeof(seedtab)};
83 +
84 + #define mtab(mb)        ((struct mblk *)(mb)->ptr)
85 + #define mtablen(mb)     ((mb)->siz/sizeof(struct mblk))
86 +
87 +
88 + static int
89 + mbcmp(m1, m2)           /* compare memory block locations */
90 + register struct mblk    *m1, *m2;
91 + {
92 +                                /* put empty blocks at end */
93 +        if (m1->siz == 0)
94 +                return(m2->siz == 0 ? 0 : 1);
95 +        if (m2->siz == 0)
96 +                return(-1);
97 +                                /* otherwise, ascending order */
98 +        return(m1->ptr - m2->ptr);
99 + }
100 +
101 +
102 + int
103 + compactfree()           /* compact free lists (moving to table) */
104 + {
105 +        register struct mblk    *tp;
106 +        register int    bucket;
107 +        unsigned        n, bsiz, ncomp;
108 +                                /* fill table from free lists */
109 +        tp = mtab(&cptab); n = mtablen(&cptab);
110 +        bucket = NBUCKETS-1; bsiz = 1<<(NBUCKETS-1);
111 +        ncomp = 0;
112 +        for ( ; ; ) {
113 +                while (tp->siz) {       /* find empty slot */
114 +                        if (--n == 0)
115 +                                goto loopexit;
116 +                        tp++;
117 +                }
118 +                while (free_list[bucket] == NULL) {     /* find block */
119 +                        if (--bucket < FIRSTBUCKET)
120 +                                goto loopexit;
121 +                        bsiz >>= 1;
122 +                }
123 +                tp->ptr = (char *)free_list[bucket];
124 +                ncomp += (tp->siz = bsiz + sizeof(M_HEAD));
125 +                free_list[bucket] = free_list[bucket]->next;
126 +        }
127 + loopexit:
128 +        if (ncomp == 0)
129 +                return(0);              /* nothing new to compact */
130 + #ifdef MSTATS
131 +        b_ncompacted += ncomp;
132 + #endif
133 +        tp = mtab(&cptab); n = mtablen(&cptab);         /* sort table */
134 +        qsort((char *)tp, n, sizeof(struct mblk), mbcmp);
135 +        ncomp = 0;                                      /* collect blocks */
136 +        while (--n && tp[1].siz) {
137 +                if (tp[0].ptr + tp[0].siz == tp[1].ptr) {
138 +                        tp[1].ptr = tp[0].ptr;
139 +                        tp[1].siz += tp[0].siz;
140 +                        ncomp += tp[0].siz;
141 +                        tp[0].siz = 0;
142 +                }
143 +                tp++;
144 +        }
145 +        return(ncomp);
146 + }
147 +
148 +
149   char *
150 + mcompact(np)            /* compact free lists to satisfy request */
151 + unsigned        *np;
152 + {
153 +        struct mblk     *tab;
154 +        unsigned        tablen;
155 +        register struct mblk    *bp, *big;
156 +
157 +        for ( ; ; ) {
158 +                                        /* compact free lists */
159 +                compactfree();
160 +                                        /* find largest block */
161 +                tab = mtab(&cptab); tablen = mtablen(&cptab);
162 +                big = tab;
163 +                bp = tab + tablen;
164 +                while (--bp > tab)
165 +                        if (bp->siz > big->siz)
166 +                                big = bp;
167 +                if (big->siz >= *np) {          /* big enough? */
168 +                        *np = big->siz;
169 +                        big->siz = 0;           /* remove from table */
170 +                        return(big->ptr);       /* return it */
171 +                }
172 +                if (mtablen(big) < tablen+1) {
173 +                        *np = 0;                /* cannot grow table */
174 +                        return(NULL);           /* report failure */
175 +                }
176 +                                /* enlarge table, free old one */
177 +                mtab(big)[0].ptr = cptab.ptr;
178 +                mtab(big)[0].siz = cptab.siz;
179 +                cptab.ptr = big->ptr;
180 +                cptab.siz = big->siz;
181 +                big->siz = 0;                   /* clear and copy */
182 + #ifdef BSD
183 +                bcopy((char *)tab, (char *)(mtab(&cptab)+1),
184 +                                tablen*sizeof(struct mblk));
185 +                bzero((char *)(mtab(&cptab)+tablen+1),
186 +                        (mtablen(&cptab)-tablen-1)*sizeof(struct mblk));
187 + #else
188 +                (void)memcpy((char *)(mtab(&cptab)+1), (char *)tab,
189 +                                tablen*sizeof(struct mblk));
190 +                memset((char *)(mtab(&cptab)+tablen+1), 0,
191 +                        (mtablen(&cptab)-tablen-1)*sizeof(struct mblk));
192 + #endif
193 +        }                       /* next round */
194 + }
195 + #endif          /* MCOMP */
196 +
197 +
198 + char *
199 + mscrounge(np)           /* search free lists to satisfy request */
200 + register unsigned       *np;
201 + {
202 +        char    *p;
203 +        register int    bucket;
204 +        register unsigned       bsiz;
205 +
206 +        for (bucket = FIRSTBUCKET, bsiz = 1<<FIRSTBUCKET;
207 +                        bucket < NBUCKETS; bucket++, bsiz <<= 1)
208 +                if (free_list[bucket] != NULL && bsiz+sizeof(M_HEAD) >= *np) {
209 +                        *np = bsiz+sizeof(M_HEAD);
210 +                        p = (char *)free_list[bucket];
211 +                        free_list[bucket] = free_list[bucket]->next;
212 + #ifdef MSTATS
213 +                        b_nscrounged += *np;
214 + #endif
215 +                        return(p);
216 +                }
217 + #ifdef MCOMP
218 +        return(mcompact(np));           /* try compaction */
219 + #else
220 +        *np = 0;
221 +        return(NULL);
222 + #endif
223 + }
224 +
225 +
226 + char *
227   bmalloc(n)              /* allocate a block of n bytes, sans header */
228   register unsigned  n;
229   {
230          extern char  *sbrk();
231 <        static int  pagesz = 0;
232 <        static int  amnt;
231 >        static unsigned  pagesz = 0;
232 >        static unsigned  amnt;
233          static char  *bpos;
234 <        static int  nrem;
234 >        static unsigned  nrem;
235 >        unsigned  thisamnt;
236          register char   *p;
237  
238          if (pagesz == 0) {                              /* initialize */
239 <                amnt = pagesz = getpagesize();
239 >                pagesz = amnt = getpagesize();
240                  nrem = (int)sbrk(0);                    /* page align break */
241                  nrem = pagesz - (nrem&(pagesz-1));
242 <                bpos = sbrk(nrem);                      /* word aligned! */
242 >                bpos = sbrk(nrem);
243                  if ((int)bpos == -1)
244                          return(NULL);
245 + #ifdef MSTATS
246 +                b_nsbrked += nrem;
247 + #endif
248 +                bpos += nrem & (BYTES_WORD-1);          /* align pointer */
249 +                nrem &= ~(BYTES_WORD-1);
250 +                memlim[0] = bpos;
251 +                memlim[1] = bpos + nrem;
252          }
253  
254          n = (n+(BYTES_WORD-1))&~(BYTES_WORD-1);         /* word align rqst. */
255  
256          if (n > nrem) {                                 /* need more core */
257 <                if (n > amnt)                   /* increase amount */
258 <                        amnt = (n+(pagesz-1))&~(pagesz-1);
259 <                p = sbrk(amnt);
260 <                if ((int)p == -1)
70 <                        return(NULL);
71 <                if (p != bpos+nrem) {           /* someone called sbrk()! */
72 <                        bfree(bpos, nrem);
73 <                        bpos = p;
74 <                        nrem = amnt;
257 >                if (n > amnt) {                         /* big chunk */
258 >                        thisamnt = (n+(pagesz-1))&~(pagesz-1);
259 >                        if (thisamnt <= MAXINCR)        /* increase amnt */
260 >                                amnt = thisamnt;
261                  } else
262 <                        nrem += amnt;
262 >                        thisamnt = amnt;
263 >                p = sbrk(thisamnt);
264 >                if ((int)p == -1) {                     /* uh-oh, ENOMEM */
265 >                        thisamnt = n;                   /* search free lists */
266 >                        p = mscrounge(&thisamnt);
267 >                        if (p == NULL)                  /* we're really out */
268 >                                return(NULL);
269 >                }
270 > #ifdef MSTATS
271 >                else b_nsbrked += thisamnt;
272 > #endif
273 >                if (p != bpos+nrem) {                   /* not an increment */
274 >                        bfree(bpos, nrem);              /* free what we have */
275 >                        bpos = p;
276 >                        nrem = thisamnt;
277 >                } else                                  /* otherwise tack on */
278 >                        nrem += thisamnt;
279 >                if (bpos < memlim[0])
280 >                        memlim[0] = bpos;
281 >                if (bpos + nrem > memlim[1])
282 >                        memlim[1] = bpos + nrem;
283          }
284          p = bpos;
285          bpos += n;                                      /* advance */
286          nrem -= n;
287 + #ifdef MSTATS
288 +        b_nalloced += n;
289 + #endif
290          return(p);
291   }
292  
293  
294   bfree(p, n)                     /* free n bytes of random memory */
295 < char  *p;
296 < unsigned  n;
295 > register char  *p;
296 > register unsigned  n;
297   {
89        register M_HEAD *mp;
298          register int    bucket;
299          register unsigned       bsiz;
300 <                                        /* find largest bucket */
301 <        bucket = 0;
302 <        for (bsiz = 1; bsiz+sizeof(M_HEAD) <= n; bsiz <<= 1)
303 <                bucket++;
304 <        mp = (M_HEAD *)p;
305 <        while (bucket > FIRSTBUCKET) {
306 <                bsiz >>= 1;
307 <                bucket--;
308 <                if (n < bsiz+sizeof(M_HEAD))    /* nothing for this bucket */
309 <                        continue;
310 <                mp->next = free_list[bucket];
103 <                free_list[bucket] = mp;
104 <                (char *)mp += bsiz+sizeof(M_HEAD);
105 <                n -= bsiz+sizeof(M_HEAD);
300 >
301 >        if (n < 1<<FIRSTBUCKET)
302 >                return;
303 > #ifdef MSTATS
304 >        b_nfreed += n;
305 > #endif
306 >                                        /* align pointer */
307 >        bsiz = BYTES_WORD - ((unsigned)p&(BYTES_WORD-1));
308 >        if (bsiz < BYTES_WORD) {
309 >                p += bsiz;
310 >                n -= bsiz;
311          }
312 +        if (p < memlim[0])
313 +                memlim[0] = p;
314 +        if (p + n > memlim[1])
315 +                memlim[1] = p + n;
316 +                                        /* fill big buckets first */
317 +        for (bucket = NBUCKETS-1, bsiz = 1<<(NBUCKETS-1);
318 +                        bucket >= FIRSTBUCKET; bucket--, bsiz >>= 1)
319 +                if (n >= bsiz+sizeof(M_HEAD)) {
320 +                        ((M_HEAD *)p)->next = free_list[bucket];
321 +                        free_list[bucket] = (M_HEAD *)p;
322 +                        p += bsiz+sizeof(M_HEAD);
323 +                        n -= bsiz+sizeof(M_HEAD);
324 +                }
325   }
326  
327  
# Line 114 | Line 332 | unsigned       n;
332          register M_HEAD *mp;
333          register int    bucket;
334          register unsigned       bsiz;
335 <
336 <        bucket = FIRSTBUCKET;
337 <        for (bsiz = 1<<FIRSTBUCKET; bsiz < n; bsiz <<= 1)
338 <                bucket++;
339 <        if (free_list[bucket] == NULL) {
335 >                                        /* don't return NULL on 0 request */
336 >        if (n == 0)
337 >                return(DUMMYLOC);
338 >                                        /* find first bucket that fits */
339 >        for (bucket = FIRSTBUCKET, bsiz = 1<<FIRSTBUCKET;
340 >                        bucket < NBUCKETS; bucket++, bsiz <<= 1)
341 >                if (bsiz >= n)
342 >                        break;
343 >        if (bucket >= NBUCKETS) {
344 >                errno = EINVAL;
345 >                return(NULL);
346 >        }
347 >        if (free_list[bucket] == NULL) {        /* need more core */
348                  mp = (M_HEAD *)bmalloc(bsiz+sizeof(M_HEAD));
349                  if (mp == NULL)
350                          return(NULL);
351 <        } else {
351 >        } else {                                /* got it */
352                  mp = free_list[bucket];
353                  free_list[bucket] = mp->next;
354          }
355 <        mp->bucket = bucket;
355 > #ifdef MSTATS
356 >        m_nalloced += bsiz + sizeof(M_HEAD);
357 >        m_nwasted += bsiz + sizeof(M_HEAD) - n;
358 > #endif
359 >        mp->a.magic = MAGIC;                    /* tag block */
360 >        mp->a.bucket = bucket;
361          return((char *)(mp+1));
362   }
363  
364  
365   char *
366   realloc(op, n)                  /* reallocate memory using malloc() */
367 < char    *op;
367 > register char   *op;
368   unsigned        n;
369   {
370 <        register char   *p;
370 >        char    *p;
371          register unsigned       on;
372 <
373 <        if (op != NULL)
374 <                on = 1 << ((M_HEAD *)op-1)->bucket;
372 >                                        /* get old size */
373 >        if (op != DUMMYLOC && !BADPTR(op) &&
374 >                        ((M_HEAD *)op-1)->a.magic == MAGIC)
375 >                on = 1 << ((M_HEAD *)op-1)->a.bucket;
376          else
377                  on = 0;
378 <        if (n <= on && n > on>>1)
378 >        if (n <= on && (n > on>>1 || on == 1<<FIRSTBUCKET))
379                  return(op);             /* same bucket */
380 <        p = malloc(n);
381 <        if (p == NULL)
382 <                return(NULL);
380 >        if ((p = malloc(n)) == NULL)
381 >                return(n<=on ? op : NULL);
382 >        if (on) {
383   #ifdef  BSD
384 <        bcopy(op, p, n>on ? on : n);
384 >                bcopy(op, p, n>on ? on : n);
385   #else
386 <        (void)memcpy(p, op, n>on ? on : n);
386 >                (void)memcpy(p, op, n>on ? on : n);
387   #endif
388 <        free(op);
388 >                free(op);
389 >        }
390          return(p);
391   }
392  
# Line 164 | Line 397 | char   *p;
397          register M_HEAD *mp;
398          register int    bucket;
399  
400 +        if (p == DUMMYLOC)
401 +                return(1);
402 +        if (BADPTR(p))
403 +                goto invalid;
404          mp = (M_HEAD *)p - 1;
405 <        bucket = mp->bucket;
405 >        if (mp->a.magic != MAGIC)               /* sanity check */
406 >                goto invalid;
407 >        bucket = mp->a.bucket;
408 >        if (bucket < FIRSTBUCKET | bucket >= NBUCKETS)
409 >                goto invalid;
410          mp->next = free_list[bucket];
411          free_list[bucket] = mp;
412 + #ifdef MSTATS
413 +        m_nfreed += (1 << bucket) + sizeof(M_HEAD);
414 + #endif
415 +        return(1);
416 + invalid:
417 +        errno = EINVAL;
418 +        return(0);
419   }
420  
421  
422 < #ifndef NOVMEM
423 < #ifndef BSD
424 < #include <sys/var.h>
177 < int
178 < getpagesize()                   /* use SYSV var structure to get page size */
422 > #ifdef MSTATS
423 > printmemstats(fp)               /* print memory statistics to stream */
424 > FILE    *fp;
425   {
426 <        static int  pagesz = 0;
427 <        struct var  v;
426 >        register int    i;
427 >        int     n;
428 >        register M_HEAD *mp;
429 >        unsigned int    total = 0;
430  
431 <        if (pagesz == 0) {
432 <                uvar(&v);
433 <                pagesz = 1 << v.v_pageshift;
431 >        fprintf(fp, "Memory statistics:\n");
432 >        fprintf(fp, "\tbmalloc: %d bytes from sbrk\n", b_nsbrked);
433 >        fprintf(fp, "\tbmalloc: %d bytes allocated\n", b_nalloced);
434 >        fprintf(fp, "\tbmalloc: %d bytes freed\n", b_nfreed);
435 >        fprintf(fp, "\tbmalloc: %d bytes scrounged\n", b_nscrounged);
436 >        fprintf(fp, "\tbmalloc: %d bytes compacted\n", b_ncompacted);
437 >        fprintf(fp, "\tmalloc: %d bytes allocated\n", m_nalloced);
438 >        fprintf(fp, "\tmalloc: %d bytes wasted (%.1f%%)\n", m_nwasted,
439 >                        100.0*m_nwasted/m_nalloced);
440 >        fprintf(fp, "\tmalloc: %d bytes freed\n", m_nfreed);
441 >        for (i = NBUCKETS-1; i >= FIRSTBUCKET; i--) {
442 >                n = 0;
443 >                for (mp = free_list[i]; mp != NULL; mp = mp->next)
444 >                        n++;
445 >                if (n) {
446 >                        fprintf(fp, "\t%d * %u\n", n, 1<<i);
447 >                        total += n * ((1<<i) + sizeof(M_HEAD));
448 >                }
449          }
450 <        return(pagesz);
450 >        fprintf(fp, "\t %u total bytes in free list\n", total);
451   }
189 #endif
452   #endif

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines