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#ifdef CHECKCLEANBUFFER
930#define CHECKCLEANBUFFER_TESTSIZE 1048576 /**< size of test block */
931
932/** a memory block that will be initialized to all zero, to be used in memcmp() */
933static uint8_t checkcleanbuffer_testblock[CHECKCLEANBUFFER_TESTSIZE];
934
935/** whether checkcleanbuffer_testblock has been initialized to be all zero */
936static SCIP_Bool checkcleanbuffer_testblockinit = FALSE;
937
938/** check whether a memory block has all zero values */
939static
940void checkCleanmem(
941 void* mem, /**< memory block to check */
942 int size /**< size of memory block */
943 )
944{
945 uint8_t* startptr;
946 uint8_t* endptr;
947
948 if( !checkcleanbuffer_testblockinit )
949 {
950 BMSclearMemorySize(checkcleanbuffer_testblock, CHECKCLEANBUFFER_TESTSIZE);
951 checkcleanbuffer_testblockinit = TRUE;
952 }
953
954 for( startptr = (uint8_t*)mem, endptr = (uint8_t*)(mem) + size;
955 startptr + CHECKCLEANBUFFER_TESTSIZE < endptr;
956 startptr += CHECKCLEANBUFFER_TESTSIZE )
957 {
958 assert(memcmp(startptr, checkcleanbuffer_testblock, CHECKCLEANBUFFER_TESTSIZE) == 0);
959 }
960 assert(memcmp(startptr, checkcleanbuffer_testblock, endptr - startptr) == 0);
961}
962#endif
963
964/** links chunk to the block's chunk array, sort it by store pointer;
965 * returns TRUE if successful, FALSE otherwise
966 */
967static
969 BMS_CHKMEM* chkmem, /**< chunk block */
970 CHUNK* chunk /**< memory chunk */
971 )
972{
973 CHUNK* parent;
974 int pos;
975
976 assert(chkmem != NULL);
977 assert(chunk != NULL);
978 assert(chunk->store != NULL);
979
980 debugMessage("linking chunk %p to chunk block %p [elemsize:%d, %d chunks]\n",
981 (void*)chunk, (void*)chkmem, chkmem->elemsize, chkmem->nchunks);
982
983 pos = rbTreeFindChunk(chkmem->rootchunk, chunk->store, &parent);
984 assert(pos != 0);
985
986 SCIPrbtreeInsert(&chkmem->rootchunk, parent, pos, chunk);
987
988 chkmem->nchunks++;
989 chkmem->storesize += chunk->storesize;
990
991 return TRUE;
992}
993
994/** unlinks chunk from the chunk block's chunk list */
995static
997 CHUNK* chunk /**< memory chunk */
998 )
999{
1000 BMS_CHKMEM* chkmem;
1001
1002 assert(chunk != NULL);
1003 assert(chunk->eagerfree == NULL);
1004 assert(chunk->nexteager == NULL);
1005 assert(chunk->preveager == NULL);
1006
1007 chkmem = chunk->chkmem;
1008 assert(chkmem != NULL);
1009 assert(chkmem->elemsize == chunk->elemsize);
1010
1011 debugMessage("unlinking chunk %p from chunk block %p [elemsize:%d, %d chunks]\n",
1012 (void*)chunk, (void*)chkmem, chkmem->elemsize, chkmem->nchunks);
1013
1014 /* remove the chunk from the chunks of the chunk block */
1015 SCIPrbtreeDelete(&chkmem->rootchunk, chunk);
1016
1017 chkmem->nchunks--;
1018 chkmem->storesize -= chunk->storesize;
1019}
1020
1021/** links chunk to the chunk block's eager chunk list */
1022static
1024 BMS_CHKMEM* chkmem, /**< chunk block */
1025 CHUNK* chunk /**< memory chunk */
1026 )
1027{
1028 assert(chunk->chkmem == chkmem);
1029 assert(chunk->nexteager == NULL);
1030 assert(chunk->preveager == NULL);
1031
1032 chunk->nexteager = chkmem->firsteager;
1033 chunk->preveager = NULL;
1034 if( chkmem->firsteager != NULL )
1035 {
1036 assert(chkmem->firsteager->preveager == NULL);
1037 chkmem->firsteager->preveager = chunk;
1038 }
1039 chkmem->firsteager = chunk;
1040}
1041
1042/** unlinks chunk from the chunk block's eager chunk list */
1043static
1045 CHUNK* chunk /**< memory chunk */
1046 )
1047{
1048 assert(chunk != NULL);
1049 assert(chunk->eagerfreesize == 0 || chunk->eagerfreesize == chunk->storesize);
1050
1051 if( chunk->nexteager != NULL )
1052 chunk->nexteager->preveager = chunk->preveager;
1053 if( chunk->preveager != NULL )
1054 chunk->preveager->nexteager = chunk->nexteager;
1055 else
1056 {
1057 assert(chunk->chkmem->firsteager == chunk);
1058 chunk->chkmem->firsteager = chunk->nexteager;
1059 }
1060 chunk->nexteager = NULL;
1061 chunk->preveager = NULL;
1062 chunk->eagerfree = NULL;
1063}
1064
1065/** creates a new memory chunk in the given chunk block and adds memory elements to the lazy free list;
1066 * returns TRUE if successful, FALSE otherwise
1067 */
1068static
1070 BMS_CHKMEM* chkmem, /**< chunk block */
1071 long long* memsize /**< pointer to total size of allocated memory (or NULL) */
1072 )
1073{
1074 CHUNK *newchunk;
1075 FREELIST *freelist;
1076 int i;
1077 int storesize;
1078 int retval;
1079
1080 assert(chkmem != NULL);
1081
1082 debugMessage("creating new chunk in chunk block %p [elemsize: %d]\n", (void*)chkmem, chkmem->elemsize);
1083
1084 /* calculate store size */
1085 if( chkmem->nchunks == 0 )
1086 storesize = chkmem->initchunksize;
1087 else
1088 storesize = 2 * chkmem->lastchunksize;
1089 assert(storesize > 0);
1090 storesize = MAX(storesize, CHUNKLENGTH_MIN / chkmem->elemsize);
1091 storesize = MIN(storesize, CHUNKLENGTH_MAX / chkmem->elemsize);
1092 storesize = MIN(storesize, STORESIZE_MAX);
1093 storesize = MAX(storesize, 1);
1094 chkmem->lastchunksize = storesize;
1095
1096 /* create new chunk */
1097 assert(BMSisAligned(sizeof(CHUNK)));
1098 assert( chkmem->elemsize < INT_MAX / storesize );
1099 assert( sizeof(CHUNK) < MAXMEMSIZE - (size_t)(storesize * chkmem->elemsize) ); /*lint !e571 !e647*/
1100 BMSallocMemorySize(&newchunk, sizeof(CHUNK) + storesize * chkmem->elemsize);
1101 if( newchunk == NULL )
1102 return FALSE;
1103
1104 /* the store is allocated directly behind the chunk header */
1105 newchunk->store = (void*) ((char*) newchunk + sizeof(CHUNK));
1106 newchunk->storeend = (void*) ((char*) newchunk->store + (ptrdiff_t)storesize * chkmem->elemsize);
1107 newchunk->eagerfree = NULL;
1108 newchunk->nexteager = NULL;
1109 newchunk->preveager = NULL;
1110 newchunk->chkmem = chkmem;
1111 newchunk->elemsize = chkmem->elemsize;
1112 newchunk->storesize = storesize;
1113 newchunk->eagerfreesize = 0;
1114
1115 if( memsize != NULL )
1116 (*memsize) += ((long long)((long long)sizeof(CHUNK) + (long long)storesize * chkmem->elemsize));
1117
1118 debugMessage("allocated new chunk %p: %d elements with size %d\n", (void*)newchunk, newchunk->storesize, newchunk->elemsize);
1119
1120 /* add new memory to the lazy free list
1121 * (due to the BMSisAligned assert above, we know that elemsize is divisible by the size of pointers)
1122 */
1123 for( i = 0; i < newchunk->storesize - 1; ++i )
1124 {
1125 freelist = (FREELIST*) newchunk->store + (ptrdiff_t)i * chkmem->elemsize / (ptrdiff_t)sizeof(FREELIST*); /*lint !e573 !e647*/
1126 freelist->next = (FREELIST*) newchunk->store + ((ptrdiff_t)i + 1) * chkmem->elemsize / (ptrdiff_t)sizeof(FREELIST*); /*lint !e573 !e647*/
1127 }
1128
1129 freelist = (FREELIST*) newchunk->store + ((ptrdiff_t) newchunk->storesize - 1) * chkmem->elemsize / (ptrdiff_t)sizeof(FREELIST*); /*lint !e573 !e647*/
1130 freelist->next = chkmem->lazyfree;
1131 chkmem->lazyfree = (FREELIST*) (newchunk->store);
1132 chkmem->lazyfreesize += newchunk->storesize;
1133
1134 /* link chunk into chunk block */
1135 retval = linkChunk(chkmem, newchunk);
1136
1137 checkChkmem(chkmem);
1138
1139 return retval;
1140}
1141
1142/** destroys a chunk without updating the chunk lists */
1143static
1145 CHUNK** chunk, /**< memory chunk */
1146 long long* memsize /**< pointer to total size of allocated memory (or NULL) */
1147 )
1148{
1149 assert(chunk != NULL);
1150 assert(*chunk != NULL);
1151
1152 debugMessage("destroying chunk %p\n", (void*)*chunk);
1153
1154 if( memsize != NULL )
1155 (*memsize) -= ((long long)sizeof(CHUNK) + (long long)(*chunk)->storesize * (*chunk)->elemsize);
1156
1157 /* free chunk header and store (allocated in one call) */
1158 BMSfreeMemory(chunk);
1159}
1160
1161/** removes a completely unused chunk, i.e. a chunk with all elements in the eager free list */
1162static
1164 CHUNK** chunk, /**< memory chunk */
1165 long long* memsize /**< pointer to total size of allocated memory (or NULL) */
1166 )
1167{
1168 assert(chunk != NULL);
1169 assert(*chunk != NULL);
1170 assert((*chunk)->store != NULL);
1171 assert((*chunk)->eagerfree != NULL);
1172 assert((*chunk)->chkmem != NULL);
1173 assert((*chunk)->chkmem->rootchunk != NULL);
1174 assert((*chunk)->chkmem->firsteager != NULL);
1175 assert((*chunk)->eagerfreesize == (*chunk)->storesize);
1176
1177 debugMessage("freeing chunk %p of chunk block %p [elemsize: %d]\n", (void*)*chunk, (void*)(*chunk)->chkmem, (*chunk)->chkmem->elemsize);
1178
1179 /* count the deleted eager free slots */
1180 (*chunk)->chkmem->eagerfreesize -= (*chunk)->eagerfreesize;
1181 assert((*chunk)->chkmem->eagerfreesize >= 0);
1182
1183 /* remove chunk from eager chunk list */
1184 unlinkEagerChunk(*chunk);
1185
1186 /* remove chunk from chunk list */
1187 unlinkChunk(*chunk);
1188
1189 /* destroy the chunk */
1190 destroyChunk(chunk, memsize);
1191}
1192
1193/** returns an element of the eager free list and removes it from the list */
1194static
1196 CHUNK* chunk /**< memory chunk */
1197 )
1198{
1199 FREELIST* ptr;
1200
1201 assert(chunk != NULL);
1202 assert(chunk->eagerfree != NULL);
1203 assert(chunk->eagerfreesize > 0);
1204 assert(chunk->chkmem != NULL);
1205
1206 debugMessage("allocating chunk element in chunk %p [elemsize: %d]\n", (void*)chunk, chunk->chkmem->elemsize);
1207
1208 /* unlink first element in the eager free list */
1209 ptr = chunk->eagerfree;
1210 chunk->eagerfree = ptr->next;
1211 chunk->eagerfreesize--;
1212 chunk->chkmem->eagerfreesize--;
1213
1214 assert((chunk->eagerfreesize == 0 && chunk->eagerfree == NULL)
1215 || (chunk->eagerfreesize != 0 && chunk->eagerfree != NULL));
1216 assert(chunk->chkmem->eagerfreesize >= 0);
1217
1218 /* unlink chunk from eager chunk list if necessary */
1219 if( chunk->eagerfree == NULL )
1220 {
1221 assert(chunk->eagerfreesize == 0);
1222 unlinkEagerChunk(chunk);
1223 }
1224
1225 checkChunk(chunk);
1226
1227 return (void*) ptr;
1228}
1229
1230/** puts given pointer into the eager free list and adds the chunk to the eager list of its chunk block, if necessary */
1231static
1233 CHUNK* chunk, /**< memory chunk */
1234 void* ptr /**< pointer */
1235 )
1236{
1237 assert(chunk != NULL);
1238 assert(chunk->chkmem != NULL);
1239 assert(isPtrInChunk(chunk, ptr));
1240
1241 debugMessage("freeing chunk element %p of chunk %p [elemsize: %d]\n", (void*)ptr, (void*)chunk, chunk->chkmem->elemsize);
1242
1243 /* link chunk to the eager chunk list if necessary */
1244 if( chunk->eagerfree == NULL )
1245 {
1246 assert(chunk->eagerfreesize == 0);
1247 linkEagerChunk(chunk->chkmem, chunk);
1248 }
1249
1250 /* add ptr to the chunks eager free list */
1251 ((FREELIST*)ptr)->next = chunk->eagerfree;
1252 chunk->eagerfree = (FREELIST*)ptr;
1253 chunk->eagerfreesize++;
1254 chunk->chkmem->eagerfreesize++;
1255
1256 checkChunk(chunk);
1257}
1258
1259/** creates a new chunk block data structure */
1260static
1262 int size, /**< element size of the chunk block */
1263 int initchunksize, /**< number of elements in the first chunk of the chunk block */
1264 int garbagefactor, /**< garbage collector is called, if at least garbagefactor * avg. chunksize
1265 * elements are free (-1: disable garbage collection) */
1266 long long* memsize /**< pointer to total size of allocated memory (or NULL) */
1267 )
1268{
1269 BMS_CHKMEM* chkmem;
1270
1271 assert(size >= 0);
1272 assert(BMSisAligned((size_t)size)); /*lint !e571*/
1273
1274 BMSallocMemory(&chkmem);
1275 if( chkmem == NULL )
1276 return NULL;
1277
1278 chkmem->lazyfree = NULL;
1279 chkmem->rootchunk = NULL;
1280 chkmem->firsteager = NULL;
1281 chkmem->nextchkmem = NULL;
1282 chkmem->elemsize = size;
1283 chkmem->nchunks = 0;
1284 chkmem->lastchunksize = 0;
1285 chkmem->storesize = 0;
1286 chkmem->lazyfreesize = 0;
1287 chkmem->eagerfreesize = 0;
1288 chkmem->initchunksize = initchunksize;
1289 chkmem->garbagefactor = garbagefactor;
1290#ifndef NDEBUG
1291 chkmem->filename = NULL;
1292 chkmem->line = 0;
1293 chkmem->ngarbagecalls = 0;
1294 chkmem->ngarbagefrees = 0;
1295#endif
1296
1297 if( memsize != NULL )
1298 (*memsize) += (long long)sizeof(BMS_CHKMEM);
1299
1300 return chkmem;
1301}
1302
1303/** destroys all chunks of the chunk block, but keeps the chunk block header structure */
1304static
1306 BMS_CHKMEM* chkmem, /**< chunk block */
1307 long long* memsize /**< pointer to total size of allocated memory (or NULL) */
1308 )
1309{
1310 assert(chkmem != NULL);
1311
1312 /* destroy all chunks of the chunk block */
1313 FOR_EACH_NODE(CHUNK*, chunk, chkmem->rootchunk,
1314 {
1315 SCIPrbtreeDelete(&chkmem->rootchunk, chunk);
1316 destroyChunk(&chunk, memsize);
1317 })
1318
1319 chkmem->lazyfree = NULL;
1320 chkmem->firsteager = NULL;
1321 chkmem->nchunks = 0;
1322 chkmem->lastchunksize = 0;
1323 chkmem->storesize = 0;
1324 chkmem->lazyfreesize = 0;
1325 chkmem->eagerfreesize = 0;
1326}
1327
1328/** deletes chunk block and frees all associated memory chunks */
1329static
1331 BMS_CHKMEM** chkmem, /**< pointer to chunk block */
1332 long long* memsize /**< pointer to total size of allocated memory (or NULL) */
1333 )
1334{
1335 assert(chkmem != NULL);
1336 assert(*chkmem != NULL);
1337
1338 clearChkmem(*chkmem, memsize);
1339
1340#ifndef NDEBUG
1341 BMSfreeMemoryArrayNull(&(*chkmem)->filename);
1342#endif
1343
1344 if( memsize != NULL )
1345 (*memsize) -= (long long)(sizeof(BMS_CHKMEM));
1346
1347 BMSfreeMemory(chkmem);
1348}
1349
1350/** allocates a new memory element from the chunk block */
1351static
1353 BMS_CHKMEM* chkmem, /**< chunk block */
1354 long long* memsize /**< pointer to total size of allocated memory (or NULL) */
1355 )
1356{
1357 FREELIST* ptr;
1358
1359 assert(chkmem != NULL);
1360
1361 /* if the lazy freelist is empty, we have to find the memory element somewhere else */
1362 if( chkmem->lazyfree == NULL )
1363 {
1364 assert(chkmem->lazyfreesize == 0);
1365
1366 /* check for a free element in the eager freelists */
1367 if( chkmem->firsteager != NULL )
1368 return allocChunkElement(chkmem->firsteager);
1369
1370 /* allocate a new chunk */
1371 if( !createChunk(chkmem, memsize) )
1372 return NULL;
1373 }
1374
1375 /* now the lazy freelist should contain an element */
1376 assert(chkmem->lazyfree != NULL);
1377 assert(chkmem->lazyfreesize > 0);
1378
1379 ptr = chkmem->lazyfree;
1380 chkmem->lazyfree = ptr->next;
1381 chkmem->lazyfreesize--;
1382
1383 checkChkmem(chkmem);
1384
1385 return (void*) ptr;
1386}
1387
1388/** sorts the lazy free list of the chunk block into the eager free lists of the chunks, and removes completely
1389 * unused chunks
1390 */
1391static
1393 BMS_CHKMEM* chkmem, /**< chunk block */
1394 long long* memsize /**< pointer to total size of allocated memory (or NULL) */
1395 )
1396{
1397 CHUNK* chunk;
1398 CHUNK* nexteager;
1399 FREELIST* lazyfree;
1400
1401 assert(chkmem != NULL);
1402
1403 debugMessage("garbage collection for chunk block %p [elemsize: %d]\n", (void*)chkmem, chkmem->elemsize);
1404
1405 /* check, if the chunk block is completely unused */
1406 if( chkmem->lazyfreesize + chkmem->eagerfreesize == chkmem->storesize )
1407 {
1408 clearChkmem(chkmem, memsize);
1409 return;
1410 }
1411
1412#ifndef NDEBUG
1413 chkmem->ngarbagecalls++;
1414#endif
1415
1416 /* put the lazy free elements into the eager free lists */
1417 while( chkmem->lazyfree != NULL )
1418 {
1419 /* unlink first element from the lazy free list */
1420 lazyfree = chkmem->lazyfree;
1421 chkmem->lazyfree = chkmem->lazyfree->next;
1422 chkmem->lazyfreesize--;
1423
1424 /* identify the chunk of the element */
1425 chunk = findChunk(chkmem, (void*)lazyfree);
1426#ifndef NDEBUG
1427 if( chunk == NULL )
1428 {
1429 errorMessage("chunk for lazy free chunk %p not found in chunk block %p\n", (void*)lazyfree, (void*)chkmem);
1430 }
1431#endif
1432 assert(chunk != NULL);
1433
1434 /* add the element to the chunk's eager free list */
1435 freeChunkElement(chunk, (void*)lazyfree);
1436 assert(chunk->eagerfreesize > 0);
1437 }
1438 assert(chkmem->lazyfreesize == 0);
1439
1440 /* delete completely unused chunks, but keep at least one */
1441 chunk = chkmem->firsteager;
1442 while( chunk != NULL && chkmem->nchunks > 1 )
1443 {
1444 nexteager = chunk->nexteager;
1445 if( chunk->eagerfreesize == chunk->storesize )
1446 {
1447#ifndef NDEBUG
1448 chkmem->ngarbagefrees++;
1449#endif
1450 freeChunk(&chunk, memsize);
1451 }
1452 chunk = nexteager;
1453 }
1454
1455 checkChkmem(chkmem);
1456}
1457
1458/** frees a memory element and returns it to the lazy freelist of the chunk block */ /*lint -e715*/
1459static
1461 BMS_CHKMEM* chkmem, /**< chunk block */
1462 void* ptr, /**< memory element */
1463 long long* memsize, /**< pointer to total size of allocated memory (or NULL) */
1464 const char* filename, /**< source file of the function call */
1465 int line /**< line number in source file of the function call */
1466 )
1467{ /*lint --e{715}*/
1468 assert(chkmem != NULL);
1469 assert(ptr != NULL);
1470
1471#if ( defined(CHECKMEM) || defined(CHECKCHKFREE) )
1472 /* check, if ptr belongs to the chunk block */
1473 if( !isPtrInChkmem(chkmem, ptr) )
1474 {
1475 printErrorHeader(filename, line);
1476 printError("Pointer %p does not belong to chunk block %p (size: %d).\n", ptr, chkmem, chkmem->elemsize);
1477 }
1478#endif
1479
1480 /* put ptr in lazy free list */
1481 ((FREELIST*)ptr)->next = chkmem->lazyfree;
1482 chkmem->lazyfree = (FREELIST*)ptr;
1483 chkmem->lazyfreesize++;
1484
1485 /* check if we want to apply garbage collection */
1486 if( chkmem->garbagefactor >= 0 && chkmem->nchunks > 0 && chkmem->lazyfreesize >= GARBAGE_SIZE
1487 && chkmem->lazyfreesize + chkmem->eagerfreesize
1488 > chkmem->garbagefactor * (double)(chkmem->storesize) / (double)(chkmem->nchunks) )
1489 {
1490 garbagecollectChkmem(chkmem, memsize);
1491 }
1492
1493 checkChkmem(chkmem);
1494}
1495
1496/** creates a new chunk block data structure */
1498 size_t size, /**< element size of the chunk block */
1499 int initchunksize, /**< number of elements in the first chunk of the chunk block */
1500 int garbagefactor, /**< garbage collector is called, if at least garbagefactor * avg. chunksize
1501 * elements are free (-1: disable garbage collection) */
1502 const char* filename, /**< source file of the function call */
1503 int line /**< line number in source file of the function call */
1504 )
1505{
1506 BMS_CHKMEM* chkmem;
1507
1508 alignSize(&size);
1509 chkmem = createChkmem((int) size, initchunksize, garbagefactor, NULL);
1510 if( chkmem == NULL )
1511 {
1512 printErrorHeader(filename, line);
1513 printError("Insufficient memory for chunk block.\n");
1514 }
1515 debugMessage("created chunk memory %p [elemsize: %d]\n", (void*)chkmem, (int)size);
1516
1517 return chkmem;
1518}
1519
1520/** clears a chunk block data structure */
1522 BMS_CHKMEM* chkmem, /**< chunk block */
1523 const char* filename, /**< source file of the function call */
1524 int line /**< line number in source file of the function call */
1525 )
1526{
1527 if( chkmem != NULL )
1528 {
1529 debugMessage("clearing chunk memory %p [elemsize: %d]\n", (void*)chkmem, chkmem->elemsize);
1530 clearChkmem(chkmem, NULL);
1531 }
1532 else
1533 {
1534 printErrorHeader(filename, line);
1535 printError("Tried to clear null chunk block.\n");
1536 }
1537}
1538
1539/** destroys and frees a chunk block data structure */
1541 BMS_CHKMEM** chkmem, /**< pointer to chunk block */
1542 const char* filename, /**< source file of the function call */
1543 int line /**< line number in source file of the function call */
1544 )
1545{
1546 assert(chkmem != NULL);
1547
1548 if( *chkmem != NULL )
1549 {
1550 debugMessage("destroying chunk memory %p [elemsize: %d]\n", (void*)*chkmem, (*chkmem)->elemsize);
1551 destroyChkmem(chkmem, NULL);
1552 }
1553 else
1554 {
1555 printErrorHeader(filename, line);
1556 printError("Tried to destroy null chunk block.\n");
1557 }
1558}
1559
1560/** allocates a memory element of the given chunk block */
1562 BMS_CHKMEM* chkmem, /**< chunk block */
1563 size_t size, /**< size of memory element to allocate (only needed for sanity check) */
1564 const char* filename, /**< source file of the function call */
1565 int line /**< line number in source file of the function call */
1566 )
1567{
1568 void* ptr;
1569
1570 assert(chkmem != NULL);
1571 assert((int)size == chkmem->elemsize);
1572
1573 /* get memory inside the chunk block */
1574 ptr = allocChkmemElement(chkmem, NULL);
1575 if( ptr == NULL )
1576 {
1577 printErrorHeader(filename, line);
1578 printError("Insufficient memory for new chunk.\n");
1579 }
1580 debugMessage("alloced %8llu bytes in %p [%s:%d]\n", (unsigned long long)size, (void*)ptr, filename, line);
1581
1582 checkChkmem(chkmem);
1583
1584 return ptr;
1585}
1586
1587/** duplicates a given memory element by allocating a new element of the same chunk block and copying the data */
1589 BMS_CHKMEM* chkmem, /**< chunk block */
1590 const void* source, /**< source memory element */
1591 size_t size, /**< size of memory element to allocate (only needed for sanity check) */
1592 const char* filename, /**< source file of the function call */
1593 int line /**< line number in source file of the function call */
1594 )
1595{
1596 void* ptr;
1597
1598 assert(chkmem != NULL);
1599 assert(source != NULL);
1600 assert((int)size == chkmem->elemsize);
1601
1602 ptr = BMSallocChunkMemory_call(chkmem, size, filename, line);
1603 if( ptr != NULL )
1604 BMScopyMemorySize(ptr, source, chkmem->elemsize);
1605
1606 return ptr;
1607}
1608
1609/** frees a memory element of the given chunk block and sets pointer to NULL */
1611 BMS_CHKMEM* chkmem, /**< chunk block */
1612 void** ptr, /**< pointer to pointer to memory element to free */
1613 size_t size, /**< size of memory element to allocate (only needed for sanity check) */
1614 const char* filename, /**< source file of the function call */
1615 int line /**< line number in source file of the function call */
1616 )
1617{
1618 assert(chkmem != NULL);
1619 assert((int)size == chkmem->elemsize);
1620 assert( ptr != NULL );
1621
1622 if ( *ptr != NULL )
1623 {
1624 debugMessage("free %8d bytes in %p [%s:%d]\n", chkmem->elemsize, *ptr, filename, line);
1625
1626 /* free memory in chunk block */
1627 freeChkmemElement(chkmem, *ptr, NULL, filename, line);
1628 checkChkmem(chkmem);
1629 *ptr = NULL;
1630 }
1631 else
1632 {
1633 printErrorHeader(filename, line);
1634 printError("Tried to free null chunk pointer.\n");
1635 }
1636}
1637
1638/** frees a memory element of the given chunk block if pointer is not NULL and sets pointer to NULL */
1640 BMS_CHKMEM* chkmem, /**< chunk block */
1641 void** ptr, /**< pointer to pointer to memory element to free */
1642 size_t size, /**< size of memory element to allocate (only needed for sanity check) */
1643 const char* filename, /**< source file of the function call */
1644 int line /**< line number in source file of the function call */
1645 )
1646{
1647 assert(chkmem != NULL);
1648 assert((int)size == chkmem->elemsize);
1649 assert( ptr != NULL );
1650
1651 if ( *ptr != NULL )
1652 {
1653 debugMessage("free %8d bytes in %p [%s:%d]\n", chkmem->elemsize, *ptr, filename, line);
1654
1655 /* free memory in chunk block */
1656 freeChkmemElement(chkmem, *ptr, NULL, filename, line);
1657 checkChkmem(chkmem);
1658 *ptr = NULL;
1659 }
1660}
1661
1662/** calls garbage collection of chunk block and frees chunks without allocated memory elements */
1664 BMS_CHKMEM* chkmem /**< chunk block */
1665 )
1666{
1667 debugMessage("garbage collection on chunk memory %p [elemsize: %d]\n", (void*)chkmem, chkmem->elemsize);
1668
1669 garbagecollectChkmem(chkmem, NULL);
1670}
1671
1672/** returns the number of allocated bytes in the chunk block */
1674 const BMS_CHKMEM* chkmem /**< chunk block */
1675 )
1676{
1677 assert(chkmem != NULL);
1678
1679 return ((long long)(chkmem->elemsize) * (long long)(chkmem->storesize));
1680}
1681
1682
1683
1684
1685/***********************************************************
1686 * Block Memory Management
1687 *
1688 * Efficient memory management for objects of varying sizes
1689 ***********************************************************/
1690
1691/* for a definition of the struct, see above */
1692
1693
1694/*
1695 * debugging methods
1696 */
1697
1698#ifdef CHECKMEM
1699static
1700void checkBlkmem(
1701 const BMS_BLKMEM* blkmem /**< block memory */
1702 )
1703{
1704 const BMS_CHKMEM* chkmem;
1705 long long tmpmemalloc = 0LL;
1706 long long tmpmemused = 0LL;
1707 int i;
1708
1709 assert(blkmem != NULL);
1710 assert(blkmem->chkmemhash != NULL);
1711
1712 for( i = 0; i < CHKHASH_SIZE; ++i )
1713 {
1714 chkmem = blkmem->chkmemhash[i];
1715 while( chkmem != NULL )
1716 {
1717 checkChkmem(chkmem);
1718 tmpmemalloc += ((chkmem->elemsize * chkmem->storesize) + chkmem->nchunks * sizeof(CHUNK) + sizeof(BMS_CHKMEM));
1719 tmpmemused += (chkmem->elemsize * (chkmem->storesize - chkmem->eagerfreesize - chkmem->lazyfreesize));
1720 chkmem = chkmem->nextchkmem;
1721 }
1722 }
1723 assert(tmpmemalloc == blkmem->memallocated);
1724 assert(tmpmemused == blkmem->memused);
1725}
1726#else
1727#define checkBlkmem(blkmem) /**/
1728#endif
1729
1730
1731/** finds the chunk block, to whick the given pointer belongs to
1732 *
1733 * This could be done by selecting the chunk block of the corresponding element size, but in a case of an
1734 * error (free gives an incorrect element size), we want to identify and output the correct element size.
1735 */
1736static
1738 const BMS_BLKMEM* blkmem, /**< block memory */
1739 const void* ptr /**< memory element to search */
1740 )
1741{
1742 BMS_CHKMEM* chkmem;
1743 int i;
1744
1745 assert(blkmem != NULL);
1746
1747 chkmem = NULL;
1748 for( i = 0; chkmem == NULL && i < CHKHASH_SIZE; ++i )
1749 {
1750 chkmem = blkmem->chkmemhash[i];
1751 while( chkmem != NULL && !isPtrInChkmem(chkmem, ptr) )
1752 chkmem = chkmem->nextchkmem;
1753 }
1754
1755 return chkmem;
1756}
1757
1758/** calculates hash number of memory size */
1759static
1761 size_t size /**< element size */
1762 )
1763{
1764 assert(BMSisAligned(size));
1765
1766 return ((uint32_t)size * UINT32_C(0x9e3779b9)) >> (32-CHKHASH_POWER);
1767}
1768
1769/** creates a block memory allocation data structure */
1771 int initchunksize, /**< number of elements in the first chunk of each chunk block */
1772 int garbagefactor, /**< garbage collector is called, if at least garbagefactor * avg. chunksize
1773 * elements are free (-1: disable garbage collection) */
1774 const char* filename, /**< source file of the function call */
1775 int line /**< line number in source file of the function call */
1776 )
1777{
1778 BMS_BLKMEM* blkmem;
1779 int i;
1780
1781 BMSallocMemory(&blkmem);
1782 if( blkmem != NULL )
1783 {
1784 for( i = 0; i < CHKHASH_SIZE; ++i )
1785 blkmem->chkmemhash[i] = NULL;
1786 blkmem->initchunksize = initchunksize;
1787 blkmem->garbagefactor = garbagefactor;
1788 blkmem->memused = 0;
1789 blkmem->memallocated = 0;
1790 blkmem->maxmemused = 0;
1791 blkmem->maxmemunused = 0;
1792 blkmem->maxmemallocated = 0;
1793 }
1794 else
1795 {
1796 printErrorHeader(filename, line);
1797 printError("Insufficient memory for block memory header.\n");
1798 }
1799
1800 return blkmem;
1801}
1802
1803/** frees all chunk blocks in the block memory */
1805 BMS_BLKMEM* blkmem, /**< 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 BMS_CHKMEM* chkmem;
1811 BMS_CHKMEM* nextchkmem;
1812 int i;
1813
1814 if( blkmem != NULL )
1815 {
1816 for( i = 0; i < CHKHASH_SIZE; ++i )
1817 {
1818 chkmem = blkmem->chkmemhash[i];
1819 while( chkmem != NULL )
1820 {
1821 nextchkmem = chkmem->nextchkmem;
1822 destroyChkmem(&chkmem, &blkmem->memallocated);
1823 chkmem = nextchkmem;
1824 }
1825 blkmem->chkmemhash[i] = NULL;
1826 }
1827 blkmem->memused = 0;
1828 assert(blkmem->memallocated == 0);
1829 }
1830 else
1831 {
1832 printErrorHeader(filename, line);
1833 printError("Tried to clear null block memory.\n");
1834 }
1835}
1836
1837/** clears and deletes block memory */
1839 BMS_BLKMEM** blkmem, /**< pointer to block memory */
1840 const char* filename, /**< source file of the function call */
1841 int line /**< line number in source file of the function call */
1842 )
1843{
1844 assert(blkmem != NULL);
1845
1846 if( *blkmem != NULL )
1847 {
1848 BMSclearBlockMemory_call(*blkmem, filename, line);
1849 BMSfreeMemory(blkmem);
1850 assert(*blkmem == NULL);
1851 }
1852 else
1853 {
1854 printErrorHeader(filename, line);
1855 printError("Tried to destroy null block memory.\n");
1856 }
1857}
1858
1859/** work for allocating memory in the block memory pool */
1860INLINE static
1862 BMS_BLKMEM* blkmem, /**< block memory */
1863 size_t size, /**< size of memory element to allocate */
1864 const char* filename, /**< source file of the function call */
1865 int line /**< line number in source file of the function call */
1866 )
1867{
1868 BMS_CHKMEM** chkmemptr;
1869 uint32_t hashnumber;
1870 void* ptr;
1871
1872 assert( blkmem != NULL );
1873
1874 /* allocating very large memory blocks is currently not possible, because BMS_CHKMEM::elemsize is of type int only */
1875 if( size > INT_MAX )
1876 return NULL;
1877
1878 /* calculate hash number of given size */
1879 alignSize(&size);
1880 hashnumber = getHashNumber(size);
1881 assert(hashnumber < CHKHASH_SIZE);
1882
1883 /* find corresponding chunk block */
1884 chkmemptr = &(blkmem->chkmemhash[hashnumber]);
1885 while( *chkmemptr != NULL && (*chkmemptr)->elemsize != (int)size )
1886 chkmemptr = &((*chkmemptr)->nextchkmem);
1887
1888 /* create new chunk block if necessary */
1889 if( *chkmemptr == NULL )
1890 {
1891 *chkmemptr = createChkmem((int)size, blkmem->initchunksize, blkmem->garbagefactor, &blkmem->memallocated);
1892 if( *chkmemptr == NULL )
1893 {
1894 printErrorHeader(filename, line);
1895 printError("Insufficient memory for chunk block.\n");
1896 return NULL;
1897 }
1898#ifndef NDEBUG
1899 BMSduplicateMemoryArray(&(*chkmemptr)->filename, filename, strlen(filename) + 1);
1900 (*chkmemptr)->line = line;
1901#endif
1902 }
1903#ifndef NDEBUG
1904 else
1905 {
1906 BMSfreeMemoryArrayNull(&(*chkmemptr)->filename);
1907 BMSduplicateMemoryArray(&(*chkmemptr)->filename, filename, strlen(filename) + 1);
1908 (*chkmemptr)->line = line;
1909 }
1910#endif
1911
1912 /* get memory inside the chunk block */
1913 ptr = allocChkmemElement(*chkmemptr, &blkmem->memallocated);
1914
1915 if( ptr == NULL )
1916 {
1917 printErrorHeader(filename, line);
1918 printError("Insufficient memory for new chunk.\n");
1919 }
1920 debugMessage("alloced %8llu bytes in %p [%s:%d]\n", (unsigned long long)size, ptr, filename, line);
1921
1922 /* add the used memory */
1923 blkmem->memused += (long long) size;
1924 blkmem->maxmemused = MAX(blkmem->maxmemused, blkmem->memused);
1925 blkmem->maxmemunused = MAX(blkmem->maxmemunused, blkmem->memallocated - blkmem->memused);
1926 blkmem->maxmemallocated = MAX(blkmem->maxmemallocated, blkmem->memallocated);
1927
1928 assert(blkmem->memused >= 0);
1929 assert(blkmem->memallocated >= 0);
1930
1931 checkBlkmem(blkmem);
1932
1933 return ptr;
1934}
1935
1936/** allocates memory in the block memory pool */
1938 BMS_BLKMEM* blkmem, /**< block memory */
1939 size_t size, /**< size of memory element to allocate */
1940 const char* filename, /**< source file of the function call */
1941 int line /**< line number in source file of the function call */
1942 )
1943{
1944#ifndef NDEBUG
1945 if ( size > MAXMEMSIZE )
1946 {
1947 printErrorHeader(filename, line);
1948 printError("Tried to allocate block of size exceeding %lu.\n", MAXMEMSIZE);
1949 return NULL;
1950 }
1951#endif
1952
1953 return BMSallocBlockMemory_work(blkmem, size, filename, line);
1954}
1955
1956/** allocates memory in the block memory pool and clears it */
1958 BMS_BLKMEM* blkmem, /**< block memory */
1959 size_t size, /**< size of memory element to allocate */
1960 const char* filename, /**< source file of the function call */
1961 int line /**< line number in source file of the function call */
1962 )
1963{
1964 void* ptr;
1965
1966 ptr = BMSallocBlockMemory_call(blkmem, size, filename, line);
1967 if( ptr != NULL )
1968 BMSclearMemorySize(ptr, size);
1969
1970 return ptr;
1971}
1972
1973/** allocates array in the block memory pool */
1975 BMS_BLKMEM* blkmem, /**< block memory */
1976 size_t num, /**< size of array to be allocated */
1977 size_t typesize, /**< size of each component */
1978 const char* filename, /**< source file of the function call */
1979 int line /**< line number in source file of the function call */
1980 )
1981{
1982#ifndef NDEBUG
1983 if ( num > (MAXMEMSIZE / typesize) )
1984 {
1985 printErrorHeader(filename, line);
1986 printError("Tried to allocate block of size exceeding %lu.\n", MAXMEMSIZE);
1987 return NULL;
1988 }
1989#endif
1990
1991 return BMSallocBlockMemory_work(blkmem, num * typesize, filename, line);
1992}
1993
1994/** allocates array in the block memory pool and clears it */
1996 BMS_BLKMEM* blkmem, /**< block memory */
1997 size_t num, /**< size of array to be allocated */
1998 size_t typesize, /**< size of each component */
1999 const char* filename, /**< source file of the function call */
2000 int line /**< line number in source file of the function call */
2001 )
2002{
2003 void* ptr;
2004
2005 ptr = BMSallocBlockMemoryArray_call(blkmem, num, typesize, filename, line);
2006 if ( ptr != NULL )
2007 BMSclearMemorySize(ptr, num * typesize);
2008
2009 return ptr;
2010}
2011
2012/** resizes memory element in the block memory pool and copies the data */
2014 BMS_BLKMEM* blkmem, /**< block memory */
2015 void* ptr, /**< memory element to reallocated */
2016 size_t oldsize, /**< old size of memory element */
2017 size_t newsize, /**< new size of memory element */
2018 const char* filename, /**< source file of the function call */
2019 int line /**< line number in source file of the function call */
2020 )
2021{
2022 void* newptr;
2023
2024 if( ptr == NULL )
2025 {
2026 assert(oldsize == 0);
2027 return BMSallocBlockMemory_call(blkmem, newsize, filename, line);
2028 }
2029
2030#ifndef NDEBUG
2031 if ( newsize > MAXMEMSIZE )
2032 {
2033 printErrorHeader(filename, line);
2034 printError("Tried to allocate block of size exceeding %lu.\n", MAXMEMSIZE);
2035 return NULL;
2036 }
2037#endif
2038
2039 alignSize(&oldsize);
2040 alignSize(&newsize);
2041 if( oldsize == newsize )
2042 return ptr;
2043
2044 newptr = BMSallocBlockMemory_call(blkmem, newsize, filename, line);
2045 if( newptr != NULL )
2046 BMScopyMemorySize(newptr, ptr, MIN(oldsize, newsize));
2047 BMSfreeBlockMemory_call(blkmem, &ptr, oldsize, filename, line);
2048
2049 return newptr;
2050}
2051
2052/** resizes array in the block memory pool and copies the data */
2054 BMS_BLKMEM* blkmem, /**< block memory */
2055 void* ptr, /**< memory element to reallocated */
2056 size_t oldnum, /**< old size of array */
2057 size_t newnum, /**< new size of array */
2058 size_t typesize, /**< size of each component */
2059 const char* filename, /**< source file of the function call */
2060 int line /**< line number in source file of the function call */
2061 )
2062{
2063 void* newptr;
2064
2065 if( ptr == NULL )
2066 {
2067 assert(oldnum == 0);
2068 return BMSallocBlockMemoryArray_call(blkmem, newnum, typesize, filename, line);
2069 }
2070
2071#ifndef NDEBUG
2072 if ( newnum > (MAXMEMSIZE / typesize) )
2073 {
2074 printErrorHeader(filename, line);
2075 printError("Tried to allocate array of size exceeding %lu.\n", MAXMEMSIZE);
2076 return NULL;
2077 }
2078#endif
2079
2080 if ( oldnum == newnum )
2081 return ptr;
2082
2083 newptr = BMSallocBlockMemoryArray_call(blkmem, newnum, typesize, filename, line);
2084 if ( newptr != NULL )
2085 BMScopyMemorySize(newptr, ptr, MIN(oldnum, newnum) * typesize);
2086 BMSfreeBlockMemory_call(blkmem, &ptr, oldnum * typesize, filename, line);
2087
2088 return newptr;
2089}
2090
2091/** duplicates memory element in the block memory pool and copies the data */
2093 BMS_BLKMEM* blkmem, /**< block memory */
2094 const void* source, /**< memory element to duplicate */
2095 size_t size, /**< size of memory elements */
2096 const char* filename, /**< source file of the function call */
2097 int line /**< line number in source file of the function call */
2098 )
2099{
2100 void* ptr;
2101
2102 assert(source != NULL);
2103
2104 ptr = BMSallocBlockMemory_call(blkmem, size, filename, line);
2105 if( ptr != NULL )
2106 BMScopyMemorySize(ptr, source, size);
2107
2108 return ptr;
2109}
2110
2111/** duplicates array in the block memory pool and copies the data */
2113 BMS_BLKMEM* blkmem, /**< block memory */
2114 const void* source, /**< memory element to duplicate */
2115 size_t num, /**< size of array to be duplicated */
2116 size_t typesize, /**< size of each component */
2117 const char* filename, /**< source file of the function call */
2118 int line /**< line number in source file of the function call */
2119 )
2120{
2121 void* ptr;
2122
2123 assert(source != NULL);
2124
2125 ptr = BMSallocBlockMemoryArray_call(blkmem, num, typesize, filename, line);
2126 if( ptr != NULL )
2127 BMScopyMemorySize(ptr, source, num * typesize);
2128
2129 return ptr;
2130}
2131
2132/** common work for freeing block memory */
2133INLINE static
2135 BMS_BLKMEM* blkmem, /**< block memory */
2136 void** ptr, /**< pointer to pointer to memory element to free */
2137 size_t size, /**< size of memory element */
2138 const char* filename, /**< source file of the function call */
2139 int line /**< line number in source file of the function call */
2140 )
2141{
2142 BMS_CHKMEM* chkmem;
2143 uint32_t hashnumber;
2144
2145 assert(ptr != NULL);
2146 assert(*ptr != NULL);
2147
2148 /* calculate hash number of given size */
2149 alignSize(&size);
2150 hashnumber = getHashNumber(size);
2151 assert(hashnumber < CHKHASH_SIZE);
2152
2153 debugMessage("free %8llu bytes in %p [%s:%d]\n", (unsigned long long)size, *ptr, filename, line);
2154
2155 /* find corresponding chunk block */
2156 assert( blkmem->chkmemhash != NULL );
2157 chkmem = blkmem->chkmemhash[hashnumber];
2158 while( chkmem != NULL && chkmem->elemsize != (int)size )
2159 chkmem = chkmem->nextchkmem;
2160 if( chkmem == NULL )
2161 {
2162 printErrorHeader(filename, line);
2163 printError("Tried to free pointer <%p> in block memory <%p> of unknown size %llu.\n", *ptr, (void*)blkmem, (unsigned long long)size);
2164 return;
2165 }
2166 assert(chkmem->elemsize == (int)size);
2167
2168 /* free memory in chunk block */
2169 freeChkmemElement(chkmem, *ptr, &blkmem->memallocated, filename, line);
2170 blkmem->memused -= (long long) size;
2171
2172 blkmem->maxmemunused = MAX(blkmem->maxmemunused, blkmem->memallocated - blkmem->memused);
2173
2174 assert(blkmem->memused >= 0);
2175 assert(blkmem->memallocated >= 0);
2176
2177 checkBlkmem(blkmem);
2178
2179 *ptr = NULL;
2180}
2181
2182/** frees memory element in the block memory pool and sets pointer to NULL */
2184 BMS_BLKMEM* blkmem, /**< block memory */
2185 void** ptr, /**< pointer to pointer to memory element to free */
2186 size_t size, /**< size of memory element */
2187 const char* filename, /**< source file of the function call */
2188 int line /**< line number in source file of the function call */
2189 )
2190{
2191 assert( blkmem != NULL );
2192 assert( ptr != NULL );
2193
2194 if( *ptr != NULL )
2195 BMSfreeBlockMemory_work(blkmem, ptr, size, filename, line);
2196 else if( size != 0 )
2197 {
2198 printErrorHeader(filename, line);
2199 printError("Tried to free null block pointer.\n");
2200 }
2201 checkBlkmem(blkmem);
2202}
2203
2204/** frees memory element in the block memory pool if pointer is not NULL and sets pointer to NULL */
2206 BMS_BLKMEM* blkmem, /**< block memory */
2207 void** ptr, /**< pointer to pointer to memory element to free */
2208 size_t size, /**< size of memory element */
2209 const char* filename, /**< source file of the function call */
2210 int line /**< line number in source file of the function call */
2211 )
2212{
2213 assert( blkmem != NULL );
2214 assert( ptr != NULL );
2215
2216 if( *ptr != NULL )
2217 {
2218 BMSfreeBlockMemory_work(blkmem, ptr, size, filename, line);
2219 }
2220 checkBlkmem(blkmem);
2221}
2222
2223/** calls garbage collection of block memory, frees chunks without allocated memory elements, and frees
2224 * chunk blocks without any chunks
2225 */
2227 BMS_BLKMEM* blkmem /**< block memory */
2228 )
2229{
2230 int i;
2231
2232 assert(blkmem != NULL);
2233
2234 for( i = 0; i < CHKHASH_SIZE; ++i )
2235 {
2236 BMS_CHKMEM** chkmemptr;
2237
2238 chkmemptr = &blkmem->chkmemhash[i];
2239 while( *chkmemptr != NULL )
2240 {
2241 garbagecollectChkmem(*chkmemptr, &blkmem->memallocated);
2242 checkBlkmem(blkmem);
2243 if( (*chkmemptr)->nchunks == 0 )
2244 {
2245 BMS_CHKMEM* nextchkmem;
2246
2247 assert((*chkmemptr)->lazyfreesize == 0);
2248 nextchkmem = (*chkmemptr)->nextchkmem;
2249 destroyChkmem(chkmemptr, &blkmem->memallocated);
2250 *chkmemptr = nextchkmem;
2251 checkBlkmem(blkmem);
2252 }
2253 else
2254 chkmemptr = &(*chkmemptr)->nextchkmem;
2255 }
2256 }
2257}
2258
2259/** returns the number of allocated bytes in the block memory */
2261 const BMS_BLKMEM* blkmem /**< block memory */
2262 )
2263{
2264 assert( blkmem != NULL );
2265
2266 return blkmem->memallocated;
2267}
2268
2269/** returns the number of used bytes in the block memory */
2271 const BMS_BLKMEM* blkmem /**< block memory */
2272 )
2273{
2274 assert( blkmem != NULL );
2275
2276 return blkmem->memused;
2277}
2278
2279/** returns the number of allocated but not used bytes in the block memory */
2281 const BMS_BLKMEM* blkmem /**< block memory */
2282 )
2283{
2284 assert( blkmem != NULL );
2285
2286 return blkmem->memallocated - blkmem->memused;
2287}
2288
2289/** returns the maximal number of used bytes in the block memory */
2291 const BMS_BLKMEM* blkmem /**< block memory */
2292 )
2293{
2294 assert( blkmem != NULL );
2295
2296 return blkmem->maxmemused;
2297}
2298
2299/** returns the maximal number of allocated but not used bytes in the block memory */
2301 const BMS_BLKMEM* blkmem /**< block memory */
2302 )
2303{
2304 assert( blkmem != NULL );
2305
2306 return blkmem->maxmemunused;
2307}
2308
2309/** returns the maximal number of allocated bytes in the block memory */
2311 const BMS_BLKMEM* blkmem /**< block memory */
2312 )
2313{
2314 assert( blkmem != NULL );
2315
2316 return blkmem->maxmemallocated;
2317}
2318
2319/** returns the size of the given memory element; returns 0, if the element is not member of the block memory */
2321 const BMS_BLKMEM* blkmem, /**< block memory */
2322 const void* ptr /**< memory element */
2323 )
2324{
2325 const BMS_CHKMEM* chkmem;
2326
2327 assert(blkmem != NULL);
2328
2329 if( ptr == NULL )
2330 return 0;
2331
2332 chkmem = findChkmem(blkmem, ptr);
2333 if( chkmem == NULL )
2334 return 0;
2335
2336 return (size_t)(chkmem->elemsize); /*lint !e571*/
2337}
2338
2339/** outputs allocation diagnostics of block memory */
2341 const BMS_BLKMEM* blkmem /**< block memory */
2342 )
2343{
2344 const BMS_CHKMEM* chkmem;
2345 int nblocks = 0;
2346 int nunusedblocks = 0;
2347 int totalnchunks = 0;
2348 int totalneagerchunks = 0;
2349 int totalnelems = 0;
2350 int totalneagerelems = 0;
2351 int totalnlazyelems = 0;
2352#ifndef NDEBUG
2353 int totalngarbagecalls = 0;
2354 int totalngarbagefrees = 0;
2355#endif
2356 long long allocedmem = 0;
2357 long long freemem = 0;
2358 int i;
2359
2360#ifndef NDEBUG
2361 printInfo(" ElSize #Chunk #Eag #Elems #EagFr #LazFr #GCl #GFr Free MBytes First Allocator\n");
2362#else
2363 printInfo(" ElSize #Chunk #Eag #Elems #EagFr #LazFr Free MBytes\n");
2364#endif
2365
2366 assert(blkmem != NULL);
2367
2368 for( i = 0; i < CHKHASH_SIZE; ++i )
2369 {
2370 chkmem = blkmem->chkmemhash[i];
2371 while( chkmem != NULL )
2372 {
2373 int nchunks = 0;
2374 int nelems = 0;
2375 int neagerchunks = 0;
2376 int neagerelems = 0;
2377
2378 FOR_EACH_NODE(CHUNK*, chunk, chkmem->rootchunk,
2379 {
2380 assert(chunk != NULL);
2381 assert(chunk->elemsize == chkmem->elemsize);
2382 assert(chunk->chkmem == chkmem);
2383 nchunks++;
2384 nelems += chunk->storesize;
2385 if( chunk->eagerfree != NULL )
2386 {
2387 neagerchunks++;
2388 neagerelems += chunk->eagerfreesize;
2389 }
2390 })
2391
2392 assert(nchunks == chkmem->nchunks);
2393 assert(nelems == chkmem->storesize);
2394 assert(neagerelems == chkmem->eagerfreesize);
2395
2396 if( nelems > 0 )
2397 {
2398 nblocks++;
2399 allocedmem += (long long)chkmem->elemsize * (long long)nelems;
2400 freemem += (long long)chkmem->elemsize * ((long long)neagerelems + (long long)chkmem->lazyfreesize);
2401
2402#ifndef NDEBUG
2403 printInfo("%7d %6d %4d %7d %7d %7d %5d %4d %5.1f%% %6.1f %s:%d\n",
2404 chkmem->elemsize, nchunks, neagerchunks, nelems,
2405 neagerelems, chkmem->lazyfreesize, chkmem->ngarbagecalls, chkmem->ngarbagefrees,
2406 100.0 * (double) (neagerelems + chkmem->lazyfreesize) / (double) (nelems),
2407 (double)chkmem->elemsize * nelems / (1024.0*1024.0),
2408 chkmem->filename, chkmem->line);
2409#else
2410 printInfo("%7d %6d %4d %7d %7d %7d %5.1f%% %6.1f\n",
2411 chkmem->elemsize, nchunks, neagerchunks, nelems,
2412 neagerelems, chkmem->lazyfreesize,
2413 100.0 * (double) (neagerelems + chkmem->lazyfreesize) / (double) (nelems),
2414 (double)chkmem->elemsize * nelems / (1024.0*1024.0));
2415#endif
2416 }
2417 else
2418 {
2419#ifndef NDEBUG
2420 printInfo("%7d <unused> %5d %4d %s:%d\n",
2421 chkmem->elemsize, chkmem->ngarbagecalls, chkmem->ngarbagefrees,
2422 chkmem->filename, chkmem->line);
2423#else
2424 printInfo("%7d <unused>\n", chkmem->elemsize);
2425#endif
2426 nunusedblocks++;
2427 }
2428 totalnchunks += nchunks;
2429 totalneagerchunks += neagerchunks;
2430 totalnelems += nelems;
2431 totalneagerelems += neagerelems;
2432 totalnlazyelems += chkmem->lazyfreesize;
2433#ifndef NDEBUG
2434 totalngarbagecalls += chkmem->ngarbagecalls;
2435 totalngarbagefrees += chkmem->ngarbagefrees;
2436#endif
2437 chkmem = chkmem->nextchkmem;
2438 }
2439 }
2440#ifndef NDEBUG
2441 printInfo(" Total %6d %4d %7d %7d %7d %5d %4d %5.1f%% %6.1f\n",
2442 totalnchunks, totalneagerchunks, totalnelems, totalneagerelems, totalnlazyelems,
2443 totalngarbagecalls, totalngarbagefrees,
2444 totalnelems > 0 ? 100.0 * (double) (totalneagerelems + totalnlazyelems) / (double) (totalnelems) : 0.0,
2445 (double)allocedmem/(1024.0*1024.0));
2446#else
2447 printInfo(" Total %6d %4d %7d %7d %7d %5.1f%% %6.1f\n",
2448 totalnchunks, totalneagerchunks, totalnelems, totalneagerelems, totalnlazyelems,
2449 totalnelems > 0 ? 100.0 * (double) (totalneagerelems + totalnlazyelems) / (double) (totalnelems) : 0.0,
2450 (double)allocedmem/(1024.0*1024.0));
2451#endif
2452 printInfo("%d blocks (%d unused), %" LONGINT_FORMAT " bytes allocated, %" LONGINT_FORMAT " bytes free", /* cppcheck-suppress syntaxError */
2453 nblocks + nunusedblocks, nunusedblocks, allocedmem, freemem);
2454 if( allocedmem > 0 )
2455 printInfo(" (%.1f%%)", 100.0 * (double) freemem / (double) allocedmem);
2456 printInfo("\n\n");
2457
2458 printInfo("Memory Peaks: Used Lazy Total\n");
2459 printInfo(" %6.1f %6.1f %6.1f MBytes\n", (double)blkmem->maxmemused / (1024.0 * 1024.0),
2460 (double)blkmem->maxmemunused / (1024.0 * 1024.0), (double)blkmem->maxmemallocated / (1024.0 * 1024.0));
2461}
2462
2463/** outputs error messages, if there are allocated elements in the block memory and returns number of unfreed bytes */
2465 const BMS_BLKMEM* blkmem /**< block memory */
2466 )
2467{
2468 const BMS_CHKMEM* chkmem;
2469 long long allocedmem = 0;
2470 long long freemem = 0;
2471 int i;
2472
2473 assert(blkmem != NULL);
2474
2475 for( i = 0; i < CHKHASH_SIZE; ++i )
2476 {
2477 chkmem = blkmem->chkmemhash[i];
2478 while( chkmem != NULL )
2479 {
2480 int nchunks = 0;
2481 int nelems = 0;
2482 int neagerelems = 0;
2483
2484 FOR_EACH_NODE(CHUNK*, chunk, chkmem->rootchunk,
2485 {
2486 assert(chunk != NULL);
2487 assert(chunk->elemsize == chkmem->elemsize);
2488 assert(chunk->chkmem == chkmem);
2489 nchunks++;
2490 nelems += chunk->storesize;
2491 if( chunk->eagerfree != NULL )
2492 neagerelems += chunk->eagerfreesize;
2493 })
2494
2495 assert(nchunks == chkmem->nchunks);
2496 SCIP_UNUSED(nchunks);
2497 assert(nelems == chkmem->storesize);
2498 assert(neagerelems == chkmem->eagerfreesize);
2499
2500 if( nelems > 0 )
2501 {
2502 allocedmem += (long long)chkmem->elemsize * (long long)nelems;
2503 freemem += (long long)chkmem->elemsize * ((long long)neagerelems + (long long)chkmem->lazyfreesize);
2504
2505 if( nelems != neagerelems + chkmem->lazyfreesize )
2506 {
2507#ifndef NDEBUG
2508 errorMessage("%" LONGINT_FORMAT " bytes (%d elements of size %" LONGINT_FORMAT ") not freed. First Allocator: %s:%d\n",
2509 (((long long)nelems - (long long)neagerelems) - (long long)chkmem->lazyfreesize)
2510 * (long long)(chkmem->elemsize),
2511 (nelems - neagerelems) - chkmem->lazyfreesize, (long long)(chkmem->elemsize),
2512 chkmem->filename, chkmem->line);
2513#else
2514 errorMessage("%" LONGINT_FORMAT " bytes (%d elements of size %" LONGINT_FORMAT ") not freed.\n",
2515 ((nelems - neagerelems) - chkmem->lazyfreesize) * (long long)(chkmem->elemsize),
2516 (nelems - neagerelems) - chkmem->lazyfreesize, (long long)(chkmem->elemsize));
2517#endif
2518 }
2519 }
2520 chkmem = chkmem->nextchkmem;
2521 }
2522 }
2523
2524 if( allocedmem != freemem )
2525 {
2526 errorMessage("%" LONGINT_FORMAT " bytes not freed in total.\n", allocedmem - freemem);
2527 }
2528
2529 return allocedmem - freemem;
2530}
2531
2532
2533
2534
2535
2536
2537/***********************************************************
2538 * Buffer Memory Management
2539 *
2540 * Efficient memory management for temporary objects
2541 ***********************************************************/
2542
2543/** memory buffer storage for temporary objects */
2545{
2546 void** data; /**< allocated memory chunks for arbitrary data */
2547 size_t* size; /**< sizes of buffers in bytes */
2548 unsigned int* used; /**< 1 iff corresponding buffer is in use */
2549 size_t totalmem; /**< total memory consumption of buffer */
2550 unsigned int clean; /**< 1 iff the memory blocks in the buffer should be initialized to zero? */
2551 size_t ndata; /**< number of memory chunks */
2552 size_t firstfree; /**< first unused memory chunk */
2553 double arraygrowfac; /**< memory growing factor for dynamically allocated arrays */
2554 unsigned int arraygrowinit; /**< initial size of dynamically allocated arrays */
2555};
2556
2557
2558/** creates memory buffer storage */
2560 double arraygrowfac, /**< memory growing factor for dynamically allocated arrays */
2561 int arraygrowinit, /**< initial size of dynamically allocated arrays */
2562 unsigned int clean, /**< should the memory blocks in the buffer be initialized to zero? */
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 BMS_BUFMEM* buffer;
2568
2569 assert( arraygrowinit > 0 );
2570 assert( arraygrowfac > 0.0 );
2571
2572 BMSallocMemory(&buffer);
2573 if ( buffer != NULL )
2574 {
2575 buffer->data = NULL;
2576 buffer->size = NULL;
2577 buffer->used = NULL;
2578 buffer->totalmem = 0UL;
2579 buffer->clean = clean;
2580 buffer->ndata = 0;
2581 buffer->firstfree = 0;
2582 buffer->arraygrowinit = (unsigned) arraygrowinit;
2583 buffer->arraygrowfac = arraygrowfac;
2584 }
2585 else
2586 {
2587 printErrorHeader(filename, line);
2588 printError("Insufficient memory for buffer memory header.\n");
2589 }
2590
2591 return buffer;
2592}
2593
2594/** destroys buffer memory */
2596 BMS_BUFMEM** buffer, /**< pointer to memory buffer storage */
2597 const char* filename, /**< source file of the function call */
2598 int line /**< line number in source file of the function call */
2599 )
2600{
2601 size_t i;
2602
2603 if ( *buffer != NULL )
2604 {
2605 i = (*buffer)->ndata;
2606 if ( i > 0 ) {
2607 for (--i ; ; i--)
2608 {
2609 assert( ! (*buffer)->used[i] );
2610 BMSfreeMemoryArrayNull(&(*buffer)->data[i]);
2611 if ( i == 0 )
2612 break;
2613 }
2614 }
2615 BMSfreeMemoryArrayNull(&(*buffer)->data);
2616 BMSfreeMemoryArrayNull(&(*buffer)->size);
2617 BMSfreeMemoryArrayNull(&(*buffer)->used);
2618 BMSfreeMemory(buffer);
2619 }
2620 else
2621 {
2622 printErrorHeader(filename, line);
2623 printError("Tried to free null buffer memory.\n");
2624 }
2625}
2626
2627/** set arraygrowfac */
2629 BMS_BUFMEM* buffer, /**< pointer to memory buffer storage */
2630 double arraygrowfac /**< memory growing factor for dynamically allocated arrays */
2631 )
2632{
2633 assert( buffer != NULL );
2634 assert( arraygrowfac > 0.0 );
2635
2636 buffer->arraygrowfac = arraygrowfac;
2637}
2638
2639/** set arraygrowinit */
2641 BMS_BUFMEM* buffer, /**< pointer to memory buffer storage */
2642 int arraygrowinit /**< initial size of dynamically allocated arrays */
2643 )
2644{
2645 assert( buffer != NULL );
2646 assert( arraygrowinit > 0 );
2647
2648 buffer->arraygrowinit = (unsigned) arraygrowinit;
2649}
2650
2651#ifndef SCIP_NOBUFFERMEM
2652/** calculate memory size for dynamically allocated arrays
2653 *
2654 * This function is a copy of the function in set.c in order to be able to use memory.? separately.
2655 */
2656static
2658 size_t initsize, /**< initial size of array */
2659 SCIP_Real growfac, /**< growing factor of array */
2660 size_t num /**< minimum number of entries to store */
2661 )
2662{
2663 size_t size;
2664
2665 assert( growfac >= 1.0 );
2666
2667 if ( growfac == 1.0 )
2668 size = MAX(initsize, num);
2669 else
2670 {
2671 size_t oldsize;
2672
2673 /* calculate the size with this loop, such that the resulting numbers are always the same */
2674 initsize = MAX(initsize, 4);
2675 size = initsize;
2676 oldsize = size - 1;
2677
2678 /* second condition checks against overflow */
2679 while ( size < num && size > oldsize )
2680 {
2681 oldsize = size;
2682 size = (size_t)(growfac * size + initsize);
2683 }
2684
2685 /* if an overflow happened, set the correct value */
2686 if ( size <= oldsize )
2687 size = num;
2688 }
2689
2690 assert( size >= initsize );
2691 assert( size >= num );
2692
2693 return size;
2694}
2695#endif
2696
2697/** work for allocating the next unused buffer */
2698INLINE static
2700 BMS_BUFMEM* buffer, /**< memory buffer storage */
2701 size_t size, /**< minimal required size of the buffer */
2702 const char* filename, /**< source file of the function call */
2703 int line /**< line number in source file of the function call */
2704 )
2705{
2706 void* ptr;
2707#ifndef SCIP_NOBUFFERMEM
2708 size_t bufnum;
2709#endif
2710
2711#ifndef SCIP_NOBUFFERMEM
2712 assert( buffer != NULL );
2713 assert( buffer->firstfree <= buffer->ndata );
2714
2715 /* allocate a minimum of 1 byte */
2716 if ( size == 0 )
2717 size = 1;
2718
2719 /* check, if we need additional buffers */
2720 if ( buffer->firstfree == buffer->ndata )
2721 {
2722 size_t newsize;
2723 size_t i;
2724
2725 /* create additional buffers */
2726 newsize = calcMemoryGrowSize((size_t)buffer->arraygrowinit, buffer->arraygrowfac, buffer->firstfree + 1);
2727 BMSreallocMemoryArray(&buffer->data, newsize);
2728 if ( buffer->data == NULL )
2729 {
2730 printErrorHeader(filename, line);
2731 printError("Insufficient memory for reallocating buffer data storage.\n");
2732 return NULL;
2733 }
2734 BMSreallocMemoryArray(&buffer->size, newsize);
2735 if ( buffer->size == NULL )
2736 {
2737 printErrorHeader(filename, line);
2738 printError("Insufficient memory for reallocating buffer size storage.\n");
2739 return NULL;
2740 }
2741 BMSreallocMemoryArray(&buffer->used, newsize);
2742 if ( buffer->used == NULL )
2743 {
2744 printErrorHeader(filename, line);
2745 printError("Insufficient memory for reallocating buffer used storage.\n");
2746 return NULL;
2747 }
2748
2749 /* init data */
2750 for (i = buffer->ndata; i < newsize; ++i)
2751 {
2752 buffer->data[i] = NULL;
2753 buffer->size[i] = 0;
2754 buffer->used[i] = FALSE;
2755 }
2756 buffer->ndata = newsize;
2757 }
2758 assert(buffer->firstfree < buffer->ndata);
2759
2760 /* check, if the current buffer is large enough */
2761 bufnum = buffer->firstfree;
2762 assert( ! buffer->used[bufnum] );
2763 if ( buffer->size[bufnum] < size )
2764 {
2765 size_t newsize;
2766
2767 /* enlarge buffer */
2768 newsize = calcMemoryGrowSize((size_t)buffer->arraygrowinit, buffer->arraygrowfac, size);
2769 BMSreallocMemorySize(&buffer->data[bufnum], newsize);
2770
2771 /* clear new memory */
2772 if( buffer->clean )
2773 {
2774 char* tmpptr = (char*)(buffer->data[bufnum]);
2775 size_t inc = buffer->size[bufnum] / sizeof(*tmpptr);
2776 tmpptr += inc;
2777
2778 BMSclearMemorySize(tmpptr, newsize - buffer->size[bufnum]);
2779 }
2780 assert( newsize > buffer->size[bufnum] );
2781 buffer->totalmem += newsize - buffer->size[bufnum];
2782 buffer->size[bufnum] = newsize;
2783
2784 if ( buffer->data[bufnum] == NULL )
2785 {
2786 printErrorHeader(filename, line);
2787 printError("Insufficient memory for reallocating buffer storage.\n");
2788 return NULL;
2789 }
2790 }
2791 assert( buffer->size[bufnum] >= size );
2792
2793#ifdef CHECKCLEANBUFFER
2794 /* check that the memory is cleared */
2795 if( buffer->clean )
2796 checkCleanmem(buffer->data[bufnum], buffer->size[bufnum]);
2797#endif
2798
2799 ptr = buffer->data[bufnum];
2800 buffer->used[bufnum] = TRUE;
2801 buffer->firstfree++;
2802
2803 debugMessage("Allocated buffer %llu/%llu at %p of size %llu (required size: %llu) for pointer %p.\n",
2804 (unsigned long long)bufnum, (unsigned long long)(buffer->ndata), buffer->data[bufnum],
2805 (unsigned long long)(buffer->size[bufnum]), (unsigned long long)size, ptr);
2806
2807#else
2808 if( buffer->clean )
2809 {
2810 /* we should allocate at least one byte, otherwise BMSallocMemorySize will fail */
2811 size = MAX(size,1);
2812
2813 BMSallocClearMemorySize(&ptr, size);
2814 }
2815 else
2816 {
2817 BMSallocMemorySize(&ptr, size);
2818 }
2819#endif
2820
2821 return ptr;
2822}
2823
2824/** allocates the next unused buffer */
2826 BMS_BUFMEM* buffer, /**< memory buffer storage */
2827 size_t size, /**< minimal required size of the buffer */
2828 const char* filename, /**< source file of the function call */
2829 int line /**< line number in source file of the function call */
2830 )
2831{
2832#ifndef NDEBUG
2833 if ( size > MAXMEMSIZE )
2834 {
2835 printErrorHeader(filename, line);
2836 printError("Tried to allocate buffer of size exceeding %lu.\n", MAXMEMSIZE);
2837 return NULL;
2838 }
2839#endif
2840
2841 return BMSallocBufferMemory_work(buffer, size, filename, line);
2842}
2843
2844/** allocates the next unused buffer array */
2846 BMS_BUFMEM* buffer, /**< memory buffer storage */
2847 size_t num, /**< size of array to be allocated */
2848 size_t typesize, /**< size of components */
2849 const char* filename, /**< source file of the function call */
2850 int line /**< line number in source file of the function call */
2851 )
2852{
2853#ifndef NDEBUG
2854 if ( num > (MAXMEMSIZE / typesize) )
2855 {
2856 printErrorHeader(filename, line);
2857 printError("Tried to allocate buffer of size exceeding %lu.\n", MAXMEMSIZE);
2858 return NULL;
2859 }
2860#endif
2861
2862 return BMSallocBufferMemory_work(buffer, num * typesize, filename, line);
2863}
2864
2865/** allocates the next unused buffer and clears it */
2867 BMS_BUFMEM* buffer, /**< memory buffer storage */
2868 size_t num, /**< size of array to be allocated */
2869 size_t typesize, /**< size of components */
2870 const char* filename, /**< source file of the function call */
2871 int line /**< line number in source file of the function call */
2872 )
2873{
2874 void* ptr;
2875
2876 ptr = BMSallocBufferMemoryArray_call(buffer, num, typesize, filename, line);
2877 if ( ptr != NULL )
2878 BMSclearMemorySize(ptr, num * typesize);
2879
2880 return ptr;
2881}
2882
2883/** work for reallocating the buffer to at least the given size */
2884INLINE static
2886 BMS_BUFMEM* buffer, /**< memory buffer storage */
2887 void* ptr, /**< pointer to the allocated memory buffer */
2888 size_t size, /**< minimal required size of the buffer */
2889 const char* filename, /**< source file of the function call */
2890 int line /**< line number in source file of the function call */
2891 )
2892{
2893 void* newptr;
2894#ifndef SCIP_NOBUFFERMEM
2895 size_t bufnum;
2896#endif
2897
2898#ifndef SCIP_NOBUFFERMEM
2899 assert( buffer != NULL );
2900 assert( buffer->firstfree <= buffer->ndata );
2901 assert(!buffer->clean); /* reallocating clean buffer elements is not supported */
2902
2903 /* if the pointer doesn't exist yet, allocate it */
2904 if ( ptr == NULL )
2905 return BMSallocBufferMemory_call(buffer, size, filename, line);
2906
2907 assert( buffer->firstfree >= 1 );
2908
2909 /* Search the pointer in the buffer list:
2910 * Usually, buffers are allocated and freed like a stack, such that the currently used pointer is
2911 * most likely at the end of the buffer list.
2912 */
2913 bufnum = buffer->firstfree - 1;
2914 while ( bufnum > 0 && buffer->data[bufnum] != ptr )
2915 --bufnum;
2916
2917 newptr = ptr;
2918 assert( buffer->data[bufnum] == newptr );
2919 assert( buffer->used[bufnum] );
2920 assert( buffer->size[bufnum] >= 1 );
2921
2922 /* check if the buffer has to be enlarged */
2923 if ( size > buffer->size[bufnum] )
2924 {
2925 size_t newsize;
2926
2927 /* enlarge buffer */
2928 newsize = calcMemoryGrowSize((size_t)buffer->arraygrowinit, buffer->arraygrowfac, size);
2929 BMSreallocMemorySize(&buffer->data[bufnum], newsize);
2930 assert( newsize > buffer->size[bufnum] );
2931 buffer->totalmem += newsize - buffer->size[bufnum];
2932 buffer->size[bufnum] = newsize;
2933 if ( buffer->data[bufnum] == NULL )
2934 {
2935 printErrorHeader(filename, line);
2936 printError("Insufficient memory for reallocating buffer storage.\n");
2937 return NULL;
2938 }
2939 newptr = buffer->data[bufnum];
2940 }
2941 assert( buffer->size[bufnum] >= size );
2942 assert( newptr == buffer->data[bufnum] );
2943
2944 debugMessage("Reallocated buffer %llu/%llu at %p to size %llu (required size: %llu) for pointer %p.\n",
2945 (unsigned long long)bufnum, (unsigned long long)(buffer->ndata), buffer->data[bufnum],
2946 (unsigned long long)(buffer->size[bufnum]), (unsigned long long)size, newptr);
2947
2948#else
2949 newptr = ptr;
2950 BMSreallocMemorySize(&newptr, size);
2951#endif
2952
2953 return newptr;
2954}
2955
2956/** reallocates the buffer to at least the given size */
2958 BMS_BUFMEM* buffer, /**< memory buffer storage */
2959 void* ptr, /**< pointer to the allocated memory buffer */
2960 size_t size, /**< minimal required size of the buffer */
2961 const char* filename, /**< source file of the function call */
2962 int line /**< line number in source file of the function call */
2963 )
2964{
2965#ifndef NDEBUG
2966 if ( size > MAXMEMSIZE )
2967 {
2968 printErrorHeader(filename, line);
2969 printError("Tried to allocate buffer of size exceeding %lu.\n", MAXMEMSIZE);
2970 return NULL;
2971 }
2972#endif
2973
2974 return BMSreallocBufferMemory_work(buffer, ptr, size, filename, line);
2975}
2976
2977/** reallocates an array in the buffer to at least the given size */
2979 BMS_BUFMEM* buffer, /**< memory buffer storage */
2980 void* ptr, /**< pointer to the allocated memory buffer */
2981 size_t num, /**< size of array to be allocated */
2982 size_t typesize, /**< size of components */
2983 const char* filename, /**< source file of the function call */
2984 int line /**< line number in source file of the function call */
2985 )
2986{
2987#ifndef NDEBUG
2988 if ( num > (MAXMEMSIZE / typesize) )
2989 {
2990 printErrorHeader(filename, line);
2991 printError("Tried to allocate array of size exceeding %lu.\n", MAXMEMSIZE);
2992 return NULL;
2993 }
2994#endif
2995
2996 return BMSreallocBufferMemory_work(buffer, ptr, num * typesize, filename, line);
2997}
2998
2999/** allocates the next unused buffer and copies the given memory into the buffer */
3001 BMS_BUFMEM* buffer, /**< memory buffer storage */
3002 const void* source, /**< memory block to copy into the buffer */
3003 size_t size, /**< minimal required size of the buffer */
3004 const char* filename, /**< source file of the function call */
3005 int line /**< line number in source file of the function call */
3006 )
3007{
3008 void* ptr;
3009
3010 assert( source != NULL );
3011
3012 /* allocate a buffer of the given size */
3013 ptr = BMSallocBufferMemory_call(buffer, size, filename, line);
3014
3015 /* copy the source memory into the buffer */
3016 if ( ptr != NULL )
3017 BMScopyMemorySize(ptr, source, size);
3018
3019 return ptr;
3020}
3021
3022/** allocates an array in the next unused buffer and copies the given memory into the buffer */
3024 BMS_BUFMEM* buffer, /**< memory buffer storage */
3025 const void* source, /**< memory block to copy into the buffer */
3026 size_t num, /**< size of array to be allocated */
3027 size_t typesize, /**< size of components */
3028 const char* filename, /**< source file of the function call */
3029 int line /**< line number in source file of the function call */
3030 )
3031{
3032 void* ptr;
3033
3034 assert( source != NULL );
3035
3036 /* allocate a buffer of the given size */
3037 ptr = BMSallocBufferMemoryArray_call(buffer, num, typesize, filename, line);
3038
3039 /* copy the source memory into the buffer */
3040 if ( ptr != NULL )
3041 BMScopyMemorySize(ptr, source, num * typesize);
3042
3043 return ptr;
3044}
3045
3046/** work for freeing a buffer */
3047INLINE static
3049 BMS_BUFMEM* buffer, /**< memory buffer storage */
3050 void** ptr, /**< pointer to pointer to the allocated memory buffer */
3051 const char* filename, /**< source file of the function call */
3052 int line /**< line number in source file of the function call */
3053 )
3054{ /*lint --e{715}*/
3055 size_t bufnum;
3056
3057 assert( buffer != NULL );
3058 assert( buffer->firstfree <= buffer->ndata );
3059 assert( buffer->firstfree >= 1 );
3060 assert( ptr != NULL );
3061 assert( *ptr != NULL );
3062
3063 /* Search the pointer in the buffer list:
3064 * Usually, buffers are allocated and freed like a stack, such that the freed pointer is
3065 * most likely at the end of the buffer list.
3066 */
3067 bufnum = buffer->firstfree-1;
3068 while ( bufnum > 0 && buffer->data[bufnum] != *ptr )
3069 --bufnum;
3070
3071#ifdef CHECKBUFFERORDER
3072 if ( bufnum < buffer->firstfree - 1 )
3073 {
3074 warningMessage("[%s:%d]: freeing buffer in wrong order.\n", filename, line);
3075 }
3076#endif
3077
3078#ifndef NDEBUG
3079 if ( bufnum == 0 && buffer->data[bufnum] != *ptr )
3080 {
3081 printErrorHeader(filename, line);
3082 printError("Tried to free unknown buffer pointer.\n");
3083 return;
3084 }
3085 if ( ! buffer->used[bufnum] )
3086 {
3087 printErrorHeader(filename, line);
3088 printError("Tried to free buffer pointer already freed.\n");
3089 return;
3090 }
3091#endif
3092
3093#ifdef CHECKCLEANBUFFER
3094 /* check that the memory is cleared */
3095 if( buffer->clean )
3096 checkCleanmem(buffer->data[bufnum], buffer->size[bufnum]);
3097#endif
3098
3099 assert( buffer->data[bufnum] == *ptr );
3100 buffer->used[bufnum] = FALSE;
3101
3102 while ( buffer->firstfree > 0 && !buffer->used[buffer->firstfree-1] )
3103 --buffer->firstfree;
3104
3105 debugMessage("Freed buffer %llu/%llu at %p of size %llu for pointer %p, first free is %llu.\n",
3106 (unsigned long long)bufnum, (unsigned long long)(buffer->ndata), buffer->data[bufnum],
3107 (unsigned long long)(buffer->size[bufnum]), *ptr, (unsigned long long)(buffer->firstfree));
3108
3109 *ptr = NULL;
3110}
3111
3112/** frees a buffer and sets pointer to NULL */
3114 BMS_BUFMEM* buffer, /**< memory buffer storage */
3115 void** ptr, /**< pointer to pointer to the allocated memory buffer */
3116 const char* filename, /**< source file of the function call */
3117 int line /**< line number in source file of the function call */
3118 )
3119{ /*lint --e{715}*/
3120 assert( ptr != NULL );
3121
3122#ifndef SCIP_NOBUFFERMEM
3123 if ( *ptr != NULL )
3124 BMSfreeBufferMemory_work(buffer, ptr, filename, line);
3125 else
3126 {
3127 printErrorHeader(filename, line);
3128 printError("Tried to free null buffer pointer.\n");
3129 }
3130#else
3131 BMSfreeMemory(ptr);
3132#endif
3133}
3134
3135/** frees a buffer if pointer is not NULL and sets pointer to NULL */
3137 BMS_BUFMEM* buffer, /**< memory buffer storage */
3138 void** ptr, /**< pointer to pointer to the allocated memory buffer */
3139 const char* filename, /**< source file of the function call */
3140 int line /**< line number in source file of the function call */
3141 )
3142{ /*lint --e{715}*/
3143 assert( ptr != NULL );
3144
3145 if ( *ptr != NULL )
3146 {
3147#ifndef SCIP_NOBUFFERMEM
3148 BMSfreeBufferMemory_work(buffer, ptr, filename, line);
3149#else
3150 BMSfreeMemory(ptr);
3151#endif
3152 }
3153}
3154
3155/** gets number of used buffers */
3157 BMS_BUFMEM* buffer /**< memory buffer storage */
3158 )
3159{
3160 assert( buffer != NULL );
3161
3162 return buffer->firstfree;
3163}
3164
3165/** returns the number of allocated bytes in the buffer memory */
3167 const BMS_BUFMEM* buffer /**< buffer memory */
3168 )
3169{
3170#ifdef CHECKMEM
3171 size_t totalmem = 0UL;
3172 size_t i;
3173
3174 assert( buffer != NULL );
3175 for (i = 0; i < buffer->ndata; ++i)
3176 totalmem += buffer->size[i];
3177 assert( totalmem == buffer->totalmem );
3178#endif
3179
3180 return (long long) buffer->totalmem;
3181}
3182
3183/** outputs statistics about currently allocated buffers to the screen */
3185 BMS_BUFMEM* buffer /**< memory buffer storage */
3186 )
3187{
3188 size_t totalmem;
3189 size_t i;
3190
3191 assert( buffer != NULL );
3192
3193 totalmem = 0UL;
3194 for (i = 0; i < buffer->ndata; ++i)
3195 {
3196 printf("[%c] %8llu bytes at %p\n", buffer->used[i] ? '*' : ' ', (unsigned long long)(buffer->size[i]), buffer->data[i]);
3197 totalmem += buffer->size[i];
3198 }
3199 printf(" %8llu bytes total in %llu buffers\n", (unsigned long long)totalmem, (unsigned long long)(buffer->ndata));
3200}
common defines and data types used in all packages of SCIP
#define NULL
Definition: def.h:248
#define INLINE
Definition: def.h:120
#define SCIP_UNUSED(x)
Definition: def.h:409
#define SCIP_Bool
Definition: def.h:91
#define MIN(x, y)
Definition: def.h:224
#define SCIP_Real
Definition: def.h:156
#define TRUE
Definition: def.h:93
#define FALSE
Definition: def.h:94
#define MAX(x, y)
Definition: def.h:220
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:1610
#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:3000
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:2205
#define CHUNK_LT(ptr, chunk)
Definition: memory.c:748
static void destroyChunk(CHUNK **chunk, long long *memsize)
Definition: memory.c:1144
void BMSgarbagecollectChunkMemory_call(BMS_CHKMEM *chkmem)
Definition: memory.c:1663
size_t BMSgetBlockPointerSize_call(const BMS_BLKMEM *blkmem, const void *ptr)
Definition: memory.c:2320
#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:1330
static INLINE void BMSfreeBlockMemory_work(BMS_BLKMEM *blkmem, void **ptr, size_t size, const char *filename, int line)
Definition: memory.c:2134
int BMSisAligned(size_t size)
Definition: memory.c:777
void BMSclearBlockMemory_call(BMS_BLKMEM *blkmem, const char *filename, int line)
Definition: memory.c:1804
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:2464
long long BMSgetBufferMemoryUsed(const BMS_BUFMEM *buffer)
Definition: memory.c:3166
#define ALIGNMENT
Definition: memory.c:697
void BMSfreeBufferMemory_call(BMS_BUFMEM *buffer, void **ptr, const char *filename, int line)
Definition: memory.c:3113
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:2013
void BMSfreeMemoryNull_call(void **ptr, const char *filename, int line)
Definition: memory.c:642
void BMSsetBufferMemoryArraygrowinit(BMS_BUFMEM *buffer, int arraygrowinit)
Definition: memory.c:2640
static void unlinkChunk(CHUNK *chunk)
Definition: memory.c:996
static uint32_t getHashNumber(size_t size)
Definition: memory.c:1760
void BMSdestroyBufferMemory_call(BMS_BUFMEM **buffer, const char *filename, int line)
Definition: memory.c:2595
#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:1521
void * BMSreallocBufferMemory_call(BMS_BUFMEM *buffer, void *ptr, size_t size, const char *filename, int line)
Definition: memory.c:2957
static INLINE void BMSfreeBufferMemory_work(BMS_BUFMEM *buffer, void **ptr, const char *filename, int line)
Definition: memory.c:3048
static size_t calcMemoryGrowSize(size_t initsize, SCIP_Real growfac, size_t num)
Definition: memory.c:2657
#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:2290
static BMS_CHKMEM * findChkmem(const BMS_BLKMEM *blkmem, const void *ptr)
Definition: memory.c:1737
static BMS_CHKMEM * createChkmem(int size, int initchunksize, int garbagefactor, long long *memsize)
Definition: memory.c:1261
void * BMSallocBufferMemoryArray_call(BMS_BUFMEM *buffer, size_t num, size_t typesize, const char *filename, int line)
Definition: memory.c:2845
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:1163
static void freeChkmemElement(BMS_CHKMEM *chkmem, void *ptr, long long *memsize, const char *filename, int line)
Definition: memory.c:1460
static void freeChunkElement(CHUNK *chunk, void *ptr)
Definition: memory.c:1232
void * BMSallocBlockMemoryArray_call(BMS_BLKMEM *blkmem, size_t num, size_t typesize, const char *filename, int line)
Definition: memory.c:1974
#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:1861
void * BMSreallocBufferMemoryArray_call(BMS_BUFMEM *buffer, void *ptr, size_t num, size_t typesize, const char *filename, int line)
Definition: memory.c:2978
#define CHUNKLENGTH_MIN
Definition: memory.c:693
static void garbagecollectChkmem(BMS_CHKMEM *chkmem, long long *memsize)
Definition: memory.c:1392
void BMSdisplayBlockMemory_call(const BMS_BLKMEM *blkmem)
Definition: memory.c:2340
long long BMSgetBlockMemoryAllocated_call(const BMS_BLKMEM *blkmem)
Definition: memory.c:2260
void BMSclearMemory_call(void *ptr, size_t size)
Definition: memory.c:536
long long BMSgetBlockMemoryUsed_call(const BMS_BLKMEM *blkmem)
Definition: memory.c:2270
void BMSfreeBufferMemoryNull_call(BMS_BUFMEM *buffer, void **ptr, const char *filename, int line)
Definition: memory.c:3136
void * BMSallocChunkMemory_call(BMS_CHKMEM *chkmem, size_t size, const char *filename, int line)
Definition: memory.c:1561
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:1770
void * BMSallocClearBlockMemoryArray_call(BMS_BLKMEM *blkmem, size_t num, size_t typesize, const char *filename, int line)
Definition: memory.c:1995
void * BMSduplicateBlockMemoryArray_call(BMS_BLKMEM *blkmem, const void *source, size_t num, size_t typesize, const char *filename, int line)
Definition: memory.c:2112
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:2559
static INLINE void * BMSreallocBufferMemory_work(BMS_BUFMEM *buffer, void *ptr, size_t size, const char *filename, int line)
Definition: memory.c:2885
static void unlinkEagerChunk(CHUNK *chunk)
Definition: memory.c:1044
void BMSdestroyBlockMemory_call(BMS_BLKMEM **blkmem, const char *filename, int line)
Definition: memory.c:1838
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:1023
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:2280
void BMSprintBufferMemory(BMS_BUFMEM *buffer)
Definition: memory.c:3184
void * BMSduplicateChunkMemory_call(BMS_CHKMEM *chkmem, const void *source, size_t size, const char *filename, int line)
Definition: memory.c:1588
#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:968
static void * allocChkmemElement(BMS_CHKMEM *chkmem, long long *memsize)
Definition: memory.c:1352
static void clearChkmem(BMS_CHKMEM *chkmem, long long *memsize)
Definition: memory.c:1305
#define checkBlkmem(blkmem)
Definition: memory.c:1727
void * BMSallocClearBlockMemory_call(BMS_BLKMEM *blkmem, size_t size, const char *filename, int line)
Definition: memory.c:1957
void * BMSallocBufferMemory_call(BMS_BUFMEM *buffer, size_t size, const char *filename, int line)
Definition: memory.c:2825
BMS_CHKMEM * BMScreateChunkMemory_call(size_t size, int initchunksize, int garbagefactor, const char *filename, int line)
Definition: memory.c:1497
static INLINE void * BMSallocBufferMemory_work(BMS_BUFMEM *buffer, size_t size, const char *filename, int line)
Definition: memory.c:2699
void * BMSallocBlockMemory_call(BMS_BLKMEM *blkmem, size_t size, const char *filename, int line)
Definition: memory.c:1937
void BMScopyMemory_call(void *ptr, const void *source, size_t size)
Definition: memory.c:549
static void * allocChunkElement(CHUNK *chunk)
Definition: memory.c:1195
#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:1069
long long BMSgetChunkMemoryUsed_call(const BMS_CHKMEM *chkmem)
Definition: memory.c:1673
void BMSfreeChunkMemoryNull_call(BMS_CHKMEM *chkmem, void **ptr, size_t size, const char *filename, int line)
Definition: memory.c:1639
void BMSsetBufferMemoryArraygrowfac(BMS_BUFMEM *buffer, double arraygrowfac)
Definition: memory.c:2628
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:3023
void BMSdestroyChunkMemory_call(BMS_CHKMEM **chkmem, const char *filename, int line)
Definition: memory.c:1540
void BMSgarbagecollectBlockMemory_call(BMS_BLKMEM *blkmem)
Definition: memory.c:2226
void BMSfreeBlockMemory_call(BMS_BLKMEM *blkmem, void **ptr, size_t size, const char *filename, int line)
Definition: memory.c:2183
void * BMSallocClearBufferMemoryArray_call(BMS_BUFMEM *buffer, size_t num, size_t typesize, const char *filename, int line)
Definition: memory.c:2866
#define GARBAGE_SIZE
Definition: memory.c:696
long long BMSgetBlockMemoryUnusedMax_call(const BMS_BLKMEM *blkmem)
Definition: memory.c:2300
void * BMSduplicateBlockMemory_call(BMS_BLKMEM *blkmem, const void *source, size_t size, const char *filename, int line)
Definition: memory.c:2092
#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:2053
size_t BMSgetNUsedBufferMemory(BMS_BUFMEM *buffer)
Definition: memory.c:3156
long long BMSgetBlockMemoryAllocatedMax_call(const BMS_BLKMEM *blkmem)
Definition: memory.c:2310
#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:2547
unsigned int * used
Definition: memory.c:2548
void ** data
Definition: memory.c:2546
size_t firstfree
Definition: memory.c:2552
double arraygrowfac
Definition: memory.c:2553
unsigned int arraygrowinit
Definition: memory.c:2554
unsigned int clean
Definition: memory.c:2550
size_t totalmem
Definition: memory.c:2549
size_t ndata
Definition: memory.c:2551