Leptonica  1.77.0
Image processing and image analysis suite
pixalloc.c
Go to the documentation of this file.
1 /*====================================================================*
2  - Copyright (C) 2001 Leptonica. All rights reserved.
3  -
4  - Redistribution and use in source and binary forms, with or without
5  - modification, are permitted provided that the following conditions
6  - are met:
7  - 1. Redistributions of source code must retain the above copyright
8  - notice, this list of conditions and the following disclaimer.
9  - 2. Redistributions in binary form must reproduce the above
10  - copyright notice, this list of conditions and the following
11  - disclaimer in the documentation and/or other materials
12  - provided with the distribution.
13  -
14  - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
15  - ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
16  - LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
17  - A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL ANY
18  - CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
19  - EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
20  - PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
21  - PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
22  - OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
23  - NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
24  - SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25  *====================================================================*/
26 
44 #include "allheaders.h"
45 
46 /*-------------------------------------------------------------------------*
47  * Pix Memory Storage *
48  * *
49  * This is a simple utility for handling pix memory storage. It is *
50  * enabled by setting the PixMemoryManager allocators to the functions *
51  * that are defined here *
52  * pmsCustomAlloc() *
53  * pmsCustomDealloc() *
54  * Use pmsCreate() at the beginning to do the pre-allocation, and *
55  * pmsDestroy() at the end to clean it up. *
56  *-------------------------------------------------------------------------*/
57 /*
58  * In the following, the "memory" refers to the image data
59  * field that is used within the pix. The memory store is a
60  * continuous block of memory, that is logically divided into
61  * smaller "chunks" starting with a set at a minimum size, and
62  * followed by sets of increasing size that are a power of 2 larger
63  * than the minimum size. You must specify the number of chunks
64  * of each size.
65  *
66  * A requested data chunk, if it exists, is borrowed from the memory
67  * storage, and returned after use. If the chunk is too small, or
68  * too large, or if all chunks in the appropriate size range are
69  * in use, the memory is allocated dynamically and freed after use.
70  *
71  * There are four parameters that determine the use of pre-allocated memory:
72  *
73  * minsize: any requested chunk smaller than this is allocated
74  * dynamically and destroyed after use. No preallocated
75  * memory is used.
76  * smallest: the size of the smallest pre-allocated memory chunk.
77  * nlevels: the number of different sizes of data chunks, each a
78  * power of 2 larger than 'smallest'.
79  * numalloc: a Numa of size 'nlevels' containing the number of data
80  * chunks for each size that are in the memory store.
81  *
82  * As an example, suppose:
83  * minsize = 0.5MB
84  * smallest = 1.0MB
85  * nlevels = 4
86  * numalloc = {10, 5, 5, 5}
87  * Then the total amount of allocated memory (in MB) is
88  * 10 * 1 + 5 * 2 + 5 * 4 + 5 * 8 = 80 MB
89  * Any pix requiring less than 0.5 MB or more than 8 MB of memory will
90  * not come from the memory store. Instead, it will be dynamically
91  * allocated and freed after use.
92  *
93  * How is this implemented?
94  *
95  * At setup, the full data block size is computed and allocated.
96  * The addresses of the individual chunks are found, and the pointers
97  * are stored in a set of Ptra (generic pointer arrays), using one Ptra
98  * for each of the sizes of the chunks. When returning a chunk after
99  * use, it is necessary to determine from the address which size level
100  * (ptra) the chunk belongs to. This is done by comparing the address
101  * of the associated chunk.
102  *
103  * In the event that memory chunks need to be dynamically allocated,
104  * either (1) because they are too small or too large for the memory
105  * store or (2) because all the pix of that size (i.e., in the
106  * appropriate level) in the memory store are in use, the
107  * addresses generated will be outside the pre-allocated block.
108  * After use they won't be returned to a ptra; instead the deallocator
109  * will free them.
110  */
111 
114 {
115  struct L_Ptraa *paa;
116  size_t minsize;
118  size_t smallest;
119  size_t largest;
120  size_t nbytes;
121  l_int32 nlevels;
122  size_t *sizes;
123  l_int32 *allocarray;
124  l_uint32 *baseptr;
125  l_uint32 *maxptr;
126  l_uint32 **firstptr;
127  l_int32 *memused;
128  l_int32 *meminuse;
129  l_int32 *memmax;
130  l_int32 *memempty;
132  char *logfile;
133 };
134 typedef struct PixMemoryStore L_PIX_MEM_STORE;
135 
136 static L_PIX_MEM_STORE *CustomPMS = NULL;
137 
138 
167 l_ok
169  size_t smallest,
170  NUMA *numalloc,
171  const char *logfile)
172 {
173 l_int32 nlevels, i, j, nbytes;
174 l_int32 *alloca;
175 l_float32 nchunks;
176 l_uint32 *baseptr, *data;
177 l_uint32 **firstptr;
178 size_t *sizes;
179 L_PIX_MEM_STORE *pms;
180 L_PTRA *pa;
181 L_PTRAA *paa;
182 
183  PROCNAME("createPMS");
184 
185  if (!numalloc)
186  return ERROR_INT("numalloc not defined", procName, 1);
187  numaGetSum(numalloc, &nchunks);
188  if (nchunks > 1000.0)
189  L_WARNING("There are %.0f chunks\n", procName, nchunks);
190 
191  if ((pms = (L_PIX_MEM_STORE *)LEPT_CALLOC(1, sizeof(L_PIX_MEM_STORE)))
192  == NULL)
193  return ERROR_INT("pms not made", procName, 1);
194  CustomPMS = pms;
195 
196  /* Make sure that minsize and smallest are multiples of 32 bit words */
197  if (minsize % 4 != 0)
198  minsize -= minsize % 4;
199  pms->minsize = minsize;
200  nlevels = numaGetCount(numalloc);
201  pms->nlevels = nlevels;
202 
203  if ((sizes = (size_t *)LEPT_CALLOC(nlevels, sizeof(size_t))) == NULL)
204  return ERROR_INT("sizes not made", procName, 1);
205  pms->sizes = sizes;
206  if (smallest % 4 != 0)
207  smallest += 4 - (smallest % 4);
208  pms->smallest = smallest;
209  for (i = 0; i < nlevels; i++)
210  sizes[i] = smallest * (1 << i);
211  pms->largest = sizes[nlevels - 1];
212 
213  alloca = numaGetIArray(numalloc);
214  pms->allocarray = alloca;
215  if ((paa = ptraaCreate(nlevels)) == NULL)
216  return ERROR_INT("paa not made", procName, 1);
217  pms->paa = paa;
218 
219  for (i = 0, nbytes = 0; i < nlevels; i++)
220  nbytes += alloca[i] * sizes[i];
221  pms->nbytes = nbytes;
222 
223  if ((baseptr = (l_uint32 *)LEPT_CALLOC(nbytes / 4, sizeof(l_uint32)))
224  == NULL)
225  return ERROR_INT("calloc fail for baseptr", procName, 1);
226  pms->baseptr = baseptr;
227  pms->maxptr = baseptr + nbytes / 4; /* just beyond the memory store */
228  if ((firstptr = (l_uint32 **)LEPT_CALLOC(nlevels, sizeof(l_uint32 *)))
229  == NULL)
230  return ERROR_INT("calloc fail for firstptr", procName, 1);
231  pms->firstptr = firstptr;
232 
233  data = baseptr;
234  for (i = 0; i < nlevels; i++) {
235  if ((pa = ptraCreate(alloca[i])) == NULL)
236  return ERROR_INT("pa not made", procName, 1);
237  ptraaInsertPtra(paa, i, pa);
238  firstptr[i] = data;
239  for (j = 0; j < alloca[i]; j++) {
240  ptraAdd(pa, data);
241  data += sizes[i] / 4;
242  }
243  }
244 
245  if (logfile) {
246  pms->memused = (l_int32 *)LEPT_CALLOC(nlevels, sizeof(l_int32));
247  pms->meminuse = (l_int32 *)LEPT_CALLOC(nlevels, sizeof(l_int32));
248  pms->memmax = (l_int32 *)LEPT_CALLOC(nlevels, sizeof(l_int32));
249  pms->memempty = (l_int32 *)LEPT_CALLOC(nlevels, sizeof(l_int32));
250  pms->logfile = stringNew(logfile);
251  }
252 
253  return 0;
254 }
255 
256 
266 void
268 {
269 L_PIX_MEM_STORE *pms;
270 
271  if ((pms = CustomPMS) == NULL)
272  return;
273 
274  ptraaDestroy(&pms->paa, FALSE, FALSE); /* don't touch the ptrs */
275  LEPT_FREE(pms->baseptr); /* free the memory */
276 
277  if (pms->logfile) {
278  pmsLogInfo();
279  LEPT_FREE(pms->logfile);
280  LEPT_FREE(pms->memused);
281  LEPT_FREE(pms->meminuse);
282  LEPT_FREE(pms->memmax);
283  LEPT_FREE(pms->memempty);
284  }
285 
286  LEPT_FREE(pms->sizes);
287  LEPT_FREE(pms->allocarray);
288  LEPT_FREE(pms->firstptr);
289  LEPT_FREE(pms);
290  CustomPMS = NULL;
291  return;
292 }
293 
294 
310 void *
312 {
313 l_int32 level;
314 void *data;
315 L_PIX_MEM_STORE *pms;
316 L_PTRA *pa;
317 
318  PROCNAME("pmsCustomAlloc");
319 
320  if ((pms = CustomPMS) == NULL)
321  return (void *)ERROR_PTR("pms not defined", procName, NULL);
322 
323  pmsGetLevelForAlloc(nbytes, &level);
324 
325  if (level < 0) { /* size range invalid; must alloc */
326  if ((data = pmsGetAlloc(nbytes)) == NULL)
327  return (void *)ERROR_PTR("data not made", procName, NULL);
328  } else { /* get from store */
329  pa = ptraaGetPtra(pms->paa, level, L_HANDLE_ONLY);
330  data = ptraRemoveLast(pa);
331  if (data && pms->logfile) {
332  pms->memused[level]++;
333  pms->meminuse[level]++;
334  if (pms->meminuse[level] > pms->memmax[level])
335  pms->memmax[level]++;
336  }
337  if (!data) { /* none left at this level */
338  data = pmsGetAlloc(nbytes);
339  if (pms->logfile)
340  pms->memempty[level]++;
341  }
342  }
343 
344  return data;
345 }
346 
347 
354 void
355 pmsCustomDealloc(void *data)
356 {
357 l_int32 level;
358 L_PIX_MEM_STORE *pms;
359 L_PTRA *pa;
360 
361  PROCNAME("pmsCustomDealloc");
362 
363  if ((pms = CustomPMS) == NULL) {
364  L_ERROR("pms not defined\n", procName);
365  return;
366  }
367 
368  if (pmsGetLevelForDealloc(data, &level) == 1) {
369  L_ERROR("level not found\n", procName);
370  return;
371  }
372 
373  if (level < 0) { /* no logging; just free the data */
374  LEPT_FREE(data);
375  } else { /* return the data to the store */
376  pa = ptraaGetPtra(pms->paa, level, L_HANDLE_ONLY);
377  ptraAdd(pa, data);
378  if (pms->logfile)
379  pms->meminuse[level]--;
380  }
381 
382  return;
383 }
384 
385 
405 void *
407 {
408 void *data;
409 FILE *fp;
410 L_PIX_MEM_STORE *pms;
411 
412  PROCNAME("pmsGetAlloc");
413 
414  if ((pms = CustomPMS) == NULL)
415  return (void *)ERROR_PTR("pms not defined", procName, NULL);
416 
417  if ((data = (void *)LEPT_CALLOC(nbytes, sizeof(char))) == NULL)
418  return (void *)ERROR_PTR("data not made", procName, NULL);
419  if (pms->logfile && nbytes >= pms->smallest) {
420  fp = fopenWriteStream(pms->logfile, "a");
421  fprintf(fp, "Alloc %lu bytes at %p\n", (unsigned long)nbytes, data);
422  fclose(fp);
423  }
424 
425  return data;
426 }
427 
428 
436 l_ok
438  l_int32 *plevel)
439 {
440 l_int32 i;
441 l_float64 ratio;
442 L_PIX_MEM_STORE *pms;
443 
444  PROCNAME("pmsGetLevelForAlloc");
445 
446  if (!plevel)
447  return ERROR_INT("&level not defined", procName, 1);
448  *plevel = -1;
449  if ((pms = CustomPMS) == NULL)
450  return ERROR_INT("pms not defined", procName, 1);
451 
452  if (nbytes < pms->minsize || nbytes > pms->largest)
453  return 0; /* -1 */
454 
455  ratio = (l_float64)nbytes / (l_float64)(pms->smallest);
456  for (i = 0; i < pms->nlevels; i++) {
457  if (ratio <= 1.0)
458  break;
459  ratio /= 2.0;
460  }
461  *plevel = i;
462 
463  return 0;
464 }
465 
466 
475 l_ok
477  l_int32 *plevel)
478 {
479 l_int32 i;
480 l_uint32 *first;
481 L_PIX_MEM_STORE *pms;
482 
483  PROCNAME("pmsGetLevelForDealloc");
484 
485  if (!plevel)
486  return ERROR_INT("&level not defined", procName, 1);
487  *plevel = -1;
488  if (!data)
489  return ERROR_INT("data not defined", procName, 1);
490  if ((pms = CustomPMS) == NULL)
491  return ERROR_INT("pms not defined", procName, 1);
492 
493  if (data < (void *)pms->baseptr || data >= (void *)pms->maxptr)
494  return 0; /* -1 */
495 
496  for (i = 1; i < pms->nlevels; i++) {
497  first = pms->firstptr[i];
498  if (data < (void *)first)
499  break;
500  }
501  *plevel = i - 1;
502 
503  return 0;
504 }
505 
506 
510 void
512 {
513 l_int32 i;
514 L_PIX_MEM_STORE *pms;
515 
516  if ((pms = CustomPMS) == NULL)
517  return;
518 
519  fprintf(stderr, "Total number of pix used at each level\n");
520  for (i = 0; i < pms->nlevels; i++)
521  fprintf(stderr, " Level %d (%lu bytes): %d\n", i,
522  (unsigned long)pms->sizes[i], pms->memused[i]);
523 
524  fprintf(stderr, "Max number of pix in use at any time in each level\n");
525  for (i = 0; i < pms->nlevels; i++)
526  fprintf(stderr, " Level %d (%lu bytes): %d\n", i,
527  (unsigned long)pms->sizes[i], pms->memmax[i]);
528 
529  fprintf(stderr, "Number of pix alloc'd because none were available\n");
530  for (i = 0; i < pms->nlevels; i++)
531  fprintf(stderr, " Level %d (%lu bytes): %d\n", i,
532  (unsigned long)pms->sizes[i], pms->memempty[i]);
533 
534  return;
535 }
l_ok numaGetSum(NUMA *na, l_float32 *psum)
numaGetSum()
Definition: numafunc1.c:527
size_t minsize
Definition: pixalloc.c:116
char * logfile
Definition: pixalloc.c:132
void ptraaDestroy(L_PTRAA **ppaa, l_int32 freeflag, l_int32 warnflag)
ptraaDestroy()
Definition: ptra.c:826
size_t smallest
Definition: pixalloc.c:118
char * stringNew(const char *src)
stringNew()
Definition: utils2.c:215
l_uint32 * maxptr
Definition: pixalloc.c:125
size_t nbytes
Definition: pixalloc.c:120
void * pmsCustomAlloc(size_t nbytes)
pmsCustomAlloc()
Definition: pixalloc.c:311
void pmsCustomDealloc(void *data)
pmsCustomDealloc()
Definition: pixalloc.c:355
size_t * sizes
Definition: pixalloc.c:122
void * ptraRemoveLast(L_PTRA *pa)
ptraRemoveLast()
Definition: ptra.c:483
l_ok pmsGetLevelForAlloc(size_t nbytes, l_int32 *plevel)
pmsGetLevelForAlloc()
Definition: pixalloc.c:437
l_int32 * numaGetIArray(NUMA *na)
numaGetIArray()
Definition: numabasic.c:820
Definition: array.h:59
L_PTRA * ptraCreate(l_int32 n)
ptraCreate()
Definition: ptra.c:139
l_int32 numaGetCount(NUMA *na)
numaGetCount()
Definition: numabasic.c:631
L_PTRA * ptraaGetPtra(L_PTRAA *paa, l_int32 index, l_int32 accessflag)
ptraaGetPtra()
Definition: ptra.c:941
l_ok ptraaInsertPtra(L_PTRAA *paa, l_int32 index, L_PTRA *pa)
ptraaInsertPtra()
Definition: ptra.c:898
l_int32 nlevels
Definition: pixalloc.c:121
l_int32 * memused
Definition: pixalloc.c:127
void pmsLogInfo()
pmsLogInfo()
Definition: pixalloc.c:511
Definition: ptra.h:51
l_int32 * allocarray
Definition: pixalloc.c:123
struct L_Ptraa * paa
Definition: pixalloc.c:115
l_ok pmsCreate(size_t minsize, size_t smallest, NUMA *numalloc, const char *logfile)
pmsCreate()
Definition: pixalloc.c:168
void * pmsGetAlloc(size_t nbytes)
pmsGetAlloc()
Definition: pixalloc.c:406
l_int32 * meminuse
Definition: pixalloc.c:128
l_uint32 ** firstptr
Definition: pixalloc.c:126
FILE * fopenWriteStream(const char *filename, const char *modestring)
fopenWriteStream()
Definition: utils2.c:1700
l_ok ptraAdd(L_PTRA *pa, void *item)
ptraAdd()
Definition: ptra.c:242
void pmsDestroy()
pmsDestroy()
Definition: pixalloc.c:267
l_uint32 * baseptr
Definition: pixalloc.c:124
l_int32 * memempty
Definition: pixalloc.c:130
l_int32 * memmax
Definition: pixalloc.c:129
Definition: ptra.h:62
l_ok pmsGetLevelForDealloc(void *data, l_int32 *plevel)
pmsGetLevelForDealloc()
Definition: pixalloc.c:476
L_PTRAA * ptraaCreate(l_int32 n)
ptraaCreate()
Definition: ptra.c:790
size_t largest
Definition: pixalloc.c:119