Free cookie consent management tool by TermsFeed Policy Generator

source: branches/HeuristicLab.Analysis.AlgorithmBehavior/qhull-2012.1/src/libqhull/mem.c @ 11303

Last change on this file since 11303 was 10207, checked in by ascheibe, 11 years ago

#1886 added a unit test for volume calculation and the qhull library

File size: 19.1 KB
Line 
1/*<html><pre>  -<a                             href="qh-mem.htm"
2  >-------------------------------</a><a name="TOP">-</a>
3
4  mem.c
5    memory management routines for qhull
6
7  This is a standalone program.
8
9  To initialize memory:
10
11    qh_meminit(stderr);
12    qh_meminitbuffers(qh IStracing, qh_MEMalign, 7, qh_MEMbufsize,qh_MEMinitbuf);
13    qh_memsize((int)sizeof(facetT));
14    qh_memsize((int)sizeof(facetT));
15    ...
16    qh_memsetup();
17
18  To free up all memory buffers:
19    qh_memfreeshort(&curlong, &totlong);
20
21  if qh_NOmem,
22    malloc/free is used instead of mem.c
23
24  notes:
25    uses Quickfit algorithm (freelists for commonly allocated sizes)
26    assumes small sizes for freelists (it discards the tail of memory buffers)
27
28  see:
29    qh-mem.htm and mem.h
30    global.c (qh_initbuffers) for an example of using mem.c
31
32  Copyright (c) 1993-2012 The Geometry Center.
33  $Id: //main/2011/qhull/src/libqhull/mem.c#4 $$Change: 1464 $
34  $DateTime: 2012/01/25 22:58:41 $$Author: bbarber $
35*/
36
37#include "mem.h"
38#include <string.h>
39#include <stdio.h>
40#include <stdlib.h>
41
42#ifndef qhDEFlibqhull
43typedef struct ridgeT ridgeT;
44typedef struct facetT facetT;
45#ifdef _MSC_VER  /* Microsoft Visual C++ -- warning level 4 */
46#pragma warning( disable : 4127)  /* conditional expression is constant */
47#pragma warning( disable : 4706)  /* assignment within conditional function */
48#endif
49void    qh_errexit(int exitcode, facetT *, ridgeT *);
50void    qh_exit(int exitcode);
51void    qh_fprintf(FILE *fp, int msgcode, const char *fmt, ... );
52void    qh_free(void *mem);
53void   *qh_malloc(size_t size);
54#endif
55
56/*============ -global data structure ==============
57    see mem.h for definition
58*/
59
60qhmemT qhmem= {0,0,0,0,0,0,0,0,0,0,0,
61               0,0,0,0,0,0,0,0,0,0,0,
62               0,0,0,0,0,0,0};     /* remove "= {0}" if this causes a compiler error */
63
64#ifndef qh_NOmem
65
66/*============= internal functions ==============*/
67
68static int qh_intcompare(const void *i, const void *j);
69
70/*========== functions in alphabetical order ======== */
71
72/*-<a                             href="qh-mem.htm#TOC"
73  >-------------------------------</a><a name="intcompare">-</a>
74
75  qh_intcompare( i, j )
76    used by qsort and bsearch to compare two integers
77*/
78static int qh_intcompare(const void *i, const void *j) {
79  return(*((const int *)i) - *((const int *)j));
80} /* intcompare */
81
82
83/*-<a                             href="qh-mem.htm#TOC"
84  >--------------------------------</a><a name="memalloc">-</a>
85
86  qh_memalloc( insize )
87    returns object of insize bytes
88    qhmem is the global memory structure
89
90  returns:
91    pointer to allocated memory
92    errors if insufficient memory
93
94  notes:
95    use explicit type conversion to avoid type warnings on some compilers
96    actual object may be larger than insize
97    use qh_memalloc_() for inline code for quick allocations
98    logs allocations if 'T5'
99
100  design:
101    if size < qhmem.LASTsize
102      if qhmem.freelists[size] non-empty
103        return first object on freelist
104      else
105        round up request to size of qhmem.freelists[size]
106        allocate new allocation buffer if necessary
107        allocate object from allocation buffer
108    else
109      allocate object with qh_malloc() in user.c
110*/
111void *qh_memalloc(int insize) {
112  void **freelistp, *newbuffer;
113  int idx, size, n;
114  int outsize, bufsize;
115  void *object;
116
117  if (insize<0) {
118      qh_fprintf(qhmem.ferr, 6235, "qhull error (qh_memalloc): negative request size (%d).  Did int overflow due to high-D?\n", insize); /* WARN64 */
119      qh_errexit(qhmem_ERRmem, NULL, NULL);
120  }
121  if (insize>=0 && insize <= qhmem.LASTsize) {
122    idx= qhmem.indextable[insize];
123    outsize= qhmem.sizetable[idx];
124    qhmem.totshort += outsize;
125    freelistp= qhmem.freelists+idx;
126    if ((object= *freelistp)) {
127      qhmem.cntquick++;
128      qhmem.totfree -= outsize;
129      *freelistp= *((void **)*freelistp);  /* replace freelist with next object */
130#ifdef qh_TRACEshort
131      n= qhmem.cntshort+qhmem.cntquick+qhmem.freeshort;
132      if (qhmem.IStracing >= 5)
133          qh_fprintf(qhmem.ferr, 8141, "qh_mem %p n %8d alloc quick: %d bytes (tot %d cnt %d)\n", object, n, outsize, qhmem.totshort, qhmem.cntshort+qhmem.cntquick-qhmem.freeshort);
134#endif
135      return(object);
136    }else {
137      qhmem.cntshort++;
138      if (outsize > qhmem .freesize) {
139        qhmem .totdropped += qhmem .freesize;
140        if (!qhmem.curbuffer)
141          bufsize= qhmem.BUFinit;
142        else
143          bufsize= qhmem.BUFsize;
144        if (!(newbuffer= qh_malloc((size_t)bufsize))) {
145          qh_fprintf(qhmem.ferr, 6080, "qhull error (qh_memalloc): insufficient memory to allocate short memory buffer (%d bytes)\n", bufsize);
146          qh_errexit(qhmem_ERRmem, NULL, NULL);
147        }
148        *((void **)newbuffer)= qhmem.curbuffer;  /* prepend newbuffer to curbuffer
149                                                    list */
150        qhmem.curbuffer= newbuffer;
151        size= (sizeof(void **) + qhmem.ALIGNmask) & ~qhmem.ALIGNmask;
152        qhmem.freemem= (void *)((char *)newbuffer+size);
153        qhmem.freesize= bufsize - size;
154        qhmem.totbuffer += bufsize - size; /* easier to check */
155        /* Periodically test totbuffer.  It matches at beginning and exit of every call */
156        n = qhmem.totshort + qhmem.totfree + qhmem.totdropped + qhmem.freesize - outsize;
157        if (qhmem.totbuffer != n) {
158            qh_fprintf(qhmem.ferr, 6212, "qh_memalloc internal error: short totbuffer %d != totshort+totfree... %d\n", qhmem.totbuffer, n);
159            qh_errexit(qhmem_ERRmem, NULL, NULL);
160        }
161      }
162      object= qhmem.freemem;
163      qhmem.freemem= (void *)((char *)qhmem.freemem + outsize);
164      qhmem.freesize -= outsize;
165      qhmem.totunused += outsize - insize;
166#ifdef qh_TRACEshort
167      n= qhmem.cntshort+qhmem.cntquick+qhmem.freeshort;
168      if (qhmem.IStracing >= 5)
169          qh_fprintf(qhmem.ferr, 8140, "qh_mem %p n %8d alloc short: %d bytes (tot %d cnt %d)\n", object, n, outsize, qhmem.totshort, qhmem.cntshort+qhmem.cntquick-qhmem.freeshort);
170#endif
171      return object;
172    }
173  }else {                     /* long allocation */
174    if (!qhmem.indextable) {
175      qh_fprintf(qhmem.ferr, 6081, "qhull internal error (qh_memalloc): qhmem has not been initialized.\n");
176      qh_errexit(qhmem_ERRqhull, NULL, NULL);
177    }
178    outsize= insize;
179    qhmem .cntlong++;
180    qhmem .totlong += outsize;
181    if (qhmem.maxlong < qhmem.totlong)
182      qhmem.maxlong= qhmem.totlong;
183    if (!(object= qh_malloc((size_t)outsize))) {
184      qh_fprintf(qhmem.ferr, 6082, "qhull error (qh_memalloc): insufficient memory to allocate %d bytes\n", outsize);
185      qh_errexit(qhmem_ERRmem, NULL, NULL);
186    }
187    if (qhmem.IStracing >= 5)
188      qh_fprintf(qhmem.ferr, 8057, "qh_mem %p n %8d alloc long: %d bytes (tot %d cnt %d)\n", object, qhmem.cntlong+qhmem.freelong, outsize, qhmem.totlong, qhmem.cntlong-qhmem.freelong);
189  }
190  return(object);
191} /* memalloc */
192
193
194/*-<a                             href="qh-mem.htm#TOC"
195  >--------------------------------</a><a name="memfree">-</a>
196
197  qh_memfree( object, insize )
198    free up an object of size bytes
199    size is insize from qh_memalloc
200
201  notes:
202    object may be NULL
203    type checking warns if using (void **)object
204    use qh_memfree_() for quick free's of small objects
205
206  design:
207    if size <= qhmem.LASTsize
208      append object to corresponding freelist
209    else
210      call qh_free(object)
211*/
212void qh_memfree(void *object, int insize) {
213  void **freelistp;
214  int idx, outsize;
215
216  if (!object)
217    return;
218  if (insize <= qhmem.LASTsize) {
219    qhmem .freeshort++;
220    idx= qhmem.indextable[insize];
221    outsize= qhmem.sizetable[idx];
222    qhmem .totfree += outsize;
223    qhmem .totshort -= outsize;
224    freelistp= qhmem.freelists + idx;
225    *((void **)object)= *freelistp;
226    *freelistp= object;
227#ifdef qh_TRACEshort
228    idx= qhmem.cntshort+qhmem.cntquick+qhmem.freeshort;
229    if (qhmem.IStracing >= 5)
230        qh_fprintf(qhmem.ferr, 8142, "qh_mem %p n %8d free short: %d bytes (tot %d cnt %d)\n", object, idx, outsize, qhmem.totshort, qhmem.cntshort+qhmem.cntquick-qhmem.freeshort);
231#endif
232  }else {
233    qhmem .freelong++;
234    qhmem .totlong -= insize;
235    qh_free(object);
236    if (qhmem.IStracing >= 5)
237      qh_fprintf(qhmem.ferr, 8058, "qh_mem %p n %8d free long: %d bytes (tot %d cnt %d)\n", object, qhmem.cntlong+qhmem.freelong, insize, qhmem.totlong, qhmem.cntlong-qhmem.freelong);
238  }
239} /* memfree */
240
241
242/*-<a                             href="qh-mem.htm#TOC"
243  >-------------------------------</a><a name="memfreeshort">-</a>
244
245  qh_memfreeshort( curlong, totlong )
246    frees up all short and qhmem memory allocations
247
248  returns:
249    number and size of current long allocations
250
251  see:
252    qh_freeqhull(allMem)
253    qh_memtotal(curlong, totlong, curshort, totshort, maxlong, totbuffer);
254*/
255void qh_memfreeshort(int *curlong, int *totlong) {
256  void *buffer, *nextbuffer;
257  FILE *ferr;
258
259  *curlong= qhmem .cntlong - qhmem .freelong;
260  *totlong= qhmem .totlong;
261  for (buffer= qhmem.curbuffer; buffer; buffer= nextbuffer) {
262    nextbuffer= *((void **) buffer);
263    qh_free(buffer);
264  }
265  qhmem.curbuffer= NULL;
266  if (qhmem .LASTsize) {
267    qh_free(qhmem .indextable);
268    qh_free(qhmem .freelists);
269    qh_free(qhmem .sizetable);
270  }
271  ferr= qhmem.ferr;
272  memset((char *)&qhmem, 0, sizeof(qhmem));  /* every field is 0, FALSE, NULL */
273  qhmem.ferr= ferr;
274} /* memfreeshort */
275
276
277/*-<a                             href="qh-mem.htm#TOC"
278  >--------------------------------</a><a name="meminit">-</a>
279
280  qh_meminit( ferr )
281    initialize qhmem and test sizeof( void*)
282*/
283void qh_meminit(FILE *ferr) {
284
285  memset((char *)&qhmem, 0, sizeof(qhmem));  /* every field is 0, FALSE, NULL */
286  qhmem.ferr= ferr;
287  if (sizeof(void*) < sizeof(int)) {
288    qh_fprintf(ferr, 6083, "qhull internal error (qh_meminit): sizeof(void*) %d < sizeof(int) %d.  qset.c will not work\n", (int)sizeof(void*), (int)sizeof(int));
289    qh_exit(qhmem_ERRqhull);  /* can not use qh_errexit() */
290  }
291  if (sizeof(void*) > sizeof(ptr_intT)) {
292      qh_fprintf(ferr, 6084, "qhull internal error (qh_meminit): sizeof(void*) %d > sizeof(ptr_intT) %d. Change ptr_intT in mem.h to 'long long'\n", (int)sizeof(void*), (int)sizeof(ptr_intT));
293      qh_exit(qhmem_ERRqhull);  /* can not use qh_errexit() */
294  }
295} /* meminit */
296
297/*-<a                             href="qh-mem.htm#TOC"
298  >-------------------------------</a><a name="meminitbuffers">-</a>
299
300  qh_meminitbuffers( tracelevel, alignment, numsizes, bufsize, bufinit )
301    initialize qhmem
302    if tracelevel >= 5, trace memory allocations
303    alignment= desired address alignment for memory allocations
304    numsizes= number of freelists
305    bufsize=  size of additional memory buffers for short allocations
306    bufinit=  size of initial memory buffer for short allocations
307*/
308void qh_meminitbuffers(int tracelevel, int alignment, int numsizes, int bufsize, int bufinit) {
309
310  qhmem.IStracing= tracelevel;
311  qhmem.NUMsizes= numsizes;
312  qhmem.BUFsize= bufsize;
313  qhmem.BUFinit= bufinit;
314  qhmem.ALIGNmask= alignment-1;
315  if (qhmem.ALIGNmask & ~qhmem.ALIGNmask) {
316    qh_fprintf(qhmem.ferr, 6085, "qhull internal error (qh_meminit): memory alignment %d is not a power of 2\n", alignment);
317    qh_errexit(qhmem_ERRqhull, NULL, NULL);
318  }
319  qhmem.sizetable= (int *) calloc((size_t)numsizes, sizeof(int));
320  qhmem.freelists= (void **) calloc((size_t)numsizes, sizeof(void *));
321  if (!qhmem.sizetable || !qhmem.freelists) {
322    qh_fprintf(qhmem.ferr, 6086, "qhull error (qh_meminit): insufficient memory\n");
323    qh_errexit(qhmem_ERRmem, NULL, NULL);
324  }
325  if (qhmem.IStracing >= 1)
326    qh_fprintf(qhmem.ferr, 8059, "qh_meminitbuffers: memory initialized with alignment %d\n", alignment);
327} /* meminitbuffers */
328
329/*-<a                             href="qh-mem.htm#TOC"
330  >-------------------------------</a><a name="memsetup">-</a>
331
332  qh_memsetup()
333    set up memory after running memsize()
334*/
335void qh_memsetup(void) {
336  int k,i;
337
338  qsort(qhmem.sizetable, (size_t)qhmem.TABLEsize, sizeof(int), qh_intcompare);
339  qhmem.LASTsize= qhmem.sizetable[qhmem.TABLEsize-1];
340  if (qhmem .LASTsize >= qhmem .BUFsize || qhmem.LASTsize >= qhmem .BUFinit) {
341    qh_fprintf(qhmem.ferr, 6087, "qhull error (qh_memsetup): largest mem size %d is >= buffer size %d or initial buffer size %d\n",
342            qhmem .LASTsize, qhmem .BUFsize, qhmem .BUFinit);
343    qh_errexit(qhmem_ERRmem, NULL, NULL);
344  }
345  if (!(qhmem.indextable= (int *)qh_malloc((qhmem.LASTsize+1) * sizeof(int)))) {
346    qh_fprintf(qhmem.ferr, 6088, "qhull error (qh_memsetup): insufficient memory\n");
347    qh_errexit(qhmem_ERRmem, NULL, NULL);
348  }
349  for (k=qhmem.LASTsize+1; k--; )
350    qhmem.indextable[k]= k;
351  i= 0;
352  for (k=0; k <= qhmem.LASTsize; k++) {
353    if (qhmem.indextable[k] <= qhmem.sizetable[i])
354      qhmem.indextable[k]= i;
355    else
356      qhmem.indextable[k]= ++i;
357  }
358} /* memsetup */
359
360/*-<a                             href="qh-mem.htm#TOC"
361  >-------------------------------</a><a name="memsize">-</a>
362
363  qh_memsize( size )
364    define a free list for this size
365*/
366void qh_memsize(int size) {
367  int k;
368
369  if (qhmem .LASTsize) {
370    qh_fprintf(qhmem.ferr, 6089, "qhull error (qh_memsize): called after qhmem_setup\n");
371    qh_errexit(qhmem_ERRqhull, NULL, NULL);
372  }
373  size= (size + qhmem.ALIGNmask) & ~qhmem.ALIGNmask;
374  for (k=qhmem.TABLEsize; k--; ) {
375    if (qhmem.sizetable[k] == size)
376      return;
377  }
378  if (qhmem.TABLEsize < qhmem.NUMsizes)
379    qhmem.sizetable[qhmem.TABLEsize++]= size;
380  else
381    qh_fprintf(qhmem.ferr, 7060, "qhull warning (memsize): free list table has room for only %d sizes\n", qhmem.NUMsizes);
382} /* memsize */
383
384
385/*-<a                             href="qh-mem.htm#TOC"
386  >-------------------------------</a><a name="memstatistics">-</a>
387
388  qh_memstatistics( fp )
389    print out memory statistics
390
391    Verifies that qhmem.totfree == sum of freelists
392*/
393void qh_memstatistics(FILE *fp) {
394  int i, count, totfree= 0;
395  void *object;
396
397  for (i=0; i < qhmem.TABLEsize; i++) {
398    count=0;
399    for (object= qhmem .freelists[i]; object; object= *((void **)object))
400      count++;
401    totfree += qhmem.sizetable[i] * count;
402  }
403  if (totfree != qhmem .totfree) {
404      qh_fprintf(qhmem.ferr, 6211, "qh_memstatistics internal error: totfree %d not equal to freelist total %d\n", qhmem.totfree, totfree);
405      qh_errexit(qhmem_ERRqhull, NULL, NULL);
406  }
407  qh_fprintf(fp, 9278, "\nmemory statistics:\n\
408%7d quick allocations\n\
409%7d short allocations\n\
410%7d long allocations\n\
411%7d short frees\n\
412%7d long frees\n\
413%7d bytes of short memory in use\n\
414%7d bytes of short memory in freelists\n\
415%7d bytes of dropped short memory\n\
416%7d bytes of unused short memory (estimated)\n\
417%7d bytes of long memory allocated (max, except for input)\n\
418%7d bytes of long memory in use (in %d pieces)\n\
419%7d bytes of short memory buffers (minus links)\n\
420%7d bytes per short memory buffer (initially %d bytes)\n",
421           qhmem .cntquick, qhmem .cntshort, qhmem .cntlong,
422           qhmem .freeshort, qhmem .freelong,
423           qhmem .totshort, qhmem .totfree,
424           qhmem .totdropped + qhmem .freesize, qhmem .totunused,
425           qhmem .maxlong, qhmem .totlong, qhmem .cntlong - qhmem .freelong,
426           qhmem .totbuffer, qhmem .BUFsize, qhmem .BUFinit);
427  if (qhmem.cntlarger) {
428    qh_fprintf(fp, 9279, "%7d calls to qh_setlarger\n%7.2g     average copy size\n",
429           qhmem.cntlarger, ((float)qhmem.totlarger)/(float)qhmem.cntlarger);
430    qh_fprintf(fp, 9280, "  freelists(bytes->count):");
431  }
432  for (i=0; i < qhmem.TABLEsize; i++) {
433    count=0;
434    for (object= qhmem .freelists[i]; object; object= *((void **)object))
435      count++;
436    qh_fprintf(fp, 9281, " %d->%d", qhmem.sizetable[i], count);
437  }
438  qh_fprintf(fp, 9282, "\n\n");
439} /* memstatistics */
440
441
442/*-<a                             href="qh-mem.htm#TOC"
443  >-------------------------------</a><a name="NOmem">-</a>
444
445  qh_NOmem
446    turn off quick-fit memory allocation
447
448  notes:
449    uses qh_malloc() and qh_free() instead
450*/
451#else /* qh_NOmem */
452
453void *qh_memalloc(int insize) {
454  void *object;
455
456  if (!(object= qh_malloc((size_t)insize))) {
457    qh_fprintf(qhmem.ferr, 6090, "qhull error (qh_memalloc): insufficient memory\n");
458    qh_errexit(qhmem_ERRmem, NULL, NULL);
459  }
460  qhmem .cntlong++;
461  qhmem .totlong += insize;
462  if (qhmem.maxlong < qhmem.totlong)
463      qhmem.maxlong= qhmem.totlong;
464  if (qhmem.IStracing >= 5)
465    qh_fprintf(qhmem.ferr, 8060, "qh_mem %p n %8d alloc long: %d bytes (tot %d cnt %d)\n", object, qhmem.cntlong+qhmem.freelong, insize, qhmem.totlong, qhmem.cntlong-qhmem.freelong);
466  return object;
467}
468
469void qh_memfree(void *object, int insize) {
470
471  if (!object)
472    return;
473  qh_free(object);
474  qhmem .freelong++;
475  qhmem .totlong -= insize;
476  if (qhmem.IStracing >= 5)
477    qh_fprintf(qhmem.ferr, 8061, "qh_mem %p n %8d free long: %d bytes (tot %d cnt %d)\n", object, qhmem.cntlong+qhmem.freelong, insize, qhmem.totlong, qhmem.cntlong-qhmem.freelong);
478}
479
480void qh_memfreeshort(int *curlong, int *totlong) {
481  *totlong= qhmem .totlong;
482  *curlong= qhmem .cntlong - qhmem .freelong;
483  memset((char *)&qhmem, 0, sizeof(qhmem));  /* every field is 0, FALSE, NULL */
484}
485
486void qh_meminit(FILE *ferr) {
487
488  memset((char *)&qhmem, 0, sizeof(qhmem));  /* every field is 0, FALSE, NULL */
489  qhmem.ferr= ferr;
490  if (sizeof(void*) < sizeof(int)) {
491    qh_fprintf(ferr, 6091, "qhull internal error (qh_meminit): sizeof(void*) %d < sizeof(int) %d.  qset.c will not work\n", (int)sizeof(void*), (int)sizeof(int));
492    qh_errexit(qhmem_ERRqhull, NULL, NULL);
493  }
494}
495
496void qh_meminitbuffers(int tracelevel, int alignment, int numsizes, int bufsize, int bufinit) {
497
498  qhmem.IStracing= tracelevel;
499}
500
501void qh_memsetup(void) {
502
503}
504
505void qh_memsize(int size) {
506
507}
508
509void qh_memstatistics(FILE *fp) {
510
511  qh_fprintf(fp, 9409, "\nmemory statistics:\n\
512%7d long allocations\n\
513%7d long frees\n\
514%7d bytes of long memory allocated (max, except for input)\n\
515%7d bytes of long memory in use (in %d pieces)\n",
516           qhmem .cntlong,
517           qhmem .freelong,
518           qhmem .maxlong, qhmem .totlong, qhmem .cntlong - qhmem .freelong);
519}
520
521#endif /* qh_NOmem */
522
523/*-<a                             href="qh-mem.htm#TOC"
524>-------------------------------</a><a name="memtotlong">-</a>
525
526  qh_memtotal( totlong, curlong, totshort, curshort, maxlong, totbuffer )
527    Return the total, allocated long and short memory
528
529  returns:
530    Returns the total current bytes of long and short allocations
531    Returns the current count of long and short allocations
532    Returns the maximum long memory and total short buffer (minus one link per buffer)
533    Does not error (UsingLibQhull.cpp)
534*/
535void qh_memtotal(int *totlong, int *curlong, int *totshort, int *curshort, int *maxlong, int *totbuffer) {
536    *totlong= qhmem .totlong;
537    *curlong= qhmem .cntlong - qhmem .freelong;
538    *totshort= qhmem .totshort;
539    *curshort= qhmem .cntshort + qhmem .cntquick - qhmem .freeshort;
540    *maxlong= qhmem .maxlong;
541    *totbuffer= qhmem .totbuffer;
542} /* memtotlong */
543
Note: See TracBrowser for help on using the repository browser.