Scippy

SCIP

Solving Constraint Integer Programs

memory.c
Go to the documentation of this file.
1/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2/* */
3/* This file is part of the library */
4/* BMS --- Block Memory Shell */
5/* */
6/* Copyright (c) 2002-2025 Zuse Institute Berlin (ZIB) */
7/* */
8/* Licensed under the Apache License, Version 2.0 (the "License"); */
9/* you may not use this file except in compliance with the License. */
10/* You may obtain a copy of the License at */
11/* */
12/* http://www.apache.org/licenses/LICENSE-2.0 */
13/* */
14/* Unless required by applicable law or agreed to in writing, software */
15/* distributed under the License is distributed on an "AS IS" BASIS, */
16/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. */
17/* See the License for the specific language governing permissions and */
18/* limitations under the License. */
19/* */
20/* You should have received a copy of the Apache-2.0 license */
21/* along with SCIP; see the file LICENSE. If not visit scipopt.org. */
22/* */
23/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
24
25/**@file memory.c
26 * @ingroup OTHER_CFILES
27 * @brief memory allocation routines
28 * @author Tobias Achterberg
29 * @author Gerald Gamrath
30 * @author Marc Pfetsch
31 * @author Jakob Witzig
32 */
33
34/*---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0----+----1----+----2*/
35
36#ifdef __cplusplus
37#define __STDC_LIMIT_MACROS
38#endif
39
40#include <stdio.h>
41#include <stdlib.h>
42#include <assert.h>
43#include <string.h>
44
45/*
46 * include build configuration flags
47 */
48#include "scip/config.h"
49
50#ifdef WITH_SCIPDEF
51#include "scip/def.h"
52#include "scip/pub_message.h"
53#else
54#include <stdint.h>
55#endif
56
58#include "scip/rbtree.h"
59
60/* uncomment the following to enable the use of a memlist in debug mode
61 * that checks for some memory leaks and allows to add the additional
62 * checks enabled with the defines below.
63 * The maintenance of the memlist, however, is not threadsafe.
64 */
65#ifndef SCIP_THREADSAFE
66/*#define ENABLE_MEMLIST_CHECKS*/
67#endif
68
69#ifdef ENABLE_MEMLIST_CHECKS
70/* uncomment the following for debugging:
71 * - CHECKMEM: run a thorough test on every memory function call, very slow
72 * - CHECKCHKFREE: check for the presence of a pointer in a chunk block
73 */
74/*#define CHECKMEM*/
75/*#define CHECKCHKFREE*/
76#endif
77
78/* Uncomment the following for checks that clean buffer is really clean when being freed. */
79/* #define CHECKCLEANBUFFER */
80
81/* Uncomment the following for a warnings if buffers are not freed in the reverse order of allocation. */
82/* #define CHECKBUFFERORDER */
83
84/* if we are included in SCIP, use SCIP's message output methods */
85#ifdef SCIPdebugMessage
86#define debugMessage SCIPdebugMessage
87#define errorMessage SCIPerrorMessage
88#else
89#define debugMessage while( FALSE ) printf
90#define errorMessage printf
91#define printErrorHeader(f,l) printf("[%s:%d] ERROR: ", f, l)
92#define printError printf
93#endif
94
95#ifdef ENABLE_MEMLIST_CHECKS
96#define warningMessage printf
97#endif
98#define printInfo printf
99
100/* define some macros (if not already defined) */
101#ifndef FALSE
102#define FALSE 0
103#define TRUE 1
104#endif
105#ifndef MAX
106#define MAX(x,y) ((x) >= (y) ? (x) : (y))
107#define MIN(x,y) ((x) <= (y) ? (x) : (y))
108#endif
109
110#ifndef SCIP_LONGINT_FORMAT
111#if defined(_WIN32) || defined(_WIN64)
112#define LONGINT_FORMAT "I64d"
113#else
114#define LONGINT_FORMAT "lld"
115#endif
116#else
117#define LONGINT_FORMAT SCIP_LONGINT_FORMAT
118#endif
119
120#ifndef SCIP_MAXMEMSIZE
121/* we take SIZE_MAX / 2 to detect negative sizes which got a very large value when casting to (unsigned) size_t */
122#define MAXMEMSIZE SIZE_MAX / 2
123#else
124#define MAXMEMSIZE SCIP_MAXMEMSIZE
125#endif
126
127/* define inline (if not already defined) */
128#ifndef INLINE
129#if defined(_WIN32) || defined(_WIN64) || defined(__STDC__)
130#define INLINE __inline
131#else
132#define INLINE inline
133#endif
134#endif
135
136/*************************************************************************************
137 * Standard Memory Management
138 *
139 * In debug mode, these methods extend malloc() and free() by logging all currently
140 * allocated memory elements in an allocation list. This can be used as a simple leak
141 * detection.
142 *************************************************************************************/
143#if !defined(NDEBUG) && defined(ENABLE_MEMLIST_CHECKS)
144
145typedef struct Memlist MEMLIST; /**< memory list for debugging purposes */
146
147/** memory list for debugging purposes */
148struct Memlist
149{
150 const void* ptr; /**< pointer to allocated memory */
151 size_t size; /**< size of memory element */
152 char* filename; /**< source file where the allocation was performed */
153 int line; /**< line number in source file where the allocation was performed */
154 MEMLIST* next; /**< next entry in the memory list */
155};
156
157static MEMLIST* memlist = NULL; /**< global memory list for debugging purposes */
158static size_t memused = 0; /**< number of allocated bytes */
159
160#ifdef CHECKMEM
161/** checks, whether the number of allocated bytes match the entries in the memory list */
162static
163void checkMemlist(
164 void
165 )
166{
167 MEMLIST* list = memlist;
168 size_t used = 0;
169
170 while( list != NULL )
171 {
172 used += list->size;
173 list = list->next;
174 }
175 assert(used == memused);
176}
177#else
178#define checkMemlist() /**/
179#endif
180
181/** adds entry to list of allocated memory */
182static
183void addMemlistEntry(
184 const void* ptr, /**< pointer to allocated memory */
185 size_t size, /**< size of memory element */
186 const char* filename, /**< source file where the allocation was performed */
187 int line /**< line number in source file where the allocation was performed */
188 )
189{
190 MEMLIST* list;
191
192 assert(ptr != NULL && size > 0);
193
194 list = (MEMLIST*)malloc(sizeof(MEMLIST));
195 assert(list != NULL);
196
197 list->ptr = ptr;
198 list->size = size;
199 list->filename = strdup(filename);
200 assert(list->filename != NULL);
201 list->line = line;
202 list->next = memlist;
203 memlist = list;
204 memused += size;
205 checkMemlist();
206}
207
208/** removes entry from the list of allocated memory */
209static
211 const void* ptr, /**< pointer to allocated memory */
212 const char* filename, /**< source file where the deallocation was performed */
213 int line /**< line number in source file where the deallocation was performed */
214 )
215{
216 MEMLIST* list;
217 MEMLIST** listptr;
218
219 assert(ptr != NULL);
220
221 list = memlist;
222 listptr = &memlist;
223 while( list != NULL && ptr != list->ptr )
224 {
225 listptr = &(list->next);
226 list = list->next;
227 }
228 if( list != NULL )
229 {
230 assert(ptr == list->ptr);
231
232 *listptr = list->next;
233 assert( list->size <= memused );
234 memused -= list->size;
235 free(list->filename);
236 free(list);
237 }
238 else
239 {
240 printErrorHeader(filename, line);
241 printError("Tried to free unknown pointer <%p>.\n", ptr);
242 }
243 checkMemlist();
244}
245
246/** returns the size of an allocated memory element */
248 const void* ptr /**< pointer to allocated memory */
249 )
250{
251 MEMLIST* list;
252
253 list = memlist;
254 while( list != NULL && ptr != list->ptr )
255 list = list->next;
256 if( list != NULL )
257 return list->size;
258 else
259 return 0;
260}
261
262/** outputs information about currently allocated memory to the screen */
264 void
265 )
266{
267 MEMLIST* list;
268 size_t used = 0;
269
270 printInfo("Allocated memory:\n");
271 list = memlist;
272 while( list != NULL )
273 {
274 printInfo("%12p %8llu %s:%d\n", list->ptr, (unsigned long long) list->size, list->filename, list->line);
275 used += list->size;
276 list = list->next;
277 }
278 printInfo("Total: %8llu\n", (unsigned long long) memused);
279 if( used != memused )
280 {
281 errorMessage("Used memory in list sums up to %llu instead of %llu\n", (unsigned long long)used, (unsigned long long)memused);
282 }
283 checkMemlist();
284}
285
286/** displays a warning message on the screen, if allocated memory exists */
288 void
289 )
290{
291 if( memlist != NULL || memused > 0 )
292 {
293 warningMessage("Memory list not empty.\n");
295 }
296}
297
298/** returns total number of allocated bytes */
299long long BMSgetMemoryUsed_call(
300 void
301 )
302{
303 return (long long) memused;
304}
305
306#else
307
308#define addMemlistEntry(ptr, size, filename, line) do { (void) (ptr); (void) (size); (void) (filename); (void) (line); } while(0)
309#define removeMemlistEntry(ptr, filename, line) do { (void) (ptr); (void) (filename); (void) (line); } while(0)
310
311/* these methods are implemented even in optimized mode, such that a program, that includes memory.h in debug mode
312 * but links the optimized version compiles
313 */
314
315/** returns the size of an allocated memory element */
317 const void* ptr /**< pointer to allocated memory */
318 )
319{
320 (void) ptr;
321 return 0;
322}
323
324/** outputs information about currently allocated memory to the screen */
326 void
327 )
328{
329 printInfo("Optimized, threadsafe version of memory shell linked - no memory diagnostics available.\n");
330}
331
332/** displays a warning message on the screen, if allocated memory exists */
334 void
335 )
336{
337}
338
339/** returns total number of allocated bytes */
341 void
342 )
343{
344 return 0;
345}
346
347#endif
348
349/** allocates array and initializes it with 0; returns NULL if memory allocation failed */
351 size_t num, /**< number of memory element to allocate */
352 size_t typesize, /**< size of one memory element to allocate */
353 const char* filename, /**< source file where the allocation is performed */
354 int line /**< line number in source file where the allocation is performed */
355 )
356{
357 void* ptr;
358
359 assert(typesize > 0);
360
361 debugMessage("calloc %llu elements of %llu bytes [%s:%d]\n", (unsigned long long)num, (unsigned long long)typesize,
362 filename, line);
363
364#ifndef NDEBUG
365 if ( num > (MAXMEMSIZE / typesize) )
366 {
367 printErrorHeader(filename, line);
368 printError("Tried to allocate standard memory of size exceeding %lu.\n", MAXMEMSIZE);
369 return NULL;
370 }
371#endif
372
373 num = MAX(num, 1);
374 typesize = MAX(typesize, 1);
375 ptr = calloc(num, typesize);
376
377 if( ptr == NULL )
378 {
379 printErrorHeader(filename, line);
380 printError("Insufficient memory for allocation of %llu bytes.\n", (unsigned long long)(num) * (typesize));
381 }
382 else
383 addMemlistEntry(ptr, num*typesize, filename, line);
384
385 return ptr;
386}
387
388/** allocates memory; returns NULL if memory allocation failed */
390 size_t size, /**< size of memory element to allocate */
391 const char* filename, /**< source file where the allocation is performed */
392 int line /**< line number in source file where the allocation is performed */
393 )
394{
395 void* ptr;
396
397 debugMessage("malloc %llu bytes [%s:%d]\n", (unsigned long long)size, filename, line);
398
399#ifndef NDEBUG
400 if ( size > MAXMEMSIZE )
401 {
402 printErrorHeader(filename, line);
403 printError("Tried to allocate standard memory of size exceeding %lu.\n", MAXMEMSIZE);
404 return NULL;
405 }
406#endif
407
408 size = MAX(size, 1);
409 ptr = malloc(size);
410
411 if( ptr == NULL )
412 {
413 printErrorHeader(filename, line);
414 printError("Insufficient memory for allocation of %llu bytes.\n", (unsigned long long)size);
415 }
416 else
417 addMemlistEntry(ptr, size, filename, line);
418
419 return ptr;
420}
421
422/** allocates array; returns NULL if memory allocation failed */
424 size_t num, /**< number of components of array to allocate */
425 size_t typesize, /**< size of each component */
426 const char* filename, /**< source file where the allocation is performed */
427 int line /**< line number in source file where the allocation is performed */
428 )
429{
430 void* ptr;
431 size_t size;
432
433 debugMessage("malloc %llu elements of %llu bytes [%s:%d]\n",
434 (unsigned long long)num, (unsigned long long)typesize, filename, line);
435
436#ifndef NDEBUG
437 if ( num > (MAXMEMSIZE / typesize) )
438 {
439 printErrorHeader(filename, line);
440 printError("Tried to allocate standard memory of size exceeding %lu.\n", MAXMEMSIZE);
441 return NULL;
442 }
443#endif
444
445 size = num * typesize;
446 size = MAX(size, 1);
447 ptr = malloc(size);
448
449 if( ptr == NULL )
450 {
451 printErrorHeader(filename, line);
452 printError("Insufficient memory for allocation of %llu bytes.\n", (unsigned long long)size);
453 }
454 else
455 addMemlistEntry(ptr, size, filename, line);
456
457 return ptr;
458}
459
460/** allocates memory; returns NULL if memory allocation failed */
462 void* ptr, /**< pointer to memory to reallocate */
463 size_t size, /**< new size of memory element */
464 const char* filename, /**< source file where the reallocation is performed */
465 int line /**< line number in source file where the reallocation is performed */
466 )
467{
468 void* newptr;
469
470 if( ptr != NULL )
471 removeMemlistEntry(ptr, filename, line);
472
473#ifndef NDEBUG
474 if ( size > MAXMEMSIZE )
475 {
476 printErrorHeader(filename, line);
477 printError("Tried to allocate standard memory of size exceeding %lu.\n", MAXMEMSIZE);
478 return NULL;
479 }
480#endif
481
482 size = MAX(size, 1);
483 newptr = realloc(ptr, size);
484
485 if( newptr == NULL )
486 {
487 printErrorHeader(filename, line);
488 printError("Insufficient memory for reallocation of %llu bytes.\n", (unsigned long long)size);
489 }
490 else
491 addMemlistEntry(newptr, size, filename, line);
492
493 return newptr;
494}
495
496/** reallocates array; returns NULL if memory allocation failed */
498 void* ptr, /**< pointer to memory to reallocate */
499 size_t num, /**< number of components of array to allocate */
500 size_t typesize, /**< size of each component */
501 const char* filename, /**< source file where the reallocation is performed */
502 int line /**< line number in source file where the reallocation is performed */
503 )
504{
505 void* newptr;
506 size_t size;
507
508 if( ptr != NULL )
509 removeMemlistEntry(ptr, filename, line);
510
511#ifndef NDEBUG
512 if ( num > (MAXMEMSIZE / typesize) )
513 {
514 printErrorHeader(filename, line);
515 printError("Tried to allocate standard memory of size exceeding %lu.\n", MAXMEMSIZE);
516 return NULL;
517 }
518#endif
519
520 size = num * typesize;
521 size = MAX(size, 1);
522 newptr = realloc(ptr, size);
523
524 if( newptr == NULL )
525 {
526 printErrorHeader(filename, line);
527 printError("Insufficient memory for reallocation of %llu bytes.\n", (unsigned long long)size);
528 }
529 else
530 addMemlistEntry(newptr, size, filename, line);
531
532 return newptr;
533}
534
535/** clears a memory element (i.e. fills it with zeros) */
537 void* ptr, /**< pointer to memory element */
538 size_t size /**< size of memory element */
539 )
540{
541 if( size > 0 )
542 {
543 assert(ptr != NULL);
544 memset(ptr, 0, size);
545 }
546}
547
548/** copies the contents of one memory element into another memory element */
550 void* ptr, /**< pointer to target memory element */
551 const void* source, /**< pointer to source memory element */
552 size_t size /**< size of memory element to copy */
553 )
554{
555 if( size > 0 )
556 {
557 assert(ptr != NULL);
558 assert(source != NULL);
559 memcpy(ptr, source, size);
560 }
561}
562
563/** moves the contents of one memory element into another memory element, should be used if both elements overlap,
564 * otherwise BMScopyMemory is faster
565 */
567 void* ptr, /**< pointer to target memory element */
568 const void* source, /**< pointer to source memory element */
569 size_t size /**< size of memory element to copy */
570 )
571{
572 if( size > 0 )
573 {
574 assert(ptr != NULL);
575 assert(source != NULL);
576 memmove(ptr, source, size);
577 }
578}
579
580/** allocates memory and copies the contents of the given memory element into the new memory element */
582 const void* source, /**< pointer to source memory element */
583 size_t size, /**< size of memory element to copy */
584 const char* filename, /**< source file where the duplication is performed */
585 int line /**< line number in source file where the duplication is performed */
586 )
587{
588 void* ptr;
589
590 assert(source != NULL || size == 0);
591
592 ptr = BMSallocMemory_call(size, filename, line);
593 if( ptr != NULL )
594 BMScopyMemory_call(ptr, source, size);
595
596 return ptr;
597}
598
599/** allocates array and copies the contents of the given source array into the new array */
601 const void* source, /**< pointer to source memory element */
602 size_t num, /**< number of components of array to allocate */
603 size_t typesize, /**< size of each component */
604 const char* filename, /**< source file where the duplication is performed */
605 int line /**< line number in source file where the duplication is performed */
606 )
607{
608 void* ptr;
609
610 assert(source != NULL || num == 0);
611
612 ptr = BMSallocMemoryArray_call(num, typesize, filename, line);
613 if( ptr != NULL )
614 BMScopyMemory_call(ptr, source, num * typesize);
615
616 return ptr;
617}
618
619/** frees an allocated memory element and sets pointer to NULL */
621 void** ptr, /**< pointer to pointer to memory element */
622 const char* filename, /**< source file where the deallocation is performed */
623 int line /**< line number in source file where the deallocation is performed */
624 )
625{
626 assert( ptr != NULL );
627 if( *ptr != NULL )
628 {
629 removeMemlistEntry(*ptr, filename, line);
630
631 free(*ptr);
632 *ptr = NULL;
633 }
634 else
635 {
636 printErrorHeader(filename, line);
637 printError("Tried to free null pointer.\n");
638 }
639}
640
641/** frees an allocated memory element if pointer is not NULL and sets pointer to NULL */
643 void** ptr, /**< pointer to pointer to memory element */
644 const char* filename, /**< source file where the deallocation is performed */
645 int line /**< line number in source file where the deallocation is performed */
646 )
647{
648 assert( ptr != NULL );
649 if ( *ptr != NULL )
650 {
651 removeMemlistEntry(*ptr, filename, line);
652
653 free(*ptr);
654 *ptr = NULL;
655 }
656}
657
658
659/***********************************************************
660 * Block Memory Management (forward declaration)
661 *
662 * Efficient memory management for objects of varying sizes
663 ***********************************************************/
664
665#define CHKHASH_POWER 10 /**< power for size of chunk block hash table */
666#define CHKHASH_SIZE (1<<CHKHASH_POWER) /**< size of chunk block hash table is 2^CHKHASH_POWER */
667
668/** collection of chunk blocks */
669struct BMS_BlkMem
670{
671 BMS_CHKMEM* chkmemhash[CHKHASH_SIZE]; /**< hash table with chunk blocks */
672 long long memused; /**< total number of used bytes in the memory header */
673 long long memallocated; /**< total number of allocated bytes in the memory header */
674 long long maxmemused; /**< maximal number of used bytes in the memory header */
675 long long maxmemunused; /**< maximal number of allocated but not used bytes in the memory header */
676 long long maxmemallocated; /**< maximal number of allocated bytes in the memory header */
677 int initchunksize; /**< number of elements in the first chunk of each chunk block */
678 int garbagefactor; /**< garbage collector is called, if at least garbagefactor * avg. chunksize
679 * elements are free (-1: disable garbage collection) */
680};
681
682
683/********************************************************************
684 * Chunk Memory Management
685 *
686 * Efficient memory management for multiple objects of the same size
687 ********************************************************************/
688
689/*
690 * block memory methods for faster memory access
691 */
692
693#define CHUNKLENGTH_MIN 1024 /**< minimal size of a chunk (in bytes) */
694#define CHUNKLENGTH_MAX 1048576 /**< maximal size of a chunk (in bytes) */
695#define STORESIZE_MAX 8192 /**< maximal number of elements in one chunk */
696#define GARBAGE_SIZE 256 /**< size of lazy free list to start garbage collection */
697#define ALIGNMENT (sizeof(FREELIST)) /**< minimal alignment of chunks */
698
699typedef struct Freelist FREELIST; /**< linked list of free memory elements */
700typedef struct Chunk CHUNK; /**< chunk of memory elements */
701
702/** linked list of free memory elements */
703struct Freelist
704{
705 FREELIST* next; /**< pointer to the next free element */
706};
707
708/** chunk of memory elements */
709struct Chunk
710{
711 SCIP_RBTREE_HOOKS; /**< organize chunks in a red black tree */ /*lint !e768 */
712 void* store; /**< data storage */
713 void* storeend; /**< points to the first byte in memory not belonging to the chunk */
714 FREELIST* eagerfree; /**< eager free list */
715 CHUNK* nexteager; /**< next chunk, that has a non-empty eager free list */
716 CHUNK* preveager; /**< previous chunk, that has a non-empty eager free list */
717 BMS_CHKMEM* chkmem; /**< chunk memory collection, this chunk belongs to */
718 int elemsize; /**< size of each element in the chunk */
719 int storesize; /**< number of elements in this chunk */
720 int eagerfreesize; /**< number of elements in the eager free list */
721}; /* the chunk data structure must be aligned, because the storage is allocated directly behind the chunk header! */
722
723/** collection of memory chunks of the same element size */
724struct BMS_ChkMem
725{
726 CHUNK* rootchunk; /**< array with the chunks of the chunk header */
727 FREELIST* lazyfree; /**< lazy free list of unused memory elements of all chunks of this chunk block */
728 CHUNK* firsteager; /**< first chunk with a non-empty eager free list */
729 BMS_CHKMEM* nextchkmem; /**< next chunk block in the block memory's hash list */
730 int elemsize; /**< size of each memory element in the chunk memory */
731 int nchunks; /**< number of chunks in this chunk block (used slots of the chunk array) */
732 int lastchunksize; /**< number of elements in the last allocated chunk */
733 int storesize; /**< total number of elements in this chunk block */
734 int lazyfreesize; /**< number of elements in the lazy free list of the chunk block */
735 int eagerfreesize; /**< total number of elements of all eager free lists of the block's chunks */
736 int initchunksize; /**< number of elements in the first chunk */
737 int garbagefactor; /**< garbage collector is called, if at least garbagefactor * avg. chunksize
738 * elements are free (-1: disable garbage collection) */
739#ifndef NDEBUG
740 char* filename; /**< source file, where this chunk block was created */
741 int line; /**< source line, where this chunk block was created */
742 int ngarbagecalls; /**< number of times, the garbage collector was called */
743 int ngarbagefrees; /**< number of chunks, the garbage collector freed */
744#endif
745};
746
747/* define a find function to find a chunk in a red black tree of chunks */
748#define CHUNK_LT(ptr,chunk) ptr < chunk->store
749#define CHUNK_GT(ptr,chunk) ptr >= chunk->storeend
750
751static
752SCIP_DEF_RBTREE_FIND(rbTreeFindChunk, const void*, CHUNK, CHUNK_LT, CHUNK_GT) /*lint !e123*/
753
754
755/** aligns the given byte size corresponding to the minimal alignment */
756static
757void alignSize(
758 size_t* size /**< pointer to the size to align */
759 )
760{
761 if( *size < ALIGNMENT )
762 *size = ALIGNMENT;
763 else
764 *size = ((*size + ALIGNMENT - 1) / ALIGNMENT) * ALIGNMENT;
765}
766
767/** aligns the given byte size corresponding to the minimal alignment for chunk and block memory */
769 size_t* size /**< pointer to the size to align */
770 )
771{
772 assert(ALIGNMENT == sizeof(void*)); /*lint !e506*/
773 alignSize(size);
774}
775
776/** checks whether the given size meets the alignment conditions for chunk and block memory */
778 size_t size /**< size to check for alignment */
779 )
780{
781 assert(ALIGNMENT == sizeof(void*)); /*lint !e506*/
782 return( size >= ALIGNMENT && size % ALIGNMENT == 0 );
783}
784
785#ifndef NDEBUG
786/** checks, if the given pointer belongs to the given chunk */
787static
789 const CHUNK* chunk, /**< memory chunk */
790 const void* ptr /**< pointer */
791 )
792{
793 assert(chunk != NULL);
794 assert(chunk->store <= chunk->storeend);
795
796 return (ptr >= (void*)(chunk->store) && ptr < (void*)(chunk->storeend));
797}
798#endif
799
800/** given a pointer, finds the chunk this pointer points to in the chunk array of the given chunk block;
801 * binary search is used;
802 * returns NULL if the pointer does not belong to the chunk block
803 */
804static
806 const BMS_CHKMEM* chkmem, /**< chunk block */
807 const void* ptr /**< pointer */
808 )
809{
810 CHUNK* chunk;
811
812 assert(chkmem != NULL);
813 assert(ptr != NULL);
814
815 if( rbTreeFindChunk(chkmem->rootchunk, ptr, &chunk) == 0 )
816 return chunk;
817
818 /* ptr was not found in chunk */
819 return NULL;
820}
821
822/** checks, if a pointer belongs to a chunk of the given chunk block */
823static
825 const BMS_CHKMEM* chkmem, /**< chunk block */
826 const void* ptr /**< pointer */
827 )
828{
829 assert(chkmem != NULL);
830
831 return (findChunk(chkmem, ptr) != NULL);
832}
833
834
835
836/*
837 * debugging methods
838 */
839
840#ifdef CHECKMEM
841/** sanity check for a memory chunk */
842static
843void checkChunk(
844 const CHUNK* chunk /**< memory chunk */
845 )
846{
847 FREELIST* eager;
848 int eagerfreesize;
849
850 assert(chunk != NULL);
851 assert(chunk->store != NULL);
852 assert(chunk->storeend == (void*)((char*)(chunk->store) + chunk->elemsize * chunk->storesize));
853 assert(chunk->chkmem != NULL);
854 assert(chunk->chkmem->elemsize == chunk->elemsize);
855
856 if( chunk->eagerfree == NULL )
857 assert(chunk->nexteager == NULL && chunk->preveager == NULL);
858 else if( chunk->preveager == NULL )
859 assert(chunk->chkmem->firsteager == chunk);
860
861 if( chunk->nexteager != NULL )
862 assert(chunk->nexteager->preveager == chunk);
863 if( chunk->preveager != NULL )
864 assert(chunk->preveager->nexteager == chunk);
865
866 eagerfreesize = 0;
867 eager = chunk->eagerfree;
868 while( eager != NULL )
869 {
870 assert(isPtrInChunk(chunk, eager));
871 eagerfreesize++;
872 eager = eager->next;
873 }
874 assert(chunk->eagerfreesize == eagerfreesize);
875}
876
877/** sanity check for a chunk block */
878static
879void checkChkmem(
880 const BMS_CHKMEM* chkmem /**< chunk block */
881 )
882{
883 FREELIST* lazy;
884 int nchunks;
885 int storesize;
886 int lazyfreesize;
887 int eagerfreesize;
888
889 assert(chkmem != NULL);
890
891 nchunks = 0;
892 storesize = 0;
893 lazyfreesize = 0;
894 eagerfreesize = 0;
895
896 FOR_EACH_NODE(CHUNK*, chunk, chkmem->rootchunk,
897 {
898 checkChunk(chunk);
899 nchunks++;
900 storesize += chunk->storesize;
901 eagerfreesize += chunk->eagerfreesize;
902 })
903
904 assert(chkmem->nchunks == nchunks);
905 assert(chkmem->storesize == storesize);
906 assert(chkmem->eagerfreesize == eagerfreesize);
907
908 assert(((unsigned int) (chkmem->eagerfreesize == 0)) ^ ( (unsigned int) (chkmem->firsteager != NULL)));
909
910 if( chkmem->firsteager != NULL )
911 assert(chkmem->firsteager->preveager == NULL);
912
913 lazy = chkmem->lazyfree;
914 while( lazy != NULL )
915 {
916 CHUNK* chunk = findChunk(chkmem, lazy);
917 assert(chunk != NULL);
918 assert(chunk->chkmem == chkmem);
919 lazyfreesize++;
920 lazy = lazy->next;
921 }
922 assert(chkmem->lazyfreesize == lazyfreesize);
923}
924#else
925#define checkChunk(chunk) /**/
926#define checkChkmem(chkmem) /**/
927#endif
928
929
930/** links chunk to the block's chunk array, sort it by store pointer;
931 * returns TRUE if successful, FALSE otherwise
932 */
933static
935 BMS_CHKMEM* chkmem, /**< chunk block */
936 CHUNK* chunk /**< memory chunk */
937 )
938{
939 CHUNK* parent;
940 int pos;
941
942 assert(chkmem != NULL);
943 assert(chunk != NULL);
944 assert(chunk->store != NULL);
945
946 debugMessage("linking chunk %p to chunk block %p [elemsize:%d, %d chunks]\n",
947 (void*)chunk, (void*)chkmem, chkmem->elemsize, chkmem->nchunks);
948
949 pos = rbTreeFindChunk(chkmem->rootchunk, chunk->store, &parent);
950 assert(pos != 0);
951
952 SCIPrbtreeInsert(&chkmem->rootchunk, parent, pos, chunk);
953
954 chkmem->nchunks++;
955 chkmem->storesize += chunk->storesize;
956
957 return TRUE;
958}
959
960/** unlinks chunk from the chunk block's chunk list */
961static
963 CHUNK* chunk /**< memory chunk */
964 )
965{
966 BMS_CHKMEM* chkmem;
967
968 assert(chunk != NULL);
969 assert(chunk->eagerfree == NULL);
970 assert(chunk->nexteager == NULL);
971 assert(chunk->preveager == NULL);
972
973 chkmem = chunk->chkmem;
974 assert(chkmem != NULL);
975 assert(chkmem->elemsize == chunk->elemsize);
976
977 debugMessage("unlinking chunk %p from chunk block %p [elemsize:%d, %d chunks]\n",
978 (void*)chunk, (void*)chkmem, chkmem->elemsize, chkmem->nchunks);
979
980 /* remove the chunk from the chunks of the chunk block */
981 SCIPrbtreeDelete(&chkmem->rootchunk, chunk);
982
983 chkmem->nchunks--;
984 chkmem->storesize -= chunk->storesize;
985}
986
987/** links chunk to the chunk block's eager chunk list */
988static
990 BMS_CHKMEM* chkmem, /**< chunk block */
991 CHUNK* chunk /**< memory chunk */
992 )
993{
994 assert(chunk->chkmem == chkmem);
995 assert(chunk->nexteager == NULL);
996 assert(chunk->preveager == NULL);
997
998 chunk->nexteager = chkmem->firsteager;
999 chunk->preveager = NULL;
1000 if( chkmem->firsteager != NULL )
1001 {
1002 assert(chkmem->firsteager->preveager == NULL);
1003 chkmem->firsteager->preveager = chunk;
1004 }
1005 chkmem->firsteager = chunk;
1006}
1007
1008/** unlinks chunk from the chunk block's eager chunk list */
1009static
1011 CHUNK* chunk /**< memory chunk */
1012 )
1013{
1014 assert(chunk != NULL);
1015 assert(chunk->eagerfreesize == 0 || chunk->eagerfreesize == chunk->storesize);
1016
1017 if( chunk->nexteager != NULL )
1018 chunk->nexteager->preveager = chunk->preveager;
1019 if( chunk->preveager != NULL )
1020 chunk->preveager->nexteager = chunk->nexteager;
1021 else
1022 {
1023 assert(chunk->chkmem->firsteager == chunk);
1024 chunk->chkmem->firsteager = chunk->nexteager;
1025 }
1026 chunk->nexteager = NULL;
1027 chunk->preveager = NULL;
1028 chunk->eagerfree = NULL;
1029}
1030
1031/** creates a new memory chunk in the given chunk block and adds memory elements to the lazy free list;
1032 * returns TRUE if successful, FALSE otherwise
1033 */
1034static
1036 BMS_CHKMEM* chkmem, /**< chunk block */
1037 long long* memsize /**< pointer to total size of allocated memory (or NULL) */
1038 )
1039{
1040 CHUNK *newchunk;
1041 FREELIST *freelist;
1042 int i;
1043 int storesize;
1044 int retval;
1045
1046 assert(chkmem != NULL);
1047
1048 debugMessage("creating new chunk in chunk block %p [elemsize: %d]\n", (void*)chkmem, chkmem->elemsize);
1049
1050 /* calculate store size */
1051 if( chkmem->nchunks == 0 )
1052 storesize = chkmem->initchunksize;
1053 else
1054 storesize = 2 * chkmem->lastchunksize;
1055 assert(storesize > 0);
1056 storesize = MAX(storesize, CHUNKLENGTH_MIN / chkmem->elemsize);
1057 storesize = MIN(storesize, CHUNKLENGTH_MAX / chkmem->elemsize);
1058 storesize = MIN(storesize, STORESIZE_MAX);
1059 storesize = MAX(storesize, 1);
1060 chkmem->lastchunksize = storesize;
1061
1062 /* create new chunk */
1063 assert(BMSisAligned(sizeof(CHUNK)));
1064 assert( chkmem->elemsize < INT_MAX / storesize );
1065 assert( sizeof(CHUNK) < MAXMEMSIZE - (size_t)(storesize * chkmem->elemsize) ); /*lint !e571 !e647*/
1066 BMSallocMemorySize(&newchunk, sizeof(CHUNK) + storesize * chkmem->elemsize);
1067 if( newchunk == NULL )
1068 return FALSE;
1069
1070 /* the store is allocated directly behind the chunk header */
1071 newchunk->store = (void*) ((char*) newchunk + sizeof(CHUNK));
1072 newchunk->storeend = (void*) ((char*) newchunk->store + (ptrdiff_t)storesize * chkmem->elemsize);
1073 newchunk->eagerfree = NULL;
1074 newchunk->nexteager = NULL;
1075 newchunk->preveager = NULL;
1076 newchunk->chkmem = chkmem;
1077 newchunk->elemsize = chkmem->elemsize;
1078 newchunk->storesize = storesize;
1079 newchunk->eagerfreesize = 0;
1080
1081 if( memsize != NULL )
1082 (*memsize) += ((long long)((long long)sizeof(CHUNK) + (long long)storesize * chkmem->elemsize));
1083
1084 debugMessage("allocated new chunk %p: %d elements with size %d\n", (void*)newchunk, newchunk->storesize, newchunk->elemsize);
1085
1086 /* add new memory to the lazy free list
1087 * (due to the BMSisAligned assert above, we know that elemsize is divisible by the size of pointers)
1088 */
1089 for( i = 0; i < newchunk->storesize - 1; ++i )
1090 {
1091 freelist = (FREELIST*) newchunk->store + (ptrdiff_t)i * chkmem->elemsize / (ptrdiff_t)sizeof(FREELIST*); /*lint !e573 !e647*/
1092 freelist->next = (FREELIST*) newchunk->store + ((ptrdiff_t)i + 1) * chkmem->elemsize / (ptrdiff_t)sizeof(FREELIST*); /*lint !e573 !e647*/
1093 }
1094
1095 freelist = (FREELIST*) newchunk->store + ((ptrdiff_t) newchunk->storesize - 1) * chkmem->elemsize / (ptrdiff_t)sizeof(FREELIST*); /*lint !e573 !e647*/
1096 freelist->next = chkmem->lazyfree;
1097 chkmem->lazyfree = (FREELIST*) (newchunk->store);
1098 chkmem->lazyfreesize += newchunk->storesize;
1099
1100 /* link chunk into chunk block */
1101 retval = linkChunk(chkmem, newchunk);
1102
1103 checkChkmem(chkmem);
1104
1105 return retval;
1106}
1107
1108/** destroys a chunk without updating the chunk lists */
1109static
1111 CHUNK** chunk, /**< memory chunk */
1112 long long* memsize /**< pointer to total size of allocated memory (or NULL) */
1113 )
1114{
1115 assert(chunk != NULL);
1116 assert(*chunk != NULL);
1117
1118 debugMessage("destroying chunk %p\n", (void*)*chunk);
1119
1120 if( memsize != NULL )
1121 (*memsize) -= ((long long)sizeof(CHUNK) + (long long)(*chunk)->storesize * (*chunk)->elemsize);
1122
1123 /* free chunk header and store (allocated in one call) */
1124 BMSfreeMemory(chunk);
1125}
1126
1127/** removes a completely unused chunk, i.e. a chunk with all elements in the eager free list */
1128static
1130 CHUNK** chunk, /**< memory chunk */
1131 long long* memsize /**< pointer to total size of allocated memory (or NULL) */
1132 )
1133{
1134 assert(chunk != NULL);
1135 assert(*chunk != NULL);
1136 assert((*chunk)->store != NULL);
1137 assert((*chunk)->eagerfree != NULL);
1138 assert((*chunk)->chkmem != NULL);
1139 assert((*chunk)->chkmem->rootchunk != NULL);
1140 assert((*chunk)->chkmem->firsteager != NULL);
1141 assert((*chunk)->eagerfreesize == (*chunk)->storesize);
1142
1143 debugMessage("freeing chunk %p of chunk block %p [elemsize: %d]\n", (void*)*chunk, (void*)(*chunk)->chkmem, (*chunk)->chkmem->elemsize);
1144
1145 /* count the deleted eager free slots */
1146 (*chunk)->chkmem->eagerfreesize -= (*chunk)->eagerfreesize;
1147 assert((*chunk)->chkmem->eagerfreesize >= 0);
1148
1149 /* remove chunk from eager chunk list */
1150 unlinkEagerChunk(*chunk);
1151
1152 /* remove chunk from chunk list */
1153 unlinkChunk(*chunk);
1154
1155 /* destroy the chunk */
1156 destroyChunk(chunk, memsize);
1157}
1158
1159/** returns an element of the eager free list and removes it from the list */
1160static
1162 CHUNK* chunk /**< memory chunk */
1163 )
1164{
1165 FREELIST* ptr;
1166
1167 assert(chunk != NULL);
1168 assert(chunk->eagerfree != NULL);
1169 assert(chunk->eagerfreesize > 0);
1170 assert(chunk->chkmem != NULL);
1171
1172 debugMessage("allocating chunk element in chunk %p [elemsize: %d]\n", (void*)chunk, chunk->chkmem->elemsize);
1173
1174 /* unlink first element in the eager free list */
1175 ptr = chunk->eagerfree;
1176 chunk->eagerfree = ptr->next;
1177 chunk->eagerfreesize--;
1178 chunk->chkmem->eagerfreesize--;
1179
1180 assert((chunk->eagerfreesize == 0 && chunk->eagerfree == NULL)
1181 || (chunk->eagerfreesize != 0 && chunk->eagerfree != NULL));
1182 assert(chunk->chkmem->eagerfreesize >= 0);
1183
1184 /* unlink chunk from eager chunk list if necessary */
1185 if( chunk->eagerfree == NULL )
1186 {
1187 assert(chunk->eagerfreesize == 0);
1188 unlinkEagerChunk(chunk);
1189 }
1190
1191 checkChunk(chunk);
1192
1193 return (void*) ptr;
1194}
1195
1196/** puts given pointer into the eager free list and adds the chunk to the eager list of its chunk block, if necessary */
1197static
1199 CHUNK* chunk, /**< memory chunk */
1200 void* ptr /**< pointer */
1201 )
1202{
1203 assert(chunk != NULL);
1204 assert(chunk->chkmem != NULL);
1205 assert(isPtrInChunk(chunk, ptr));
1206
1207 debugMessage("freeing chunk element %p of chunk %p [elemsize: %d]\n", (void*)ptr, (void*)chunk, chunk->chkmem->elemsize);
1208
1209 /* link chunk to the eager chunk list if necessary */
1210 if( chunk->eagerfree == NULL )
1211 {
1212 assert(chunk->eagerfreesize == 0);
1213 linkEagerChunk(chunk->chkmem, chunk);
1214 }
1215
1216 /* add ptr to the chunks eager free list */
1217 ((FREELIST*)ptr)->next = chunk->eagerfree;
1218 chunk->eagerfree = (FREELIST*)ptr;
1219 chunk->eagerfreesize++;
1220 chunk->chkmem->eagerfreesize++;
1221
1222 checkChunk(chunk);
1223}
1224
1225/** creates a new chunk block data structure */
1226static
1228 int size, /**< element size of the chunk block */
1229 int initchunksize, /**< number of elements in the first chunk of the chunk block */
1230 int garbagefactor, /**< garbage collector is called, if at least garbagefactor * avg. chunksize
1231 * elements are free (-1: disable garbage collection) */
1232 long long* memsize /**< pointer to total size of allocated memory (or NULL) */
1233 )
1234{
1235 BMS_CHKMEM* chkmem;
1236
1237 assert(size >= 0);
1238 assert(BMSisAligned((size_t)size)); /*lint !e571*/
1239
1240 BMSallocMemory(&chkmem);
1241 if( chkmem == NULL )
1242 return NULL;
1243
1244 chkmem->lazyfree = NULL;
1245 chkmem->rootchunk = NULL;
1246 chkmem->firsteager = NULL;
1247 chkmem->nextchkmem = NULL;
1248 chkmem->elemsize = size;
1249 chkmem->nchunks = 0;
1250 chkmem->lastchunksize = 0;
1251 chkmem->storesize = 0;
1252 chkmem->lazyfreesize = 0;
1253 chkmem->eagerfreesize = 0;
1254 chkmem->initchunksize = initchunksize;
1255 chkmem->garbagefactor = garbagefactor;
1256#ifndef NDEBUG
1257 chkmem->filename = NULL;
1258 chkmem->line = 0;
1259 chkmem->ngarbagecalls = 0;
1260 chkmem->ngarbagefrees = 0;
1261#endif
1262
1263 if( memsize != NULL )
1264 (*memsize) += (long long)sizeof(BMS_CHKMEM);
1265
1266 return chkmem;
1267}
1268
1269/** destroys all chunks of the chunk block, but keeps the chunk block header structure */
1270static
1272 BMS_CHKMEM* chkmem, /**< chunk block */
1273 long long* memsize /**< pointer to total size of allocated memory (or NULL) */
1274 )
1275{
1276 assert(chkmem != NULL);
1277
1278 /* destroy all chunks of the chunk block */
1279 FOR_EACH_NODE(CHUNK*, chunk, chkmem->rootchunk,
1280 {
1281 SCIPrbtreeDelete(&chkmem->rootchunk, chunk);
1282 destroyChunk(&chunk, memsize);
1283 })
1284
1285 chkmem->lazyfree = NULL;
1286 chkmem->firsteager = NULL;
1287 chkmem->nchunks = 0;
1288 chkmem->lastchunksize = 0;
1289 chkmem->storesize = 0;
1290 chkmem->lazyfreesize = 0;
1291 chkmem->eagerfreesize = 0;
1292}
1293
1294/** deletes chunk block and frees all associated memory chunks */
1295static
1297 BMS_CHKMEM** chkmem, /**< pointer to chunk block */
1298 long long* memsize /**< pointer to total size of allocated memory (or NULL) */
1299 )
1300{
1301 assert(chkmem != NULL);
1302 assert(*chkmem != NULL);
1303
1304 clearChkmem(*chkmem, memsize);
1305
1306#ifndef NDEBUG
1307 BMSfreeMemoryArrayNull(&(*chkmem)->filename);
1308#endif
1309
1310 if( memsize != NULL )
1311 (*memsize) -= (long long)(sizeof(BMS_CHKMEM));
1312
1313 BMSfreeMemory(chkmem);
1314}
1315
1316/** allocates a new memory element from the chunk block */
1317static
1319 BMS_CHKMEM* chkmem, /**< chunk block */
1320 long long* memsize /**< pointer to total size of allocated memory (or NULL) */
1321 )
1322{
1323 FREELIST* ptr;
1324
1325 assert(chkmem != NULL);
1326
1327 /* if the lazy freelist is empty, we have to find the memory element somewhere else */
1328 if( chkmem->lazyfree == NULL )
1329 {
1330 assert(chkmem->lazyfreesize == 0);
1331
1332 /* check for a free element in the eager freelists */
1333 if( chkmem->firsteager != NULL )
1334 return allocChunkElement(chkmem->firsteager);
1335
1336 /* allocate a new chunk */
1337 if( !createChunk(chkmem, memsize) )
1338 return NULL;
1339 }
1340
1341 /* now the lazy freelist should contain an element */
1342 assert(chkmem->lazyfree != NULL);
1343 assert(chkmem->lazyfreesize > 0);
1344
1345 ptr = chkmem->lazyfree;
1346 chkmem->lazyfree = ptr->next;
1347 chkmem->lazyfreesize--;
1348
1349 checkChkmem(chkmem);
1350
1351 return (void*) ptr;
1352}
1353
1354/** sorts the lazy free list of the chunk block into the eager free lists of the chunks, and removes completely
1355 * unused chunks
1356 */
1357static
1359 BMS_CHKMEM* chkmem, /**< chunk block */
1360 long long* memsize /**< pointer to total size of allocated memory (or NULL) */
1361 )
1362{
1363 CHUNK* chunk;
1364 CHUNK* nexteager;
1365 FREELIST* lazyfree;
1366
1367 assert(chkmem != NULL);
1368
1369 debugMessage("garbage collection for chunk block %p [elemsize: %d]\n", (void*)chkmem, chkmem->elemsize);
1370
1371 /* check, if the chunk block is completely unused */
1372 if( chkmem->lazyfreesize + chkmem->eagerfreesize == chkmem->storesize )
1373 {
1374 clearChkmem(chkmem, memsize);
1375 return;
1376 }
1377
1378#ifndef NDEBUG
1379 chkmem->ngarbagecalls++;
1380#endif
1381
1382 /* put the lazy free elements into the eager free lists */
1383 while( chkmem->lazyfree != NULL )
1384 {
1385 /* unlink first element from the lazy free list */
1386 lazyfree = chkmem->lazyfree;
1387 chkmem->lazyfree = chkmem->lazyfree->next;
1388 chkmem->lazyfreesize--;
1389
1390 /* identify the chunk of the element */
1391 chunk = findChunk(chkmem, (void*)lazyfree);
1392#ifndef NDEBUG
1393 if( chunk == NULL )
1394 {
1395 errorMessage("chunk for lazy free chunk %p not found in chunk block %p\n", (void*)lazyfree, (void*)chkmem);
1396 }
1397#endif
1398 assert(chunk != NULL);
1399
1400 /* add the element to the chunk's eager free list */
1401 freeChunkElement(chunk, (void*)lazyfree);
1402 assert(chunk->eagerfreesize > 0);
1403 }
1404 assert(chkmem->lazyfreesize == 0);
1405
1406 /* delete completely unused chunks, but keep at least one */
1407 chunk = chkmem->firsteager;
1408 while( chunk != NULL && chkmem->nchunks > 1 )
1409 {
1410 nexteager = chunk->nexteager;
1411 if( chunk->eagerfreesize == chunk->storesize )
1412 {
1413#ifndef NDEBUG
1414 chkmem->ngarbagefrees++;
1415#endif
1416 freeChunk(&chunk, memsize);
1417 }
1418 chunk = nexteager;
1419 }
1420
1421 checkChkmem(chkmem);
1422}
1423
1424/** frees a memory element and returns it to the lazy freelist of the chunk block */ /*lint -e715*/
1425static
1427 BMS_CHKMEM* chkmem, /**< chunk block */
1428 void* ptr, /**< memory element */
1429 long long* memsize, /**< pointer to total size of allocated memory (or NULL) */
1430 const char* filename, /**< source file of the function call */
1431 int line /**< line number in source file of the function call */
1432 )
1433{ /*lint --e{715}*/
1434 assert(chkmem != NULL);
1435 assert(ptr != NULL);
1436
1437#if ( defined(CHECKMEM) || defined(CHECKCHKFREE) )
1438 /* check, if ptr belongs to the chunk block */
1439 if( !isPtrInChkmem(chkmem, ptr) )
1440 {
1441 printErrorHeader(filename, line);
1442 printError("Pointer %p does not belong to chunk block %p (size: %d).\n", ptr, chkmem, chkmem->elemsize);
1443 }
1444#endif
1445
1446 /* put ptr in lazy free list */
1447 ((FREELIST*)ptr)->next = chkmem->lazyfree;
1448 chkmem->lazyfree = (FREELIST*)ptr;
1449 chkmem->lazyfreesize++;
1450
1451 /* check if we want to apply garbage collection */
1452 if( chkmem->garbagefactor >= 0 && chkmem->nchunks > 0 && chkmem->lazyfreesize >= GARBAGE_SIZE
1453 && chkmem->lazyfreesize + chkmem->eagerfreesize
1454 > chkmem->garbagefactor * (double)(chkmem->storesize) / (double)(chkmem->nchunks) )
1455 {
1456 garbagecollectChkmem(chkmem, memsize);
1457 }
1458
1459 checkChkmem(chkmem);
1460}
1461
1462/** creates a new chunk block data structure */
1464 size_t size, /**< element size of the chunk block */
1465 int initchunksize, /**< number of elements in the first chunk of the chunk block */
1466 int garbagefactor, /**< garbage collector is called, if at least garbagefactor * avg. chunksize
1467 * elements are free (-1: disable garbage collection) */
1468 const char* filename, /**< source file of the function call */
1469 int line /**< line number in source file of the function call */
1470 )
1471{
1472 BMS_CHKMEM* chkmem;
1473
1474 alignSize(&size);
1475 chkmem = createChkmem((int) size, initchunksize, garbagefactor, NULL);
1476 if( chkmem == NULL )
1477 {
1478 printErrorHeader(filename, line);
1479 printError("Insufficient memory for chunk block.\n");
1480 }
1481 debugMessage("created chunk memory %p [elemsize: %d]\n", (void*)chkmem, (int)size);
1482
1483 return chkmem;
1484}
1485
1486/** clears a chunk block data structure */
1488 BMS_CHKMEM* chkmem, /**< chunk block */
1489 const char* filename, /**< source file of the function call */
1490 int line /**< line number in source file of the function call */
1491 )
1492{
1493 if( chkmem != NULL )
1494 {
1495 debugMessage("clearing chunk memory %p [elemsize: %d]\n", (void*)chkmem, chkmem->elemsize);
1496 clearChkmem(chkmem, NULL);
1497 }
1498 else
1499 {
1500 printErrorHeader(filename, line);
1501 printError("Tried to clear null chunk block.\n");
1502 }
1503}
1504
1505/** destroys and frees a chunk block data structure */
1507 BMS_CHKMEM** chkmem, /**< pointer to chunk block */
1508 const char* filename, /**< source file of the function call */
1509 int line /**< line number in source file of the function call */
1510 )
1511{
1512 assert(chkmem != NULL);
1513
1514 if( *chkmem != NULL )
1515 {
1516 debugMessage("destroying chunk memory %p [elemsize: %d]\n", (void*)*chkmem, (*chkmem)->elemsize);
1517 destroyChkmem(chkmem, NULL);
1518 }
1519 else
1520 {
1521 printErrorHeader(filename, line);
1522 printError("Tried to destroy null chunk block.\n");
1523 }
1524}
1525
1526/** allocates a memory element of the given chunk block */
1528 BMS_CHKMEM* chkmem, /**< chunk block */
1529 size_t size, /**< size of memory element to allocate (only needed for sanity check) */
1530 const char* filename, /**< source file of the function call */
1531 int line /**< line number in source file of the function call */
1532 )
1533{
1534 void* ptr;
1535
1536 assert(chkmem != NULL);
1537 assert((int)size == chkmem->elemsize);
1538
1539 /* get memory inside the chunk block */
1540 ptr = allocChkmemElement(chkmem, NULL);
1541 if( ptr == NULL )
1542 {
1543 printErrorHeader(filename, line);
1544 printError("Insufficient memory for new chunk.\n");
1545 }
1546 debugMessage("alloced %8llu bytes in %p [%s:%d]\n", (unsigned long long)size, (void*)ptr, filename, line);
1547
1548 checkChkmem(chkmem);
1549
1550 return ptr;
1551}
1552
1553/** duplicates a given memory element by allocating a new element of the same chunk block and copying the data */
1555 BMS_CHKMEM* chkmem, /**< chunk block */
1556 const void* source, /**< source memory element */
1557 size_t size, /**< size of memory element to allocate (only needed for sanity check) */
1558 const char* filename, /**< source file of the function call */
1559 int line /**< line number in source file of the function call */
1560 )
1561{
1562 void* ptr;
1563
1564 assert(chkmem != NULL);
1565 assert(source != NULL);
1566 assert((int)size == chkmem->elemsize);
1567
1568 ptr = BMSallocChunkMemory_call(chkmem, size, filename, line);
1569 if( ptr != NULL )
1570 BMScopyMemorySize(ptr, source, chkmem->elemsize);
1571
1572 return ptr;
1573}
1574
1575/** frees a memory element of the given chunk block and sets pointer to NULL */
1577 BMS_CHKMEM* chkmem, /**< chunk block */
1578 void** ptr, /**< pointer to pointer to memory element to free */
1579 size_t size, /**< size of memory element to allocate (only needed for sanity check) */
1580 const char* filename, /**< source file of the function call */
1581 int line /**< line number in source file of the function call */
1582 )
1583{
1584 assert(chkmem != NULL);
1585 assert((int)size == chkmem->elemsize);
1586 assert( ptr != NULL );
1587
1588 if ( *ptr != NULL )
1589 {
1590 debugMessage("free %8d bytes in %p [%s:%d]\n", chkmem->elemsize, *ptr, filename, line);
1591
1592 /* free memory in chunk block */
1593 freeChkmemElement(chkmem, *ptr, NULL, filename, line);
1594 checkChkmem(chkmem);
1595 *ptr = NULL;
1596 }
1597 else
1598 {
1599 printErrorHeader(filename, line);
1600 printError("Tried to free null chunk pointer.\n");
1601 }
1602}
1603
1604/** frees a memory element of the given chunk block if pointer is not NULL and sets pointer to NULL */
1606 BMS_CHKMEM* chkmem, /**< chunk block */
1607 void** ptr, /**< pointer to pointer to memory element to free */
1608 size_t size, /**< size of memory element to allocate (only needed for sanity check) */
1609 const char* filename, /**< source file of the function call */
1610 int line /**< line number in source file of the function call */
1611 )
1612{
1613 assert(chkmem != NULL);
1614 assert((int)size == chkmem->elemsize);
1615 assert( ptr != NULL );
1616
1617 if ( *ptr != NULL )
1618 {
1619 debugMessage("free %8d bytes in %p [%s:%d]\n", chkmem->elemsize, *ptr, filename, line);
1620
1621 /* free memory in chunk block */
1622 freeChkmemElement(chkmem, *ptr, NULL, filename, line);
1623 checkChkmem(chkmem);
1624 *ptr = NULL;
1625 }
1626}
1627
1628/** calls garbage collection of chunk block and frees chunks without allocated memory elements */
1630 BMS_CHKMEM* chkmem /**< chunk block */
1631 )
1632{
1633 debugMessage("garbage collection on chunk memory %p [elemsize: %d]\n", (void*)chkmem, chkmem->elemsize);
1634
1635 garbagecollectChkmem(chkmem, NULL);
1636}
1637
1638/** returns the number of allocated bytes in the chunk block */
1640 const BMS_CHKMEM* chkmem /**< chunk block */
1641 )
1642{
1643 assert(chkmem != NULL);
1644
1645 return ((long long)(chkmem->elemsize) * (long long)(chkmem->storesize));
1646}
1647
1648
1649
1650
1651/***********************************************************
1652 * Block Memory Management
1653 *
1654 * Efficient memory management for objects of varying sizes
1655 ***********************************************************/
1656
1657/* for a definition of the struct, see above */
1658
1659
1660/*
1661 * debugging methods
1662 */
1663
1664#ifdef CHECKMEM
1665static
1666void checkBlkmem(
1667 const BMS_BLKMEM* blkmem /**< block memory */
1668 )
1669{
1670 const BMS_CHKMEM* chkmem;
1671 long long tmpmemalloc = 0LL;
1672 long long tmpmemused = 0LL;
1673 int i;
1674
1675 assert(blkmem != NULL);
1676 assert(blkmem->chkmemhash != NULL);
1677
1678 for( i = 0; i < CHKHASH_SIZE; ++i )
1679 {
1680 chkmem = blkmem->chkmemhash[i];
1681 while( chkmem != NULL )
1682 {
1683 checkChkmem(chkmem);
1684 tmpmemalloc += ((chkmem->elemsize * chkmem->storesize) + chkmem->nchunks * sizeof(CHUNK) + sizeof(BMS_CHKMEM));
1685 tmpmemused += (chkmem->elemsize * (chkmem->storesize - chkmem->eagerfreesize - chkmem->lazyfreesize));
1686 chkmem = chkmem->nextchkmem;
1687 }
1688 }
1689 assert(tmpmemalloc == blkmem->memallocated);
1690 assert(tmpmemused == blkmem->memused);
1691}
1692#else
1693#define checkBlkmem(blkmem) /**/
1694#endif
1695
1696
1697/** finds the chunk block, to whick the given pointer belongs to
1698 *
1699 * This could be done by selecting the chunk block of the corresponding element size, but in a case of an
1700 * error (free gives an incorrect element size), we want to identify and output the correct element size.
1701 */
1702static
1704 const BMS_BLKMEM* blkmem, /**< block memory */
1705 const void* ptr /**< memory element to search */
1706 )
1707{
1708 BMS_CHKMEM* chkmem;
1709 int i;
1710
1711 assert(blkmem != NULL);
1712
1713 chkmem = NULL;
1714 for( i = 0; chkmem == NULL && i < CHKHASH_SIZE; ++i )
1715 {
1716 chkmem = blkmem->chkmemhash[i];
1717 while( chkmem != NULL && !isPtrInChkmem(chkmem, ptr) )
1718 chkmem = chkmem->nextchkmem;
1719 }
1720
1721 return chkmem;
1722}
1723
1724/** calculates hash number of memory size */
1725static
1727 size_t size /**< element size */
1728 )
1729{
1730 assert(BMSisAligned(size));
1731
1732 return ((uint32_t)size * UINT32_C(0x9e3779b9)) >> (32-CHKHASH_POWER);
1733}
1734
1735/** creates a block memory allocation data structure */
1737 int initchunksize, /**< number of elements in the first chunk of each chunk block */
1738 int garbagefactor, /**< garbage collector is called, if at least garbagefactor * avg. chunksize
1739 * elements are free (-1: disable garbage collection) */
1740 const char* filename, /**< source file of the function call */
1741 int line /**< line number in source file of the function call */
1742 )
1743{
1744 BMS_BLKMEM* blkmem;
1745 int i;
1746
1747 BMSallocMemory(&blkmem);
1748 if( blkmem != NULL )
1749 {
1750 for( i = 0; i < CHKHASH_SIZE; ++i )
1751 blkmem->chkmemhash[i] = NULL;
1752 blkmem->initchunksize = initchunksize;
1753 blkmem->garbagefactor = garbagefactor;
1754 blkmem->memused = 0;
1755 blkmem->memallocated = 0;
1756 blkmem->maxmemused = 0;
1757 blkmem->maxmemunused = 0;
1758 blkmem->maxmemallocated = 0;
1759 }
1760 else
1761 {
1762 printErrorHeader(filename, line);
1763 printError("Insufficient memory for block memory header.\n");
1764 }
1765
1766 return blkmem;
1767}
1768
1769/** frees all chunk blocks in the block memory */
1771 BMS_BLKMEM* blkmem, /**< block memory */
1772 const char* filename, /**< source file of the function call */
1773 int line /**< line number in source file of the function call */
1774 )
1775{
1776 BMS_CHKMEM* chkmem;
1777 BMS_CHKMEM* nextchkmem;
1778 int i;
1779
1780 if( blkmem != NULL )
1781 {
1782 for( i = 0; i < CHKHASH_SIZE; ++i )
1783 {
1784 chkmem = blkmem->chkmemhash[i];
1785 while( chkmem != NULL )
1786 {
1787 nextchkmem = chkmem->nextchkmem;
1788 destroyChkmem(&chkmem, &blkmem->memallocated);
1789 chkmem = nextchkmem;
1790 }
1791 blkmem->chkmemhash[i] = NULL;
1792 }
1793 blkmem->memused = 0;
1794 assert(blkmem->memallocated == 0);
1795 }
1796 else
1797 {
1798 printErrorHeader(filename, line);
1799 printError("Tried to clear null block memory.\n");
1800 }
1801}
1802
1803/** clears and deletes block memory */
1805 BMS_BLKMEM** blkmem, /**< pointer to block memory */
1806 const char* filename, /**< source file of the function call */
1807 int line /**< line number in source file of the function call */
1808 )
1809{
1810 assert(blkmem != NULL);
1811
1812 if( *blkmem != NULL )
1813 {
1814 BMSclearBlockMemory_call(*blkmem, filename, line);
1815 BMSfreeMemory(blkmem);
1816 assert(*blkmem == NULL);
1817 }
1818 else
1819 {
1820 printErrorHeader(filename, line);
1821 printError("Tried to destroy null block memory.\n");
1822 }
1823}
1824
1825/** work for allocating memory in the block memory pool */
1826INLINE static
1828 BMS_BLKMEM* blkmem, /**< block memory */
1829 size_t size, /**< size of memory element to allocate */
1830 const char* filename, /**< source file of the function call */
1831 int line /**< line number in source file of the function call */
1832 )
1833{
1834 BMS_CHKMEM** chkmemptr;
1835 uint32_t hashnumber;
1836 void* ptr;
1837
1838 assert( blkmem != NULL );
1839
1840 /* allocating very large memory blocks is currently not possible, because BMS_CHKMEM::elemsize is of type int only */
1841 if( size > INT_MAX )
1842 return NULL;
1843
1844 /* calculate hash number of given size */
1845 alignSize(&size);
1846 hashnumber = getHashNumber(size);
1847 assert(hashnumber < CHKHASH_SIZE);
1848
1849 /* find corresponding chunk block */
1850 chkmemptr = &(blkmem->chkmemhash[hashnumber]);
1851 while( *chkmemptr != NULL && (*chkmemptr)->elemsize != (int)size )
1852 chkmemptr = &((*chkmemptr)->nextchkmem);
1853
1854 /* create new chunk block if necessary */
1855 if( *chkmemptr == NULL )
1856 {
1857 *chkmemptr = createChkmem((int)size, blkmem->initchunksize, blkmem->garbagefactor, &blkmem->memallocated);
1858 if( *chkmemptr == NULL )
1859 {
1860 printErrorHeader(filename, line);
1861 printError("Insufficient memory for chunk block.\n");
1862 return NULL;
1863 }
1864#ifndef NDEBUG
1865 BMSduplicateMemoryArray(&(*chkmemptr)->filename, filename, strlen(filename) + 1);
1866 (*chkmemptr)->line = line;
1867#endif
1868 }
1869#ifndef NDEBUG
1870 else
1871 {
1872 BMSfreeMemoryArrayNull(&(*chkmemptr)->filename);
1873 BMSduplicateMemoryArray(&(*chkmemptr)->filename, filename, strlen(filename) + 1);
1874 (*chkmemptr)->line = line;
1875 }
1876#endif
1877
1878 /* get memory inside the chunk block */
1879 ptr = allocChkmemElement(*chkmemptr, &blkmem->memallocated);
1880
1881 if( ptr == NULL )
1882 {
1883 printErrorHeader(filename, line);
1884 printError("Insufficient memory for new chunk.\n");
1885 }
1886 debugMessage("alloced %8llu bytes in %p [%s:%d]\n", (unsigned long long)size, ptr, filename, line);
1887
1888 /* add the used memory */
1889 blkmem->memused += (long long) size;
1890 blkmem->maxmemused = MAX(blkmem->maxmemused, blkmem->memused);
1891 blkmem->maxmemunused = MAX(blkmem->maxmemunused, blkmem->memallocated - blkmem->memused);
1892 blkmem->maxmemallocated = MAX(blkmem->maxmemallocated, blkmem->memallocated);
1893
1894 assert(blkmem->memused >= 0);
1895 assert(blkmem->memallocated >= 0);
1896
1897 checkBlkmem(blkmem);
1898
1899 return ptr;
1900}
1901
1902/** allocates memory in the block memory pool */
1904 BMS_BLKMEM* blkmem, /**< block memory */
1905 size_t size, /**< size of memory element to allocate */
1906 const char* filename, /**< source file of the function call */
1907 int line /**< line number in source file of the function call */
1908 )
1909{
1910#ifndef NDEBUG
1911 if ( size > MAXMEMSIZE )
1912 {
1913 printErrorHeader(filename, line);
1914 printError("Tried to allocate block of size exceeding %lu.\n", MAXMEMSIZE);
1915 return NULL;
1916 }
1917#endif
1918
1919 return BMSallocBlockMemory_work(blkmem, size, filename, line);
1920}
1921
1922/** allocates memory in the block memory pool and clears it */
1924 BMS_BLKMEM* blkmem, /**< block memory */
1925 size_t size, /**< size of memory element to allocate */
1926 const char* filename, /**< source file of the function call */
1927 int line /**< line number in source file of the function call */
1928 )
1929{
1930 void* ptr;
1931
1932 ptr = BMSallocBlockMemory_call(blkmem, size, filename, line);
1933 if( ptr != NULL )
1934 BMSclearMemorySize(ptr, size);
1935
1936 return ptr;
1937}
1938
1939/** allocates array in the block memory pool */
1941 BMS_BLKMEM* blkmem, /**< block memory */
1942 size_t num, /**< size of array to be allocated */
1943 size_t typesize, /**< size of each component */
1944 const char* filename, /**< source file of the function call */
1945 int line /**< line number in source file of the function call */
1946 )
1947{
1948#ifndef NDEBUG
1949 if ( num > (MAXMEMSIZE / typesize) )
1950 {
1951 printErrorHeader(filename, line);
1952 printError("Tried to allocate block of size exceeding %lu.\n", MAXMEMSIZE);
1953 return NULL;
1954 }
1955#endif
1956
1957 return BMSallocBlockMemory_work(blkmem, num * typesize, filename, line);
1958}
1959
1960/** allocates array in the block memory pool and clears it */
1962 BMS_BLKMEM* blkmem, /**< block memory */
1963 size_t num, /**< size of array to be allocated */
1964 size_t typesize, /**< size of each component */
1965 const char* filename, /**< source file of the function call */
1966 int line /**< line number in source file of the function call */
1967 )
1968{
1969 void* ptr;
1970
1971 ptr = BMSallocBlockMemoryArray_call(blkmem, num, typesize, filename, line);
1972 if ( ptr != NULL )
1973 BMSclearMemorySize(ptr, num * typesize);
1974
1975 return ptr;
1976}
1977
1978/** resizes memory element in the block memory pool and copies the data */
1980 BMS_BLKMEM* blkmem, /**< block memory */
1981 void* ptr, /**< memory element to reallocated */
1982 size_t oldsize, /**< old size of memory element */
1983 size_t newsize, /**< new size of memory element */
1984 const char* filename, /**< source file of the function call */
1985 int line /**< line number in source file of the function call */
1986 )
1987{
1988 void* newptr;
1989
1990 if( ptr == NULL )
1991 {
1992 assert(oldsize == 0);
1993 return BMSallocBlockMemory_call(blkmem, newsize, filename, line);
1994 }
1995
1996#ifndef NDEBUG
1997 if ( newsize > MAXMEMSIZE )
1998 {
1999 printErrorHeader(filename, line);
2000 printError("Tried to allocate block of size exceeding %lu.\n", MAXMEMSIZE);
2001 return NULL;
2002 }
2003#endif
2004
2005 alignSize(&oldsize);
2006 alignSize(&newsize);
2007 if( oldsize == newsize )
2008 return ptr;
2009
2010 newptr = BMSallocBlockMemory_call(blkmem, newsize, filename, line);
2011 if( newptr != NULL )
2012 BMScopyMemorySize(newptr, ptr, MIN(oldsize, newsize));
2013 BMSfreeBlockMemory_call(blkmem, &ptr, oldsize, filename, line);
2014
2015 return newptr;
2016}
2017
2018/** resizes array in the block memory pool and copies the data */
2020 BMS_BLKMEM* blkmem, /**< block memory */
2021 void* ptr, /**< memory element to reallocated */
2022 size_t oldnum, /**< old size of array */
2023 size_t newnum, /**< new size of array */
2024 size_t typesize, /**< size of each component */
2025 const char* filename, /**< source file of the function call */
2026 int line /**< line number in source file of the function call */
2027 )
2028{
2029 void* newptr;
2030
2031 if( ptr == NULL )
2032 {
2033 assert(oldnum == 0);
2034 return BMSallocBlockMemoryArray_call(blkmem, newnum, typesize, filename, line);
2035 }
2036
2037#ifndef NDEBUG
2038 if ( newnum > (MAXMEMSIZE / typesize) )
2039 {
2040 printErrorHeader(filename, line);
2041 printError("Tried to allocate array of size exceeding %lu.\n", MAXMEMSIZE);
2042 return NULL;
2043 }
2044#endif
2045
2046 if ( oldnum == newnum )
2047 return ptr;
2048
2049 newptr = BMSallocBlockMemoryArray_call(blkmem, newnum, typesize, filename, line);
2050 if ( newptr != NULL )
2051 BMScopyMemorySize(newptr, ptr, MIN(oldnum, newnum) * typesize);
2052 BMSfreeBlockMemory_call(blkmem, &ptr, oldnum * typesize, filename, line);
2053
2054 return newptr;
2055}
2056
2057/** duplicates memory element in the block memory pool and copies the data */
2059 BMS_BLKMEM* blkmem, /**< block memory */
2060 const void* source, /**< memory element to duplicate */
2061 size_t size, /**< size of memory elements */
2062 const char* filename, /**< source file of the function call */
2063 int line /**< line number in source file of the function call */
2064 )
2065{
2066 void* ptr;
2067
2068 assert(source != NULL);
2069
2070 ptr = BMSallocBlockMemory_call(blkmem, size, filename, line);
2071 if( ptr != NULL )
2072 BMScopyMemorySize(ptr, source, size);
2073
2074 return ptr;
2075}
2076
2077/** duplicates array in the block memory pool and copies the data */
2079 BMS_BLKMEM* blkmem, /**< block memory */
2080 const void* source, /**< memory element to duplicate */
2081 size_t num, /**< size of array to be duplicated */
2082 size_t typesize, /**< size of each component */
2083 const char* filename, /**< source file of the function call */
2084 int line /**< line number in source file of the function call */
2085 )
2086{
2087 void* ptr;
2088
2089 assert(source != NULL);
2090
2091 ptr = BMSallocBlockMemoryArray_call(blkmem, num, typesize, filename, line);
2092 if( ptr != NULL )
2093 BMScopyMemorySize(ptr, source, num * typesize);
2094
2095 return ptr;
2096}
2097
2098/** common work for freeing block memory */
2099INLINE static
2101 BMS_BLKMEM* blkmem, /**< block memory */
2102 void** ptr, /**< pointer to pointer to memory element to free */
2103 size_t size, /**< size of memory element */
2104 const char* filename, /**< source file of the function call */
2105 int line /**< line number in source file of the function call */
2106 )
2107{
2108 BMS_CHKMEM* chkmem;
2109 uint32_t hashnumber;
2110
2111 assert(ptr != NULL);
2112 assert(*ptr != NULL);
2113
2114 /* calculate hash number of given size */
2115 alignSize(&size);
2116 hashnumber = getHashNumber(size);
2117 assert(hashnumber < CHKHASH_SIZE);
2118
2119 debugMessage("free %8llu bytes in %p [%s:%d]\n", (unsigned long long)size, *ptr, filename, line);
2120
2121 /* find corresponding chunk block */
2122 assert( blkmem->chkmemhash != NULL );
2123 chkmem = blkmem->chkmemhash[hashnumber];
2124 while( chkmem != NULL && chkmem->elemsize != (int)size )
2125 chkmem = chkmem->nextchkmem;
2126 if( chkmem == NULL )
2127 {
2128 printErrorHeader(filename, line);
2129 printError("Tried to free pointer <%p> in block memory <%p> of unknown size %llu.\n", *ptr, (void*)blkmem, (unsigned long long)size);
2130 return;
2131 }
2132 assert(chkmem->elemsize == (int)size);
2133
2134 /* free memory in chunk block */
2135 freeChkmemElement(chkmem, *ptr, &blkmem->memallocated, filename, line);
2136 blkmem->memused -= (long long) size;
2137
2138 blkmem->maxmemunused = MAX(blkmem->maxmemunused, blkmem->memallocated - blkmem->memused);
2139
2140 assert(blkmem->memused >= 0);
2141 assert(blkmem->memallocated >= 0);
2142
2143 checkBlkmem(blkmem);
2144
2145 *ptr = NULL;
2146}
2147
2148/** frees memory element in the block memory pool and sets pointer to NULL */
2150 BMS_BLKMEM* blkmem, /**< block memory */
2151 void** ptr, /**< pointer to pointer to memory element to free */
2152 size_t size, /**< size of memory element */
2153 const char* filename, /**< source file of the function call */
2154 int line /**< line number in source file of the function call */
2155 )
2156{
2157 assert( blkmem != NULL );
2158 assert( ptr != NULL );
2159
2160 if( *ptr != NULL )
2161 BMSfreeBlockMemory_work(blkmem, ptr, size, filename, line);
2162 else if( size != 0 )
2163 {
2164 printErrorHeader(filename, line);
2165 printError("Tried to free null block pointer.\n");
2166 }
2167 checkBlkmem(blkmem);
2168}
2169
2170/** frees memory element in the block memory pool if pointer is not NULL and sets pointer to NULL */
2172 BMS_BLKMEM* blkmem, /**< block memory */
2173 void** ptr, /**< pointer to pointer to memory element to free */
2174 size_t size, /**< size of memory element */
2175 const char* filename, /**< source file of the function call */
2176 int line /**< line number in source file of the function call */
2177 )
2178{
2179 assert( blkmem != NULL );
2180 assert( ptr != NULL );
2181
2182 if( *ptr != NULL )
2183 {
2184 BMSfreeBlockMemory_work(blkmem, ptr, size, filename, line);
2185 }
2186 checkBlkmem(blkmem);
2187}
2188
2189/** calls garbage collection of block memory, frees chunks without allocated memory elements, and frees
2190 * chunk blocks without any chunks
2191 */
2193 BMS_BLKMEM* blkmem /**< block memory */
2194 )
2195{
2196 int i;
2197
2198 assert(blkmem != NULL);
2199
2200 for( i = 0; i < CHKHASH_SIZE; ++i )
2201 {
2202 BMS_CHKMEM** chkmemptr;
2203
2204 chkmemptr = &blkmem->chkmemhash[i];
2205 while( *chkmemptr != NULL )
2206 {
2207 garbagecollectChkmem(*chkmemptr, &blkmem->memallocated);
2208 checkBlkmem(blkmem);
2209 if( (*chkmemptr)->nchunks == 0 )
2210 {
2211 BMS_CHKMEM* nextchkmem;
2212
2213 assert((*chkmemptr)->lazyfreesize == 0);
2214 nextchkmem = (*chkmemptr)->nextchkmem;
2215 destroyChkmem(chkmemptr, &blkmem->memallocated);
2216 *chkmemptr = nextchkmem;
2217 checkBlkmem(blkmem);
2218 }
2219 else
2220 chkmemptr = &(*chkmemptr)->nextchkmem;
2221 }
2222 }
2223}
2224
2225/** returns the number of allocated bytes in the block memory */
2227 const BMS_BLKMEM* blkmem /**< block memory */
2228 )
2229{
2230 assert( blkmem != NULL );
2231
2232 return blkmem->memallocated;
2233}
2234
2235/** returns the number of used bytes in the block memory */
2237 const BMS_BLKMEM* blkmem /**< block memory */
2238 )
2239{
2240 assert( blkmem != NULL );
2241
2242 return blkmem->memused;
2243}
2244
2245/** returns the number of allocated but not used bytes in the block memory */
2247 const BMS_BLKMEM* blkmem /**< block memory */
2248 )
2249{
2250 assert( blkmem != NULL );
2251
2252 return blkmem->memallocated - blkmem->memused;
2253}
2254
2255/** returns the maximal number of used bytes in the block memory */
2257 const BMS_BLKMEM* blkmem /**< block memory */
2258 )
2259{
2260 assert( blkmem != NULL );
2261
2262 return blkmem->maxmemused;
2263}
2264
2265/** returns the maximal number of allocated but not used bytes in the block memory */
2267 const BMS_BLKMEM* blkmem /**< block memory */
2268 )
2269{
2270 assert( blkmem != NULL );
2271
2272 return blkmem->maxmemunused;
2273}
2274
2275/** returns the maximal number of allocated bytes in the block memory */
2277 const BMS_BLKMEM* blkmem /**< block memory */
2278 )
2279{
2280 assert( blkmem != NULL );
2281
2282 return blkmem->maxmemallocated;
2283}
2284
2285/** returns the size of the given memory element; returns 0, if the element is not member of the block memory */
2287 const BMS_BLKMEM* blkmem, /**< block memory */
2288 const void* ptr /**< memory element */
2289 )
2290{
2291 const BMS_CHKMEM* chkmem;
2292
2293 assert(blkmem != NULL);
2294
2295 if( ptr == NULL )
2296 return 0;
2297
2298 chkmem = findChkmem(blkmem, ptr);
2299 if( chkmem == NULL )
2300 return 0;
2301
2302 return (size_t)(chkmem->elemsize); /*lint !e571*/
2303}
2304
2305/** outputs allocation diagnostics of block memory */
2307 const BMS_BLKMEM* blkmem /**< block memory */
2308 )
2309{
2310 const BMS_CHKMEM* chkmem;
2311 int nblocks = 0;
2312 int nunusedblocks = 0;
2313 int totalnchunks = 0;
2314 int totalneagerchunks = 0;
2315 int totalnelems = 0;
2316 int totalneagerelems = 0;
2317 int totalnlazyelems = 0;
2318#ifndef NDEBUG
2319 int totalngarbagecalls = 0;
2320 int totalngarbagefrees = 0;
2321#endif
2322 long long allocedmem = 0;
2323 long long freemem = 0;
2324 int i;
2325
2326#ifndef NDEBUG
2327 printInfo(" ElSize #Chunk #Eag #Elems #EagFr #LazFr #GCl #GFr Free MBytes First Allocator\n");
2328#else
2329 printInfo(" ElSize #Chunk #Eag #Elems #EagFr #LazFr Free MBytes\n");
2330#endif
2331
2332 assert(blkmem != NULL);
2333
2334 for( i = 0; i < CHKHASH_SIZE; ++i )
2335 {
2336 chkmem = blkmem->chkmemhash[i];
2337 while( chkmem != NULL )
2338 {
2339 int nchunks = 0;
2340 int nelems = 0;
2341 int neagerchunks = 0;
2342 int neagerelems = 0;
2343
2344 FOR_EACH_NODE(CHUNK*, chunk, chkmem->rootchunk,
2345 {
2346 assert(chunk != NULL);
2347 assert(chunk->elemsize == chkmem->elemsize);
2348 assert(chunk->chkmem == chkmem);
2349 nchunks++;
2350 nelems += chunk->storesize;
2351 if( chunk->eagerfree != NULL )
2352 {
2353 neagerchunks++;
2354 neagerelems += chunk->eagerfreesize;
2355 }
2356 })
2357
2358 assert(nchunks == chkmem->nchunks);
2359 assert(nelems == chkmem->storesize);
2360 assert(neagerelems == chkmem->eagerfreesize);
2361
2362 if( nelems > 0 )
2363 {
2364 nblocks++;
2365 allocedmem += (long long)chkmem->elemsize * (long long)nelems;
2366 freemem += (long long)chkmem->elemsize * ((long long)neagerelems + (long long)chkmem->lazyfreesize);
2367
2368#ifndef NDEBUG
2369 printInfo("%7d %6d %4d %7d %7d %7d %5d %4d %5.1f%% %6.1f %s:%d\n",
2370 chkmem->elemsize, nchunks, neagerchunks, nelems,
2371 neagerelems, chkmem->lazyfreesize, chkmem->ngarbagecalls, chkmem->ngarbagefrees,
2372 100.0 * (double) (neagerelems + chkmem->lazyfreesize) / (double) (nelems),
2373 (double)chkmem->elemsize * nelems / (1024.0*1024.0),
2374 chkmem->filename, chkmem->line);
2375#else
2376 printInfo("%7d %6d %4d %7d %7d %7d %5.1f%% %6.1f\n",
2377 chkmem->elemsize, nchunks, neagerchunks, nelems,
2378 neagerelems, chkmem->lazyfreesize,
2379 100.0 * (double) (neagerelems + chkmem->lazyfreesize) / (double) (nelems),
2380 (double)chkmem->elemsize * nelems / (1024.0*1024.0));
2381#endif
2382 }
2383 else
2384 {
2385#ifndef NDEBUG
2386 printInfo("%7d <unused> %5d %4d %s:%d\n",
2387 chkmem->elemsize, chkmem->ngarbagecalls, chkmem->ngarbagefrees,
2388 chkmem->filename, chkmem->line);
2389#else
2390 printInfo("%7d <unused>\n", chkmem->elemsize);
2391#endif
2392 nunusedblocks++;
2393 }
2394 totalnchunks += nchunks;
2395 totalneagerchunks += neagerchunks;
2396 totalnelems += nelems;
2397 totalneagerelems += neagerelems;
2398 totalnlazyelems += chkmem->lazyfreesize;
2399#ifndef NDEBUG
2400 totalngarbagecalls += chkmem->ngarbagecalls;
2401 totalngarbagefrees += chkmem->ngarbagefrees;
2402#endif
2403 chkmem = chkmem->nextchkmem;
2404 }
2405 }
2406#ifndef NDEBUG
2407 printInfo(" Total %6d %4d %7d %7d %7d %5d %4d %5.1f%% %6.1f\n",
2408 totalnchunks, totalneagerchunks, totalnelems, totalneagerelems, totalnlazyelems,
2409 totalngarbagecalls, totalngarbagefrees,
2410 totalnelems > 0 ? 100.0 * (double) (totalneagerelems + totalnlazyelems) / (double) (totalnelems) : 0.0,
2411 (double)allocedmem/(1024.0*1024.0));
2412#else
2413 printInfo(" Total %6d %4d %7d %7d %7d %5.1f%% %6.1f\n",
2414 totalnchunks, totalneagerchunks, totalnelems, totalneagerelems, totalnlazyelems,
2415 totalnelems > 0 ? 100.0 * (double) (totalneagerelems + totalnlazyelems) / (double) (totalnelems) : 0.0,
2416 (double)allocedmem/(1024.0*1024.0));
2417#endif
2418 printInfo("%d blocks (%d unused), %" LONGINT_FORMAT " bytes allocated, %" LONGINT_FORMAT " bytes free", /* cppcheck-suppress syntaxError */
2419 nblocks + nunusedblocks, nunusedblocks, allocedmem, freemem);
2420 if( allocedmem > 0 )
2421 printInfo(" (%.1f%%)", 100.0 * (double) freemem / (double) allocedmem);
2422 printInfo("\n\n");
2423
2424 printInfo("Memory Peaks: Used Lazy Total\n");
2425 printInfo(" %6.1f %6.1f %6.1f MBytes\n", (double)blkmem->maxmemused / (1024.0 * 1024.0),
2426 (double)blkmem->maxmemunused / (1024.0 * 1024.0), (double)blkmem->maxmemallocated / (1024.0 * 1024.0));
2427}
2428
2429/** outputs error messages, if there are allocated elements in the block memory and returns number of unfreed bytes */
2431 const BMS_BLKMEM* blkmem /**< block memory */
2432 )
2433{
2434 const BMS_CHKMEM* chkmem;
2435 long long allocedmem = 0;
2436 long long freemem = 0;
2437 int i;
2438
2439 assert(blkmem != NULL);
2440
2441 for( i = 0; i < CHKHASH_SIZE; ++i )
2442 {
2443 chkmem = blkmem->chkmemhash[i];
2444 while( chkmem != NULL )
2445 {
2446 int nchunks = 0;
2447 int nelems = 0;
2448 int neagerelems = 0;
2449
2450 FOR_EACH_NODE(CHUNK*, chunk, chkmem->rootchunk,
2451 {
2452 assert(chunk != NULL);
2453 assert(chunk->elemsize == chkmem->elemsize);
2454 assert(chunk->chkmem == chkmem);
2455 nchunks++;
2456 nelems += chunk->storesize;
2457 if( chunk->eagerfree != NULL )
2458 neagerelems += chunk->eagerfreesize;
2459 })
2460
2461 assert(nchunks == chkmem->nchunks);
2462 SCIP_UNUSED(nchunks);
2463 assert(nelems == chkmem->storesize);
2464 assert(neagerelems == chkmem->eagerfreesize);
2465
2466 if( nelems > 0 )
2467 {
2468 allocedmem += (long long)chkmem->elemsize * (long long)nelems;
2469 freemem += (long long)chkmem->elemsize * ((long long)neagerelems + (long long)chkmem->lazyfreesize);
2470
2471 if( nelems != neagerelems + chkmem->lazyfreesize )
2472 {
2473#ifndef NDEBUG
2474 errorMessage("%" LONGINT_FORMAT " bytes (%d elements of size %" LONGINT_FORMAT ") not freed. First Allocator: %s:%d\n",
2475 (((long long)nelems - (long long)neagerelems) - (long long)chkmem->lazyfreesize)
2476 * (long long)(chkmem->elemsize),
2477 (nelems - neagerelems) - chkmem->lazyfreesize, (long long)(chkmem->elemsize),
2478 chkmem->filename, chkmem->line);
2479#else
2480 errorMessage("%" LONGINT_FORMAT " bytes (%d elements of size %" LONGINT_FORMAT ") not freed.\n",
2481 ((nelems - neagerelems) - chkmem->lazyfreesize) * (long long)(chkmem->elemsize),
2482 (nelems - neagerelems) - chkmem->lazyfreesize, (long long)(chkmem->elemsize));
2483#endif
2484 }
2485 }
2486 chkmem = chkmem->nextchkmem;
2487 }
2488 }
2489
2490 if( allocedmem != freemem )
2491 {
2492 errorMessage("%" LONGINT_FORMAT " bytes not freed in total.\n", allocedmem - freemem);
2493 }
2494
2495 return allocedmem - freemem;
2496}
2497
2498
2499
2500
2501
2502
2503/***********************************************************
2504 * Buffer Memory Management
2505 *
2506 * Efficient memory management for temporary objects
2507 ***********************************************************/
2508
2509/** memory buffer storage for temporary objects */
2511{
2512 void** data; /**< allocated memory chunks for arbitrary data */
2513 size_t* size; /**< sizes of buffers in bytes */
2514 unsigned int* used; /**< 1 iff corresponding buffer is in use */
2515 size_t totalmem; /**< total memory consumption of buffer */
2516 unsigned int clean; /**< 1 iff the memory blocks in the buffer should be initialized to zero? */
2517 size_t ndata; /**< number of memory chunks */
2518 size_t firstfree; /**< first unused memory chunk */
2519 double arraygrowfac; /**< memory growing factor for dynamically allocated arrays */
2520 unsigned int arraygrowinit; /**< initial size of dynamically allocated arrays */
2521};
2522
2523
2524/** creates memory buffer storage */
2526 double arraygrowfac, /**< memory growing factor for dynamically allocated arrays */
2527 int arraygrowinit, /**< initial size of dynamically allocated arrays */
2528 unsigned int clean, /**< should the memory blocks in the buffer be initialized to zero? */
2529 const char* filename, /**< source file of the function call */
2530 int line /**< line number in source file of the function call */
2531 )
2532{
2533 BMS_BUFMEM* buffer;
2534
2535 assert( arraygrowinit > 0 );
2536 assert( arraygrowfac > 0.0 );
2537
2538 BMSallocMemory(&buffer);
2539 if ( buffer != NULL )
2540 {
2541 buffer->data = NULL;
2542 buffer->size = NULL;
2543 buffer->used = NULL;
2544 buffer->totalmem = 0UL;
2545 buffer->clean = clean;
2546 buffer->ndata = 0;
2547 buffer->firstfree = 0;
2548 buffer->arraygrowinit = (unsigned) arraygrowinit;
2549 buffer->arraygrowfac = arraygrowfac;
2550 }
2551 else
2552 {
2553 printErrorHeader(filename, line);
2554 printError("Insufficient memory for buffer memory header.\n");
2555 }
2556
2557 return buffer;
2558}
2559
2560/** destroys buffer memory */
2562 BMS_BUFMEM** buffer, /**< pointer to memory buffer storage */
2563 const char* filename, /**< source file of the function call */
2564 int line /**< line number in source file of the function call */
2565 )
2566{
2567 size_t i;
2568
2569 if ( *buffer != NULL )
2570 {
2571 i = (*buffer)->ndata;
2572 if ( i > 0 ) {
2573 for (--i ; ; i--)
2574 {
2575 assert( ! (*buffer)->used[i] );
2576 BMSfreeMemoryArrayNull(&(*buffer)->data[i]);
2577 if ( i == 0 )
2578 break;
2579 }
2580 }
2581 BMSfreeMemoryArrayNull(&(*buffer)->data);
2582 BMSfreeMemoryArrayNull(&(*buffer)->size);
2583 BMSfreeMemoryArrayNull(&(*buffer)->used);
2584 BMSfreeMemory(buffer);
2585 }
2586 else
2587 {
2588 printErrorHeader(filename, line);
2589 printError("Tried to free null buffer memory.\n");
2590 }
2591}
2592
2593/** set arraygrowfac */
2595 BMS_BUFMEM* buffer, /**< pointer to memory buffer storage */
2596 double arraygrowfac /**< memory growing factor for dynamically allocated arrays */
2597 )
2598{
2599 assert( buffer != NULL );
2600 assert( arraygrowfac > 0.0 );
2601
2602 buffer->arraygrowfac = arraygrowfac;
2603}
2604
2605/** set arraygrowinit */
2607 BMS_BUFMEM* buffer, /**< pointer to memory buffer storage */
2608 int arraygrowinit /**< initial size of dynamically allocated arrays */
2609 )
2610{
2611 assert( buffer != NULL );
2612 assert( arraygrowinit > 0 );
2613
2614 buffer->arraygrowinit = (unsigned) arraygrowinit;
2615}
2616
2617#ifndef SCIP_NOBUFFERMEM
2618/** calculate memory size for dynamically allocated arrays
2619 *
2620 * This function is a copy of the function in set.c in order to be able to use memory.? separately.
2621 */
2622static
2624 size_t initsize, /**< initial size of array */
2625 SCIP_Real growfac, /**< growing factor of array */
2626 size_t num /**< minimum number of entries to store */
2627 )
2628{
2629 size_t size;
2630
2631 assert( growfac >= 1.0 );
2632
2633 if ( growfac == 1.0 )
2634 size = MAX(initsize, num);
2635 else
2636 {
2637 size_t oldsize;
2638
2639 /* calculate the size with this loop, such that the resulting numbers are always the same */
2640 initsize = MAX(initsize, 4);
2641 size = initsize;
2642 oldsize = size - 1;
2643
2644 /* second condition checks against overflow */
2645 while ( size < num && size > oldsize )
2646 {
2647 oldsize = size;
2648 size = (size_t)(growfac * size + initsize);
2649 }
2650
2651 /* if an overflow happened, set the correct value */
2652 if ( size <= oldsize )
2653 size = num;
2654 }
2655
2656 assert( size >= initsize );
2657 assert( size >= num );
2658
2659 return size;
2660}
2661#endif
2662
2663/** work for allocating the next unused buffer */
2664INLINE static
2666 BMS_BUFMEM* buffer, /**< memory buffer storage */
2667 size_t size, /**< minimal required size of the buffer */
2668 const char* filename, /**< source file of the function call */
2669 int line /**< line number in source file of the function call */
2670 )
2671{
2672 void* ptr;
2673#ifndef SCIP_NOBUFFERMEM
2674 size_t bufnum;
2675#endif
2676
2677#ifndef SCIP_NOBUFFERMEM
2678 assert( buffer != NULL );
2679 assert( buffer->firstfree <= buffer->ndata );
2680
2681 /* allocate a minimum of 1 byte */
2682 if ( size == 0 )
2683 size = 1;
2684
2685 /* check, if we need additional buffers */
2686 if ( buffer->firstfree == buffer->ndata )
2687 {
2688 size_t newsize;
2689 size_t i;
2690
2691 /* create additional buffers */
2692 newsize = calcMemoryGrowSize((size_t)buffer->arraygrowinit, buffer->arraygrowfac, buffer->firstfree + 1);
2693 BMSreallocMemoryArray(&buffer->data, newsize);
2694 if ( buffer->data == NULL )
2695 {
2696 printErrorHeader(filename, line);
2697 printError("Insufficient memory for reallocating buffer data storage.\n");
2698 return NULL;
2699 }
2700 BMSreallocMemoryArray(&buffer->size, newsize);
2701 if ( buffer->size == NULL )
2702 {
2703 printErrorHeader(filename, line);
2704 printError("Insufficient memory for reallocating buffer size storage.\n");
2705 return NULL;
2706 }
2707 BMSreallocMemoryArray(&buffer->used, newsize);
2708 if ( buffer->used == NULL )
2709 {
2710 printErrorHeader(filename, line);
2711 printError("Insufficient memory for reallocating buffer used storage.\n");
2712 return NULL;
2713 }
2714
2715 /* init data */
2716 for (i = buffer->ndata; i < newsize; ++i)
2717 {
2718 buffer->data[i] = NULL;
2719 buffer->size[i] = 0;
2720 buffer->used[i] = FALSE;
2721 }
2722 buffer->ndata = newsize;
2723 }
2724 assert(buffer->firstfree < buffer->ndata);
2725
2726 /* check, if the current buffer is large enough */
2727 bufnum = buffer->firstfree;
2728 assert( ! buffer->used[bufnum] );
2729 if ( buffer->size[bufnum] < size )
2730 {
2731 size_t newsize;
2732
2733 /* enlarge buffer */
2734 newsize = calcMemoryGrowSize((size_t)buffer->arraygrowinit, buffer->arraygrowfac, size);
2735 BMSreallocMemorySize(&buffer->data[bufnum], newsize);
2736
2737 /* clear new memory */
2738 if( buffer->clean )
2739 {
2740 char* tmpptr = (char*)(buffer->data[bufnum]);
2741 size_t inc = buffer->size[bufnum] / sizeof(*tmpptr);
2742 tmpptr += inc;
2743
2744 BMSclearMemorySize(tmpptr, newsize - buffer->size[bufnum]);
2745 }
2746 assert( newsize > buffer->size[bufnum] );
2747 buffer->totalmem += newsize - buffer->size[bufnum];
2748 buffer->size[bufnum] = newsize;
2749
2750 if ( buffer->data[bufnum] == NULL )
2751 {
2752 printErrorHeader(filename, line);
2753 printError("Insufficient memory for reallocating buffer storage.\n");
2754 return NULL;
2755 }
2756 }
2757 assert( buffer->size[bufnum] >= size );
2758
2759#ifdef CHECKCLEANBUFFER
2760 /* check that the memory is cleared */
2761 if( buffer->clean )
2762 {
2763 char* tmpptr = (char*)(buffer->data[bufnum]);
2764 unsigned int inc = buffer->size[bufnum] / sizeof(*tmpptr);
2765 tmpptr += inc;
2766
2767 while( --tmpptr >= (char*)(buffer->data[bufnum]) )
2768 assert(*tmpptr == '\0');
2769 }
2770#endif
2771
2772 ptr = buffer->data[bufnum];
2773 buffer->used[bufnum] = TRUE;
2774 buffer->firstfree++;
2775
2776 debugMessage("Allocated buffer %llu/%llu at %p of size %llu (required size: %llu) for pointer %p.\n",
2777 (unsigned long long)bufnum, (unsigned long long)(buffer->ndata), buffer->data[bufnum],
2778 (unsigned long long)(buffer->size[bufnum]), (unsigned long long)size, ptr);
2779
2780#else
2781 if( buffer->clean )
2782 {
2783 /* we should allocate at least one byte, otherwise BMSallocMemorySize will fail */
2784 size = MAX(size,1);
2785
2786 BMSallocClearMemorySize(&ptr, size);
2787 }
2788 else
2789 {
2790 BMSallocMemorySize(&ptr, size);
2791 }
2792#endif
2793
2794 return ptr;
2795}
2796
2797/** allocates the next unused buffer */
2799 BMS_BUFMEM* buffer, /**< memory buffer storage */
2800 size_t size, /**< minimal required size of the buffer */
2801 const char* filename, /**< source file of the function call */
2802 int line /**< line number in source file of the function call */
2803 )
2804{
2805#ifndef NDEBUG
2806 if ( size > MAXMEMSIZE )
2807 {
2808 printErrorHeader(filename, line);
2809 printError("Tried to allocate buffer of size exceeding %lu.\n", MAXMEMSIZE);
2810 return NULL;
2811 }
2812#endif
2813
2814 return BMSallocBufferMemory_work(buffer, size, filename, line);
2815}
2816
2817/** allocates the next unused buffer array */
2819 BMS_BUFMEM* buffer, /**< memory buffer storage */
2820 size_t num, /**< size of array to be allocated */
2821 size_t typesize, /**< size of components */
2822 const char* filename, /**< source file of the function call */
2823 int line /**< line number in source file of the function call */
2824 )
2825{
2826#ifndef NDEBUG
2827 if ( num > (MAXMEMSIZE / typesize) )
2828 {
2829 printErrorHeader(filename, line);
2830 printError("Tried to allocate buffer of size exceeding %lu.\n", MAXMEMSIZE);
2831 return NULL;
2832 }
2833#endif
2834
2835 return BMSallocBufferMemory_work(buffer, num * typesize, filename, line);
2836}
2837
2838/** allocates the next unused buffer and clears it */
2840 BMS_BUFMEM* buffer, /**< memory buffer storage */
2841 size_t num, /**< size of array to be allocated */
2842 size_t typesize, /**< size of components */
2843 const char* filename, /**< source file of the function call */
2844 int line /**< line number in source file of the function call */
2845 )
2846{
2847 void* ptr;
2848
2849 ptr = BMSallocBufferMemoryArray_call(buffer, num, typesize, filename, line);
2850 if ( ptr != NULL )
2851 BMSclearMemorySize(ptr, num * typesize);
2852
2853 return ptr;
2854}
2855
2856/** work for reallocating the buffer to at least the given size */
2857INLINE static
2859 BMS_BUFMEM* buffer, /**< memory buffer storage */
2860 void* ptr, /**< pointer to the allocated memory buffer */
2861 size_t size, /**< minimal required size of the buffer */
2862 const char* filename, /**< source file of the function call */
2863 int line /**< line number in source file of the function call */
2864 )
2865{
2866 void* newptr;
2867#ifndef SCIP_NOBUFFERMEM
2868 size_t bufnum;
2869#endif
2870
2871#ifndef SCIP_NOBUFFERMEM
2872 assert( buffer != NULL );
2873 assert( buffer->firstfree <= buffer->ndata );
2874 assert(!buffer->clean); /* reallocating clean buffer elements is not supported */
2875
2876 /* if the pointer doesn't exist yet, allocate it */
2877 if ( ptr == NULL )
2878 return BMSallocBufferMemory_call(buffer, size, filename, line);
2879
2880 assert( buffer->firstfree >= 1 );
2881
2882 /* Search the pointer in the buffer list:
2883 * Usually, buffers are allocated and freed like a stack, such that the currently used pointer is
2884 * most likely at the end of the buffer list.
2885 */
2886 bufnum = buffer->firstfree - 1;
2887 while ( bufnum > 0 && buffer->data[bufnum] != ptr )
2888 --bufnum;
2889
2890 newptr = ptr;
2891 assert( buffer->data[bufnum] == newptr );
2892 assert( buffer->used[bufnum] );
2893 assert( buffer->size[bufnum] >= 1 );
2894
2895 /* check if the buffer has to be enlarged */
2896 if ( size > buffer->size[bufnum] )
2897 {
2898 size_t newsize;
2899
2900 /* enlarge buffer */
2901 newsize = calcMemoryGrowSize((size_t)buffer->arraygrowinit, buffer->arraygrowfac, size);
2902 BMSreallocMemorySize(&buffer->data[bufnum], newsize);
2903 assert( newsize > buffer->size[bufnum] );
2904 buffer->totalmem += newsize - buffer->size[bufnum];
2905 buffer->size[bufnum] = newsize;
2906 if ( buffer->data[bufnum] == NULL )
2907 {
2908 printErrorHeader(filename, line);
2909 printError("Insufficient memory for reallocating buffer storage.\n");
2910 return NULL;
2911 }
2912 newptr = buffer->data[bufnum];
2913 }
2914 assert( buffer->size[bufnum] >= size );
2915 assert( newptr == buffer->data[bufnum] );
2916
2917 debugMessage("Reallocated buffer %llu/%llu at %p to size %llu (required size: %llu) for pointer %p.\n",
2918 (unsigned long long)bufnum, (unsigned long long)(buffer->ndata), buffer->data[bufnum],
2919 (unsigned long long)(buffer->size[bufnum]), (unsigned long long)size, newptr);
2920
2921#else
2922 newptr = ptr;
2923 BMSreallocMemorySize(&newptr, size);
2924#endif
2925
2926 return newptr;
2927}
2928
2929/** reallocates the buffer to at least the given size */
2931 BMS_BUFMEM* buffer, /**< memory buffer storage */
2932 void* ptr, /**< pointer to the allocated memory buffer */
2933 size_t size, /**< minimal required size of the buffer */
2934 const char* filename, /**< source file of the function call */
2935 int line /**< line number in source file of the function call */
2936 )
2937{
2938#ifndef NDEBUG
2939 if ( size > MAXMEMSIZE )
2940 {
2941 printErrorHeader(filename, line);
2942 printError("Tried to allocate buffer of size exceeding %lu.\n", MAXMEMSIZE);
2943 return NULL;
2944 }
2945#endif
2946
2947 return BMSreallocBufferMemory_work(buffer, ptr, size, filename, line);
2948}
2949
2950/** reallocates an array in the buffer to at least the given size */
2952 BMS_BUFMEM* buffer, /**< memory buffer storage */
2953 void* ptr, /**< pointer to the allocated memory buffer */
2954 size_t num, /**< size of array to be allocated */
2955 size_t typesize, /**< size of components */
2956 const char* filename, /**< source file of the function call */
2957 int line /**< line number in source file of the function call */
2958 )
2959{
2960#ifndef NDEBUG
2961 if ( num > (MAXMEMSIZE / typesize) )
2962 {
2963 printErrorHeader(filename, line);
2964 printError("Tried to allocate array of size exceeding %lu.\n", MAXMEMSIZE);
2965 return NULL;
2966 }
2967#endif
2968
2969 return BMSreallocBufferMemory_work(buffer, ptr, num * typesize, filename, line);
2970}
2971
2972/** allocates the next unused buffer and copies the given memory into the buffer */
2974 BMS_BUFMEM* buffer, /**< memory buffer storage */
2975 const void* source, /**< memory block to copy into the buffer */
2976 size_t size, /**< minimal required size of the buffer */
2977 const char* filename, /**< source file of the function call */
2978 int line /**< line number in source file of the function call */
2979 )
2980{
2981 void* ptr;
2982
2983 assert( source != NULL );
2984
2985 /* allocate a buffer of the given size */
2986 ptr = BMSallocBufferMemory_call(buffer, size, filename, line);
2987
2988 /* copy the source memory into the buffer */
2989 if ( ptr != NULL )
2990 BMScopyMemorySize(ptr, source, size);
2991
2992 return ptr;
2993}
2994
2995/** allocates an array in the next unused buffer and copies the given memory into the buffer */
2997 BMS_BUFMEM* buffer, /**< memory buffer storage */
2998 const void* source, /**< memory block to copy into the buffer */
2999 size_t num, /**< size of array to be allocated */
3000 size_t typesize, /**< size of components */
3001 const char* filename, /**< source file of the function call */
3002 int line /**< line number in source file of the function call */
3003 )
3004{
3005 void* ptr;
3006
3007 assert( source != NULL );
3008
3009 /* allocate a buffer of the given size */
3010 ptr = BMSallocBufferMemoryArray_call(buffer, num, typesize, filename, line);
3011
3012 /* copy the source memory into the buffer */
3013 if ( ptr != NULL )
3014 BMScopyMemorySize(ptr, source, num * typesize);
3015
3016 return ptr;
3017}
3018
3019/** work for freeing a buffer */
3020INLINE static
3022 BMS_BUFMEM* buffer, /**< memory buffer storage */
3023 void** ptr, /**< pointer to pointer to the allocated memory buffer */
3024 const char* filename, /**< source file of the function call */
3025 int line /**< line number in source file of the function call */
3026 )
3027{ /*lint --e{715}*/
3028 size_t bufnum;
3029
3030 assert( buffer != NULL );
3031 assert( buffer->firstfree <= buffer->ndata );
3032 assert( buffer->firstfree >= 1 );
3033 assert( ptr != NULL );
3034 assert( *ptr != NULL );
3035
3036 /* Search the pointer in the buffer list:
3037 * Usually, buffers are allocated and freed like a stack, such that the freed pointer is
3038 * most likely at the end of the buffer list.
3039 */
3040 bufnum = buffer->firstfree-1;
3041 while ( bufnum > 0 && buffer->data[bufnum] != *ptr )
3042 --bufnum;
3043
3044#ifdef CHECKBUFFERORDER
3045 if ( bufnum < buffer->firstfree - 1 )
3046 {
3047 warningMessage("[%s:%d]: freeing buffer in wrong order.\n", filename, line);
3048 }
3049#endif
3050
3051#ifndef NDEBUG
3052 if ( bufnum == 0 && buffer->data[bufnum] != *ptr )
3053 {
3054 printErrorHeader(filename, line);
3055 printError("Tried to free unknown buffer pointer.\n");
3056 return;
3057 }
3058 if ( ! buffer->used[bufnum] )
3059 {
3060 printErrorHeader(filename, line);
3061 printError("Tried to free buffer pointer already freed.\n");
3062 return;
3063 }
3064#endif
3065
3066#ifdef CHECKCLEANBUFFER
3067 /* check that the memory is cleared */
3068 if( buffer->clean )
3069 {
3070 size_t i;
3071 uint8_t* tmpptr = (uint8_t*)(buffer->data[bufnum]);
3072
3073 for( i = 0; i < buffer->size[bufnum]; ++i )
3074 assert(tmpptr[i] == 0);
3075 }
3076#endif
3077
3078 assert( buffer->data[bufnum] == *ptr );
3079 buffer->used[bufnum] = FALSE;
3080
3081 while ( buffer->firstfree > 0 && !buffer->used[buffer->firstfree-1] )
3082 --buffer->firstfree;
3083
3084 debugMessage("Freed buffer %llu/%llu at %p of size %llu for pointer %p, first free is %llu.\n",
3085 (unsigned long long)bufnum, (unsigned long long)(buffer->ndata), buffer->data[bufnum],
3086 (unsigned long long)(buffer->size[bufnum]), *ptr, (unsigned long long)(buffer->firstfree));
3087
3088 *ptr = NULL;
3089}
3090
3091/** frees a buffer and sets pointer to NULL */
3093 BMS_BUFMEM* buffer, /**< memory buffer storage */
3094 void** ptr, /**< pointer to pointer to the allocated memory buffer */
3095 const char* filename, /**< source file of the function call */
3096 int line /**< line number in source file of the function call */
3097 )
3098{ /*lint --e{715}*/
3099 assert( ptr != NULL );
3100
3101#ifndef SCIP_NOBUFFERMEM
3102 if ( *ptr != NULL )
3103 BMSfreeBufferMemory_work(buffer, ptr, filename, line);
3104 else
3105 {
3106 printErrorHeader(filename, line);
3107 printError("Tried to free null buffer pointer.\n");
3108 }
3109#else
3110 BMSfreeMemory(ptr);
3111#endif
3112}
3113
3114/** frees a buffer if pointer is not NULL and sets pointer to NULL */
3116 BMS_BUFMEM* buffer, /**< memory buffer storage */
3117 void** ptr, /**< pointer to pointer to the allocated memory buffer */
3118 const char* filename, /**< source file of the function call */
3119 int line /**< line number in source file of the function call */
3120 )
3121{ /*lint --e{715}*/
3122 assert( ptr != NULL );
3123
3124 if ( *ptr != NULL )
3125 {
3126#ifndef SCIP_NOBUFFERMEM
3127 BMSfreeBufferMemory_work(buffer, ptr, filename, line);
3128#else
3129 BMSfreeMemory(ptr);
3130#endif
3131 }
3132}
3133
3134/** gets number of used buffers */
3136 BMS_BUFMEM* buffer /**< memory buffer storage */
3137 )
3138{
3139 assert( buffer != NULL );
3140
3141 return buffer->firstfree;
3142}
3143
3144/** returns the number of allocated bytes in the buffer memory */
3146 const BMS_BUFMEM* buffer /**< buffer memory */
3147 )
3148{
3149#ifdef CHECKMEM
3150 size_t totalmem = 0UL;
3151 size_t i;
3152
3153 assert( buffer != NULL );
3154 for (i = 0; i < buffer->ndata; ++i)
3155 totalmem += buffer->size[i];
3156 assert( totalmem == buffer->totalmem );
3157#endif
3158
3159 return (long long) buffer->totalmem;
3160}
3161
3162/** outputs statistics about currently allocated buffers to the screen */
3164 BMS_BUFMEM* buffer /**< memory buffer storage */
3165 )
3166{
3167 size_t totalmem;
3168 size_t i;
3169
3170 assert( buffer != NULL );
3171
3172 totalmem = 0UL;
3173 for (i = 0; i < buffer->ndata; ++i)
3174 {
3175 printf("[%c] %8llu bytes at %p\n", buffer->used[i] ? '*' : ' ', (unsigned long long)(buffer->size[i]), buffer->data[i]);
3176 totalmem += buffer->size[i];
3177 }
3178 printf(" %8llu bytes total in %llu buffers\n", (unsigned long long)totalmem, (unsigned long long)(buffer->ndata));
3179}
common defines and data types used in all packages of SCIP
#define NULL
Definition: def.h:262
#define INLINE
Definition: def.h:128
#define SCIP_UNUSED(x)
Definition: def.h:423
#define MIN(x, y)
Definition: def.h:238
#define SCIP_Real
Definition: def.h:172
#define TRUE
Definition: def.h:93
#define FALSE
Definition: def.h:94
#define MAX(x, y)
Definition: def.h:234
static CHUNK * findChunk(const BMS_CHKMEM *chkmem, const void *ptr)
Definition: memory.c:805
void BMSfreeChunkMemory_call(BMS_CHKMEM *chkmem, void **ptr, size_t size, const char *filename, int line)
Definition: memory.c:1576
#define LONGINT_FORMAT
Definition: memory.c:117
void * BMSallocClearMemory_call(size_t num, size_t typesize, const char *filename, int line)
Definition: memory.c:350
static int isPtrInChkmem(const BMS_CHKMEM *chkmem, const void *ptr)
Definition: memory.c:824
#define printError
Definition: memory.c:92
void * BMSduplicateBufferMemory_call(BMS_BUFMEM *buffer, const void *source, size_t size, const char *filename, int line)
Definition: memory.c:2973
void * BMSduplicateMemoryArray_call(const void *source, size_t num, size_t typesize, const char *filename, int line)
Definition: memory.c:600
#define removeMemlistEntry(ptr, filename, line)
Definition: memory.c:309
void * BMSallocMemory_call(size_t size, const char *filename, int line)
Definition: memory.c:389
void BMSfreeBlockMemoryNull_call(BMS_BLKMEM *blkmem, void **ptr, size_t size, const char *filename, int line)
Definition: memory.c:2171
#define CHUNK_LT(ptr, chunk)
Definition: memory.c:748
static void destroyChunk(CHUNK **chunk, long long *memsize)
Definition: memory.c:1110
void BMSgarbagecollectChunkMemory_call(BMS_CHKMEM *chkmem)
Definition: memory.c:1629
size_t BMSgetBlockPointerSize_call(const BMS_BLKMEM *blkmem, const void *ptr)
Definition: memory.c:2286
#define STORESIZE_MAX
Definition: memory.c:695
void BMSdisplayMemory_call(void)
Definition: memory.c:325
static void destroyChkmem(BMS_CHKMEM **chkmem, long long *memsize)
Definition: memory.c:1296
static INLINE void BMSfreeBlockMemory_work(BMS_BLKMEM *blkmem, void **ptr, size_t size, const char *filename, int line)
Definition: memory.c:2100
int BMSisAligned(size_t size)
Definition: memory.c:777
void BMSclearBlockMemory_call(BMS_BLKMEM *blkmem, const char *filename, int line)
Definition: memory.c:1770
struct Chunk CHUNK
Definition: memory.c:700
#define CHUNK_GT(ptr, chunk)
Definition: memory.c:749
long long BMScheckEmptyBlockMemory_call(const BMS_BLKMEM *blkmem)
Definition: memory.c:2430
long long BMSgetBufferMemoryUsed(const BMS_BUFMEM *buffer)
Definition: memory.c:3145
#define ALIGNMENT
Definition: memory.c:697
void BMSfreeBufferMemory_call(BMS_BUFMEM *buffer, void **ptr, const char *filename, int line)
Definition: memory.c:3092
void BMSfreeMemory_call(void **ptr, const char *filename, int line)
Definition: memory.c:620
size_t BMSgetPointerSize_call(const void *ptr)
Definition: memory.c:316
#define CHKHASH_SIZE
Definition: memory.c:666
void * BMSreallocBlockMemory_call(BMS_BLKMEM *blkmem, void *ptr, size_t oldsize, size_t newsize, const char *filename, int line)
Definition: memory.c:1979
void BMSfreeMemoryNull_call(void **ptr, const char *filename, int line)
Definition: memory.c:642
void BMSsetBufferMemoryArraygrowinit(BMS_BUFMEM *buffer, int arraygrowinit)
Definition: memory.c:2606
static void unlinkChunk(CHUNK *chunk)
Definition: memory.c:962
static uint32_t getHashNumber(size_t size)
Definition: memory.c:1726
void BMSdestroyBufferMemory_call(BMS_BUFMEM **buffer, const char *filename, int line)
Definition: memory.c:2561
#define MAXMEMSIZE
Definition: memory.c:124
#define addMemlistEntry(ptr, size, filename, line)
Definition: memory.c:308
void BMSclearChunkMemory_call(BMS_CHKMEM *chkmem, const char *filename, int line)
Definition: memory.c:1487
void * BMSreallocBufferMemory_call(BMS_BUFMEM *buffer, void *ptr, size_t size, const char *filename, int line)
Definition: memory.c:2930
static INLINE void BMSfreeBufferMemory_work(BMS_BUFMEM *buffer, void **ptr, const char *filename, int line)
Definition: memory.c:3021
static size_t calcMemoryGrowSize(size_t initsize, SCIP_Real growfac, size_t num)
Definition: memory.c:2623
#define printErrorHeader(f, l)
Definition: memory.c:91
void * BMSreallocMemoryArray_call(void *ptr, size_t num, size_t typesize, const char *filename, int line)
Definition: memory.c:497
long long BMSgetBlockMemoryUsedMax_call(const BMS_BLKMEM *blkmem)
Definition: memory.c:2256
static BMS_CHKMEM * findChkmem(const BMS_BLKMEM *blkmem, const void *ptr)
Definition: memory.c:1703
static BMS_CHKMEM * createChkmem(int size, int initchunksize, int garbagefactor, long long *memsize)
Definition: memory.c:1227
void * BMSallocBufferMemoryArray_call(BMS_BUFMEM *buffer, size_t num, size_t typesize, const char *filename, int line)
Definition: memory.c:2818
void BMSmoveMemory_call(void *ptr, const void *source, size_t size)
Definition: memory.c:566
static void freeChunk(CHUNK **chunk, long long *memsize)
Definition: memory.c:1129
static void freeChkmemElement(BMS_CHKMEM *chkmem, void *ptr, long long *memsize, const char *filename, int line)
Definition: memory.c:1426
static void freeChunkElement(CHUNK *chunk, void *ptr)
Definition: memory.c:1198
void * BMSallocBlockMemoryArray_call(BMS_BLKMEM *blkmem, size_t num, size_t typesize, const char *filename, int line)
Definition: memory.c:1940
#define printInfo
Definition: memory.c:98
static INLINE void * BMSallocBlockMemory_work(BMS_BLKMEM *blkmem, size_t size, const char *filename, int line)
Definition: memory.c:1827
void * BMSreallocBufferMemoryArray_call(BMS_BUFMEM *buffer, void *ptr, size_t num, size_t typesize, const char *filename, int line)
Definition: memory.c:2951
#define CHUNKLENGTH_MIN
Definition: memory.c:693
static void garbagecollectChkmem(BMS_CHKMEM *chkmem, long long *memsize)
Definition: memory.c:1358
void BMSdisplayBlockMemory_call(const BMS_BLKMEM *blkmem)
Definition: memory.c:2306
long long BMSgetBlockMemoryAllocated_call(const BMS_BLKMEM *blkmem)
Definition: memory.c:2226
void BMSclearMemory_call(void *ptr, size_t size)
Definition: memory.c:536
long long BMSgetBlockMemoryUsed_call(const BMS_BLKMEM *blkmem)
Definition: memory.c:2236
void BMSfreeBufferMemoryNull_call(BMS_BUFMEM *buffer, void **ptr, const char *filename, int line)
Definition: memory.c:3115
void * BMSallocChunkMemory_call(BMS_CHKMEM *chkmem, size_t size, const char *filename, int line)
Definition: memory.c:1527
void * BMSreallocMemory_call(void *ptr, size_t size, const char *filename, int line)
Definition: memory.c:461
BMS_BLKMEM * BMScreateBlockMemory_call(int initchunksize, int garbagefactor, const char *filename, int line)
Definition: memory.c:1736
void * BMSallocClearBlockMemoryArray_call(BMS_BLKMEM *blkmem, size_t num, size_t typesize, const char *filename, int line)
Definition: memory.c:1961
void * BMSduplicateBlockMemoryArray_call(BMS_BLKMEM *blkmem, const void *source, size_t num, size_t typesize, const char *filename, int line)
Definition: memory.c:2078
void * BMSduplicateMemory_call(const void *source, size_t size, const char *filename, int line)
Definition: memory.c:581
BMS_BUFMEM * BMScreateBufferMemory_call(double arraygrowfac, int arraygrowinit, unsigned int clean, const char *filename, int line)
Definition: memory.c:2525
static INLINE void * BMSreallocBufferMemory_work(BMS_BUFMEM *buffer, void *ptr, size_t size, const char *filename, int line)
Definition: memory.c:2858
static void unlinkEagerChunk(CHUNK *chunk)
Definition: memory.c:1010
void BMSdestroyBlockMemory_call(BMS_BLKMEM **blkmem, const char *filename, int line)
Definition: memory.c:1804
static SCIP_DEF_RBTREE_FIND(rbTreeFindChunk, const void *, CHUNK, CHUNK_LT, CHUNK_GT)
Definition: memory.c:752
static void linkEagerChunk(BMS_CHKMEM *chkmem, CHUNK *chunk)
Definition: memory.c:989
void * BMSallocMemoryArray_call(size_t num, size_t typesize, const char *filename, int line)
Definition: memory.c:423
long long BMSgetBlockMemoryUnused_call(const BMS_BLKMEM *blkmem)
Definition: memory.c:2246
void BMSprintBufferMemory(BMS_BUFMEM *buffer)
Definition: memory.c:3163
void * BMSduplicateChunkMemory_call(BMS_CHKMEM *chkmem, const void *source, size_t size, const char *filename, int line)
Definition: memory.c:1554
#define CHKHASH_POWER
Definition: memory.c:665
#define errorMessage
Definition: memory.c:90
long long BMSgetMemoryUsed_call(void)
Definition: memory.c:340
void BMScheckEmptyMemory_call(void)
Definition: memory.c:333
static int linkChunk(BMS_CHKMEM *chkmem, CHUNK *chunk)
Definition: memory.c:934
static void * allocChkmemElement(BMS_CHKMEM *chkmem, long long *memsize)
Definition: memory.c:1318
static void clearChkmem(BMS_CHKMEM *chkmem, long long *memsize)
Definition: memory.c:1271
#define checkBlkmem(blkmem)
Definition: memory.c:1693
void * BMSallocClearBlockMemory_call(BMS_BLKMEM *blkmem, size_t size, const char *filename, int line)
Definition: memory.c:1923
void * BMSallocBufferMemory_call(BMS_BUFMEM *buffer, size_t size, const char *filename, int line)
Definition: memory.c:2798
BMS_CHKMEM * BMScreateChunkMemory_call(size_t size, int initchunksize, int garbagefactor, const char *filename, int line)
Definition: memory.c:1463
static INLINE void * BMSallocBufferMemory_work(BMS_BUFMEM *buffer, size_t size, const char *filename, int line)
Definition: memory.c:2665
void * BMSallocBlockMemory_call(BMS_BLKMEM *blkmem, size_t size, const char *filename, int line)
Definition: memory.c:1903
void BMScopyMemory_call(void *ptr, const void *source, size_t size)
Definition: memory.c:549
static void * allocChunkElement(CHUNK *chunk)
Definition: memory.c:1161
#define checkChkmem(chkmem)
Definition: memory.c:926
#define CHUNKLENGTH_MAX
Definition: memory.c:694
static int createChunk(BMS_CHKMEM *chkmem, long long *memsize)
Definition: memory.c:1035
long long BMSgetChunkMemoryUsed_call(const BMS_CHKMEM *chkmem)
Definition: memory.c:1639
void BMSfreeChunkMemoryNull_call(BMS_CHKMEM *chkmem, void **ptr, size_t size, const char *filename, int line)
Definition: memory.c:1605
void BMSsetBufferMemoryArraygrowfac(BMS_BUFMEM *buffer, double arraygrowfac)
Definition: memory.c:2594
struct Freelist FREELIST
Definition: memory.c:699
static int isPtrInChunk(const CHUNK *chunk, const void *ptr)
Definition: memory.c:788
void * BMSduplicateBufferMemoryArray_call(BMS_BUFMEM *buffer, const void *source, size_t num, size_t typesize, const char *filename, int line)
Definition: memory.c:2996
void BMSdestroyChunkMemory_call(BMS_CHKMEM **chkmem, const char *filename, int line)
Definition: memory.c:1506
void BMSgarbagecollectBlockMemory_call(BMS_BLKMEM *blkmem)
Definition: memory.c:2192
void BMSfreeBlockMemory_call(BMS_BLKMEM *blkmem, void **ptr, size_t size, const char *filename, int line)
Definition: memory.c:2149
void * BMSallocClearBufferMemoryArray_call(BMS_BUFMEM *buffer, size_t num, size_t typesize, const char *filename, int line)
Definition: memory.c:2839
#define GARBAGE_SIZE
Definition: memory.c:696
long long BMSgetBlockMemoryUnusedMax_call(const BMS_BLKMEM *blkmem)
Definition: memory.c:2266
void * BMSduplicateBlockMemory_call(BMS_BLKMEM *blkmem, const void *source, size_t size, const char *filename, int line)
Definition: memory.c:2058
#define debugMessage
Definition: memory.c:89
void BMSalignMemsize(size_t *size)
Definition: memory.c:768
void * BMSreallocBlockMemoryArray_call(BMS_BLKMEM *blkmem, void *ptr, size_t oldnum, size_t newnum, size_t typesize, const char *filename, int line)
Definition: memory.c:2019
size_t BMSgetNUsedBufferMemory(BMS_BUFMEM *buffer)
Definition: memory.c:3135
long long BMSgetBlockMemoryAllocatedMax_call(const BMS_BLKMEM *blkmem)
Definition: memory.c:2276
#define checkChunk(chunk)
Definition: memory.c:925
memory allocation routines
#define BMSallocClearMemorySize(ptr, size)
Definition: memory.h:122
#define BMSfreeMemory(ptr)
Definition: memory.h:145
#define BMSreallocMemoryArray(ptr, num)
Definition: memory.h:127
struct BMS_ChkMem BMS_CHKMEM
Definition: memory.h:302
#define BMSduplicateMemoryArray(ptr, source, num)
Definition: memory.h:143
#define BMSreallocMemorySize(ptr, size)
Definition: memory.h:126
#define BMScopyMemorySize(ptr, source, size)
Definition: memory.h:135
#define BMSclearMemorySize(ptr, size)
Definition: memory.h:131
struct BMS_BlkMem BMS_BLKMEM
Definition: memory.h:437
#define BMSfreeMemoryArrayNull(ptr)
Definition: memory.h:148
#define BMSallocMemorySize(ptr, size)
Definition: memory.h:120
#define BMSallocMemory(ptr)
Definition: memory.h:118
public methods for message output
intrusive red black tree datastructure
#define SCIP_RBTREE_HOOKS
Definition: rbtree.h:62
#define SCIPrbtreeDelete(root, node)
Definition: rbtree.h:69
#define SCIPrbtreeInsert(r, p, c, n)
Definition: rbtree.h:70
#define FOR_EACH_NODE(type, n, r, body)
Definition: rbtree.h:77
size_t * size
Definition: memory.c:2513
unsigned int * used
Definition: memory.c:2514
void ** data
Definition: memory.c:2512
size_t firstfree
Definition: memory.c:2518
double arraygrowfac
Definition: memory.c:2519
unsigned int arraygrowinit
Definition: memory.c:2520
unsigned int clean
Definition: memory.c:2516
size_t totalmem
Definition: memory.c:2515
size_t ndata
Definition: memory.c:2517